Vendor import of clang trunk r300890:
https://llvm.org/svn/llvm-project/cfe/trunk@300890
This commit is contained in:
parent
7442d6faa2
commit
583e75cce4
@ -20,13 +20,5 @@
|
||||
Bindings for the Clang indexing library.
|
||||
"""
|
||||
|
||||
|
||||
# Python 3 uses unicode for strings. The bindings, in particular the interaction
|
||||
# with ctypes, need modifying to handle conversions between unicode and
|
||||
# c-strings.
|
||||
import sys
|
||||
if sys.version_info[0] != 2:
|
||||
raise Exception("Only Python 2 is supported.")
|
||||
|
||||
__all__ = ['cindex']
|
||||
|
||||
|
@ -67,6 +67,60 @@
|
||||
|
||||
import clang.enumerations
|
||||
|
||||
import sys
|
||||
if sys.version_info[0] == 3:
|
||||
# Python 3 strings are unicode, translate them to/from utf8 for C-interop.
|
||||
class c_interop_string(c_char_p):
|
||||
|
||||
def __init__(self, p=None):
|
||||
if p is None:
|
||||
p = ""
|
||||
if isinstance(p, str):
|
||||
p = p.encode("utf8")
|
||||
super(c_char_p, self).__init__(p)
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
if super(c_char_p, self).value is None:
|
||||
return None
|
||||
return super(c_char_p, self).value.decode("utf8")
|
||||
|
||||
@classmethod
|
||||
def from_param(cls, param):
|
||||
if isinstance(param, str):
|
||||
return cls(param)
|
||||
if isinstance(param, bytes):
|
||||
return cls(param)
|
||||
raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__))
|
||||
|
||||
@staticmethod
|
||||
def to_python_string(x, *args):
|
||||
return x.value
|
||||
|
||||
def b(x):
|
||||
if isinstance(x, bytes):
|
||||
return x
|
||||
return x.encode('utf8')
|
||||
|
||||
xrange = range
|
||||
|
||||
elif sys.version_info[0] == 2:
|
||||
# Python 2 strings are utf8 byte strings, no translation is needed for
|
||||
# C-interop.
|
||||
c_interop_string = c_char_p
|
||||
|
||||
def _to_python_string(x, *args):
|
||||
return x
|
||||
|
||||
c_interop_string.to_python_string = staticmethod(_to_python_string)
|
||||
|
||||
def b(x):
|
||||
return x
|
||||
|
||||
|
||||
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
|
||||
# object. This is a problem, because it means that from_parameter will see an
|
||||
# integer and pass the wrong value on platforms where int != void*. Work around
|
||||
@ -157,6 +211,7 @@ def from_result(res, fn, args):
|
||||
assert isinstance(res, _CXString)
|
||||
return conf.lib.clang_getCString(res)
|
||||
|
||||
|
||||
class SourceLocation(Structure):
|
||||
"""
|
||||
A SourceLocation represents a particular location within a source file.
|
||||
@ -596,7 +651,7 @@ class CursorKind(BaseEnumeration):
|
||||
@staticmethod
|
||||
def get_all_kinds():
|
||||
"""Return all CursorKind enumeration instances."""
|
||||
return filter(None, CursorKind._kinds)
|
||||
return [x for x in CursorKind._kinds if not x is None]
|
||||
|
||||
def is_declaration(self):
|
||||
"""Test if this is a declaration kind."""
|
||||
@ -2128,7 +2183,7 @@ def get_offset(self, fieldname):
|
||||
"""
|
||||
Retrieve the offset of a field in the record.
|
||||
"""
|
||||
return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
|
||||
return conf.lib.clang_Type_getOffsetOf(self, fieldname)
|
||||
|
||||
def get_ref_qualifier(self):
|
||||
"""
|
||||
@ -2239,7 +2294,7 @@ def __repr__(self):
|
||||
def spelling(self):
|
||||
if self.__kindNumber in SpellingCache:
|
||||
return SpellingCache[self.__kindNumber]
|
||||
return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling
|
||||
return conf.lib.clang_getCompletionChunkText(self.cs, self.key)
|
||||
|
||||
# We do not use @CachedProperty here, as the manual implementation is
|
||||
# apparently still significantly faster. Please profile carefully if you
|
||||
@ -2345,7 +2400,7 @@ def __repr__(self):
|
||||
return " | ".join([str(a) for a in self]) \
|
||||
+ " || Priority: " + str(self.priority) \
|
||||
+ " || Availability: " + str(self.availability) \
|
||||
+ " || Brief comment: " + str(self.briefComment.spelling)
|
||||
+ " || Brief comment: " + str(self.briefComment)
|
||||
|
||||
availabilityKinds = {
|
||||
0: CompletionChunk.Kind("Available"),
|
||||
@ -2542,7 +2597,7 @@ def from_source(cls, filename, args=None, unsaved_files=None, options=0,
|
||||
|
||||
args_array = None
|
||||
if len(args) > 0:
|
||||
args_array = (c_char_p * len(args))(* args)
|
||||
args_array = (c_char_p * len(args))(*[b(x) for x in args])
|
||||
|
||||
unsaved_array = None
|
||||
if len(unsaved_files) > 0:
|
||||
@ -2551,8 +2606,8 @@ def from_source(cls, filename, args=None, unsaved_files=None, options=0,
|
||||
if hasattr(contents, "read"):
|
||||
contents = contents.read()
|
||||
|
||||
unsaved_array[i].name = name
|
||||
unsaved_array[i].contents = contents
|
||||
unsaved_array[i].name = b(name)
|
||||
unsaved_array[i].contents = b(contents)
|
||||
unsaved_array[i].length = len(contents)
|
||||
|
||||
ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array,
|
||||
@ -2797,8 +2852,8 @@ def codeComplete(self, path, line, column, unsaved_files=None,
|
||||
print(value)
|
||||
if not isinstance(value, str):
|
||||
raise TypeError('Unexpected unsaved file contents.')
|
||||
unsaved_files_array[i].name = name
|
||||
unsaved_files_array[i].contents = value
|
||||
unsaved_files_array[i].name = b(name)
|
||||
unsaved_files_array[i].contents = b(value)
|
||||
unsaved_files_array[i].length = len(value)
|
||||
ptr = conf.lib.clang_codeCompleteAt(self, path, line, column,
|
||||
unsaved_files_array, len(unsaved_files), options)
|
||||
@ -2833,7 +2888,7 @@ def from_name(translation_unit, file_name):
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the complete file and path name of the file."""
|
||||
return conf.lib.clang_getCString(conf.lib.clang_getFileName(self))
|
||||
return conf.lib.clang_getFileName(self)
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
@ -3064,7 +3119,7 @@ def cursor(self):
|
||||
[c_object_p]),
|
||||
|
||||
("clang_CompilationDatabase_fromDirectory",
|
||||
[c_char_p, POINTER(c_uint)],
|
||||
[c_interop_string, POINTER(c_uint)],
|
||||
c_object_p,
|
||||
CompilationDatabase.from_result),
|
||||
|
||||
@ -3074,7 +3129,7 @@ def cursor(self):
|
||||
CompileCommands.from_result),
|
||||
|
||||
("clang_CompilationDatabase_getCompileCommands",
|
||||
[c_object_p, c_char_p],
|
||||
[c_object_p, c_interop_string],
|
||||
c_object_p,
|
||||
CompileCommands.from_result),
|
||||
|
||||
@ -3109,7 +3164,7 @@ def cursor(self):
|
||||
c_uint),
|
||||
|
||||
("clang_codeCompleteAt",
|
||||
[TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int],
|
||||
[TranslationUnit, c_interop_string, c_int, c_int, c_void_p, c_int, c_int],
|
||||
POINTER(CCRStructure)),
|
||||
|
||||
("clang_codeCompleteGetDiagnostic",
|
||||
@ -3125,7 +3180,7 @@ def cursor(self):
|
||||
c_object_p),
|
||||
|
||||
("clang_createTranslationUnit",
|
||||
[Index, c_char_p],
|
||||
[Index, c_interop_string],
|
||||
c_object_p),
|
||||
|
||||
("clang_CXXConstructor_isConvertingConstructor",
|
||||
@ -3215,7 +3270,8 @@ def cursor(self):
|
||||
|
||||
("clang_formatDiagnostic",
|
||||
[Diagnostic, c_uint],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getArgType",
|
||||
[Type, c_uint],
|
||||
@ -3255,7 +3311,8 @@ def cursor(self):
|
||||
|
||||
("clang_getCompletionBriefComment",
|
||||
[c_void_p],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getCompletionChunkCompletionString",
|
||||
[c_void_p, c_int],
|
||||
@ -3267,7 +3324,8 @@ def cursor(self):
|
||||
|
||||
("clang_getCompletionChunkText",
|
||||
[c_void_p, c_int],
|
||||
_CXString),
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getCompletionPriority",
|
||||
[c_void_p],
|
||||
@ -3275,7 +3333,8 @@ def cursor(self):
|
||||
|
||||
("clang_getCString",
|
||||
[_CXString],
|
||||
c_char_p),
|
||||
c_interop_string,
|
||||
c_interop_string.to_python_string),
|
||||
|
||||
("clang_getCursor",
|
||||
[TranslationUnit, SourceLocation],
|
||||
@ -3422,12 +3481,13 @@ def cursor(self):
|
||||
Type.from_result),
|
||||
|
||||
("clang_getFile",
|
||||
[TranslationUnit, c_char_p],
|
||||
[TranslationUnit, c_interop_string],
|
||||
c_object_p),
|
||||
|
||||
("clang_getFileName",
|
||||
[File],
|
||||
_CXString), # TODO go through _CXString.from_result?
|
||||
_CXString,
|
||||
_CXString.from_result),
|
||||
|
||||
("clang_getFileTime",
|
||||
[File],
|
||||
@ -3551,7 +3611,8 @@ def cursor(self):
|
||||
|
||||
("clang_getTUResourceUsageName",
|
||||
[c_uint],
|
||||
c_char_p),
|
||||
c_interop_string,
|
||||
c_interop_string.to_python_string),
|
||||
|
||||
("clang_getTypeDeclaration",
|
||||
[Type],
|
||||
@ -3646,7 +3707,7 @@ def cursor(self):
|
||||
bool),
|
||||
|
||||
("clang_parseTranslationUnit",
|
||||
[Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int],
|
||||
[Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int],
|
||||
c_object_p),
|
||||
|
||||
("clang_reparseTranslationUnit",
|
||||
@ -3654,7 +3715,7 @@ def cursor(self):
|
||||
c_int),
|
||||
|
||||
("clang_saveTranslationUnit",
|
||||
[TranslationUnit, c_char_p, c_uint],
|
||||
[TranslationUnit, c_interop_string, c_uint],
|
||||
c_int),
|
||||
|
||||
("clang_tokenize",
|
||||
@ -3726,7 +3787,7 @@ def cursor(self):
|
||||
Type.from_result),
|
||||
|
||||
("clang_Type_getOffsetOf",
|
||||
[Type, c_char_p],
|
||||
[Type, c_interop_string],
|
||||
c_longlong),
|
||||
|
||||
("clang_Type_getSizeOf",
|
||||
@ -3785,7 +3846,8 @@ def register_functions(lib, ignore_errors):
|
||||
def register(item):
|
||||
return register_function(lib, item, ignore_errors)
|
||||
|
||||
map(register, functionList)
|
||||
for f in functionList:
|
||||
register(f)
|
||||
|
||||
class Config:
|
||||
library_path = None
|
||||
|
@ -59,9 +59,12 @@ def test_unsaved_files():
|
||||
assert spellings[-1] == 'y'
|
||||
|
||||
def test_unsaved_files_2():
|
||||
import StringIO
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except:
|
||||
from io import StringIO
|
||||
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
|
||||
('fake.c', StringIO.StringIO('int x;'))])
|
||||
('fake.c', StringIO('int x;'))])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-1] == 'x'
|
||||
|
||||
|
@ -2346,3 +2346,178 @@ statements in C)
|
||||
The pragma can also be used with ``off`` which turns FP contraction off for a
|
||||
section of the code. This can be useful when fast contraction is otherwise
|
||||
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
|
||||
|
||||
Specifying an attribute for multiple declarations (#pragma clang attribute)
|
||||
===========================================================================
|
||||
|
||||
The ``#pragma clang attribute`` directive can be used to apply an attribute to
|
||||
multiple declarations. The ``#pragma clang attribute push`` variation of the
|
||||
directive pushes a new attribute to the attribute stack. The declarations that
|
||||
follow the pragma receive the attributes that are on the attribute stack, until
|
||||
the stack is cleared using a ``#pragma clang attribute pop`` directive. Multiple
|
||||
push directives can be nested inside each other.
|
||||
|
||||
The attributes that are used in the ``#pragma clang attribute`` directives
|
||||
can be written using the GNU-style syntax:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push(__attribute__((annotate("custom"))), apply_to = function)
|
||||
|
||||
void function(); // The function now has the annotate("custom") attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
The attributes can also be written using the C++11 style syntax:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push([[noreturn]], apply_to = function)
|
||||
|
||||
void function(); // The function now has the [[noreturn]] attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
The ``__declspec`` style syntax is also supported:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push(__declspec(dllexport), apply_to = function)
|
||||
|
||||
void function(); // The function now has the __declspec(dllexport) attribute
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
A single push directive accepts only one attribute regardless of the syntax
|
||||
used.
|
||||
|
||||
Subject Match Rules
|
||||
-------------------
|
||||
|
||||
The set of declarations that receive a single attribute from the attribute stack
|
||||
depends on the subject match rules that were specified in the pragma. Subject
|
||||
match rules are specified after the attribute. The compiler expects an
|
||||
identifier that corresponds to the subject set specifier. The ``apply_to``
|
||||
specifier is currently the only supported subject set specifier. It allows you
|
||||
to specify match rules that form a subset of the attribute's allowed subject
|
||||
set, i.e. the compiler doesn't require all of the attribute's subjects. For
|
||||
example, an attribute like ``[[nodiscard]]`` whose subject set includes
|
||||
``enum``, ``record`` and ``hasType(functionType)``, requires the presence of at
|
||||
least one of these rules after ``apply_to``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = enum)
|
||||
|
||||
enum Enum1 { A1, B1 }; // The enum will receive [[nodiscard]]
|
||||
|
||||
struct Record1 { }; // The struct will *not* receive [[nodiscard]]
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = any(record, enum))
|
||||
|
||||
enum Enum2 { A2, B2 }; // The enum will receive [[nodiscard]]
|
||||
|
||||
struct Record2 { }; // The struct *will* receive [[nodiscard]]
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
// This is an error, since [[nodiscard]] can't be applied to namespaces:
|
||||
#pragma clang attribute push([[nodiscard]], apply_to = any(record, namespace))
|
||||
|
||||
#pragma clang attribute pop
|
||||
|
||||
Multiple match rules can be specified using the ``any`` match rule, as shown
|
||||
in the example above. The ``any`` rule applies attributes to all declarations
|
||||
that are matched by at least one of the rules in the ``any``. It doesn't nest
|
||||
and can't be used inside the other match rules. Redundant match rules or rules
|
||||
that conflict with one another should not be used inside of ``any``.
|
||||
|
||||
Clang supports the following match rules:
|
||||
|
||||
- ``function``: Can be used to apply attributes to functions. This includes C++
|
||||
member functions, static functions, operators, and constructors/destructors.
|
||||
|
||||
- ``function(is_member)``: Can be used to apply attributes to C++ member
|
||||
functions. This includes members like static functions, operators, and
|
||||
constructors/destructors.
|
||||
|
||||
- ``hasType(functionType)``: Can be used to apply attributes to functions, C++
|
||||
member functions, and variables/fields whose type is a function pointer. It
|
||||
does not apply attributes to Objective-C methods or blocks.
|
||||
|
||||
- ``type_alias``: Can be used to apply attributes to ``typedef`` declarations
|
||||
and C++11 type aliases.
|
||||
|
||||
- ``record``: Can be used to apply attributes to ``struct``, ``class``, and
|
||||
``union`` declarations.
|
||||
|
||||
- ``record(unless(is_union))``: Can be used to apply attributes only to
|
||||
``struct`` and ``class`` declarations.
|
||||
|
||||
- ``enum``: Can be be used to apply attributes to enumeration declarations.
|
||||
|
||||
- ``enum_constant``: Can be used to apply attributes to enumerators.
|
||||
|
||||
- ``variable``: Can be used to apply attributes to variables, including
|
||||
local variables, parameters, global variables, and static member variables.
|
||||
It does not apply attributes to instance member variables or Objective-C
|
||||
ivars.
|
||||
|
||||
- ``variable(is_thread_local)``: Can be used to apply attributes to thread-local
|
||||
variables only.
|
||||
|
||||
- ``variable(is_global)``: Can be used to apply attributes to global variables
|
||||
only.
|
||||
|
||||
- ``variable(is_parameter)``: Can be used to apply attributes to parameters
|
||||
only.
|
||||
|
||||
- ``variable(unless(is_parameter))``: Can be used to apply attributes to all
|
||||
the variables that are not parameters.
|
||||
|
||||
- ``field``: Can be used to apply attributes to non-static member variables
|
||||
in a record. This includes Objective-C ivars.
|
||||
|
||||
- ``namespace``: Can be used to apply attributes to ``namespace`` declarations.
|
||||
|
||||
- ``objc_interface``: Can be used to apply attributes to ``@interface``
|
||||
declarations.
|
||||
|
||||
- ``objc_protocol``: Can be used to apply attributes to ``@protocol``
|
||||
declarations.
|
||||
|
||||
- ``objc_category``: Can be used to apply attributes to category declarations,
|
||||
including class extensions.
|
||||
|
||||
- ``objc_method``: Can be used to apply attributes to Objective-C methods,
|
||||
including instance and class methods. Implicit methods like implicit property
|
||||
getters and setters do not receive the attribute.
|
||||
|
||||
- ``objc_method(is_instance)``: Can be used to apply attributes to Objective-C
|
||||
instance methods.
|
||||
|
||||
- ``objc_property``: Can be used to apply attributes to ``@property``
|
||||
declarations.
|
||||
|
||||
- ``block``: Can be used to apply attributes to block declarations. This does
|
||||
not include variables/fields of block pointer type.
|
||||
|
||||
The use of ``unless`` in match rules is currently restricted to a strict set of
|
||||
sub-rules that are used by the supported attributes. That means that even though
|
||||
``variable(unless(is_parameter))`` is a valid match rule,
|
||||
``variable(unless(is_thread_local))`` is not.
|
||||
|
||||
Supported Attributes
|
||||
--------------------
|
||||
|
||||
Not all attributes can be used with the ``#pragma clang attribute`` directive.
|
||||
Notably, statement attributes like ``[[fallthrough]]`` or type attributes
|
||||
like ``address_space`` aren't supported by this directive. You can determine
|
||||
whether or not an attribute is supported by the pragma by referring to the
|
||||
:doc:`individual documentation for that attribute <AttributeReference>`.
|
||||
|
||||
The attributes are applied to all matching declarations individually, even when
|
||||
the attribute is semantically incorrect. The attributes that aren't applied to
|
||||
any declaration are not verified semantically.
|
||||
|
@ -25,17 +25,10 @@ following compile-time flags:
|
||||
**extra** slowdown).
|
||||
* ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown).
|
||||
|
||||
You may also specify ``-fsanitize-coverage=indirect-calls`` for
|
||||
additional `caller-callee coverage`_.
|
||||
|
||||
At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``,
|
||||
``LSAN_OPTIONS``, ``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as
|
||||
appropriate. For the standalone coverage mode, use ``UBSAN_OPTIONS``.
|
||||
|
||||
To get `Coverage counters`_, add ``-fsanitize-coverage=8bit-counters``
|
||||
to one of the above compile-time flags. At runtime, use
|
||||
``*SAN_OPTIONS=coverage=1:coverage_counters=1``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
@ -199,135 +192,9 @@ edges by introducing new dummy blocks and then instruments those blocks:
|
||||
|/
|
||||
C
|
||||
|
||||
Bitset
|
||||
======
|
||||
|
||||
When ``coverage_bitset=1`` run-time flag is given, the coverage will also be
|
||||
dumped as a bitset (text file with 1 for blocks that have been executed and 0
|
||||
for blocks that were not).
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -fsanitize=address -fsanitize-coverage=edge cov.cc
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out
|
||||
main
|
||||
% ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out 1
|
||||
foo
|
||||
main
|
||||
% head *bitset*
|
||||
==> a.out.38214.bitset-sancov <==
|
||||
01101
|
||||
==> a.out.6128.bitset-sancov <==
|
||||
11011%
|
||||
|
||||
For a given executable the length of the bitset is always the same (well,
|
||||
unless dlopen/dlclose come into play), so the bitset coverage can be
|
||||
easily used for bitset-based corpus distillation.
|
||||
|
||||
Caller-callee coverage
|
||||
======================
|
||||
|
||||
**Deprecated, don't use**
|
||||
|
||||
Every indirect function call is instrumented with a run-time function call that
|
||||
captures caller and callee. At the shutdown time the process dumps a separate
|
||||
file called ``caller-callee.PID.sancov`` which contains caller/callee pairs as
|
||||
pairs of lines (odd lines are callers, even lines are callees)
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a6510
|
||||
a.out 0x4a2e0c
|
||||
a.out 0x4a87f0
|
||||
|
||||
Current limitations:
|
||||
|
||||
* Only the first 14 callees for every caller are recorded, the rest are silently
|
||||
ignored.
|
||||
* The output format is not very compact since caller and callee may reside in
|
||||
different modules and we need to spell out the module names.
|
||||
* The routine that dumps the output is not optimized for speed
|
||||
* Only Linux x86_64 is tested so far.
|
||||
* Sandboxes are not supported.
|
||||
|
||||
Coverage counters
|
||||
=================
|
||||
|
||||
**Deprecated, don't use**
|
||||
|
||||
This experimental feature is inspired by
|
||||
`AFL <http://lcamtuf.coredump.cx/afl/technical_details.txt>`__'s coverage
|
||||
instrumentation. With additional compile-time and run-time flags you can get
|
||||
more sensitive coverage information. In addition to boolean values assigned to
|
||||
every basic block (edge) the instrumentation will collect imprecise counters.
|
||||
On exit, every counter will be mapped to a 8-bit bitset representing counter
|
||||
ranges: ``1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+`` and those 8-bit bitsets will
|
||||
be dumped to disk.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=edge,8bit-counters
|
||||
% ASAN_OPTIONS="coverage=1:coverage_counters=1" ./a.out
|
||||
% ls -l *counters-sancov
|
||||
... a.out.17110.counters-sancov
|
||||
% xxd *counters-sancov
|
||||
0000000: 0001 0100 01
|
||||
|
||||
These counters may also be used for in-process coverage-guided fuzzers. See
|
||||
``include/sanitizer/coverage_interface.h``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// The coverage instrumentation may optionally provide imprecise counters.
|
||||
// Rather than exposing the counter values to the user we instead map
|
||||
// the counters to a bitset.
|
||||
// Every counter is associated with 8 bits in the bitset.
|
||||
// We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
|
||||
// The i-th bit is set to 1 if the counter value is in the i-th range.
|
||||
// This counter-based coverage implementation is *not* thread-safe.
|
||||
|
||||
// Returns the number of registered coverage counters.
|
||||
uintptr_t __sanitizer_get_number_of_counters();
|
||||
// Updates the counter 'bitset', clears the counters and returns the number of
|
||||
// new bits in 'bitset'.
|
||||
// If 'bitset' is nullptr, only clears the counters.
|
||||
// Otherwise 'bitset' should be at least
|
||||
// __sanitizer_get_number_of_counters bytes long and 8-aligned.
|
||||
uintptr_t
|
||||
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
|
||||
|
||||
Tracing basic blocks
|
||||
====================
|
||||
|
||||
**Deprecated, don't use**
|
||||
|
||||
Experimental support for basic block (or edge) tracing.
|
||||
With ``-fsanitize-coverage=trace-bb`` the compiler will insert
|
||||
``__sanitizer_cov_trace_basic_block(s32 *id)`` before every function, basic block, or edge
|
||||
(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``).
|
||||
Example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
% clang -g -fsanitize=address -fsanitize-coverage=edge,trace-bb foo.cc
|
||||
% ASAN_OPTIONS=coverage=1 ./a.out
|
||||
|
||||
This will produce two files after the process exit:
|
||||
`trace-points.PID.sancov` and `trace-events.PID.sancov`.
|
||||
The first file will contain a textual description of all the instrumented points in the program
|
||||
in the form that you can feed into llvm-symbolizer (e.g. `a.out 0x4dca89`), one per line.
|
||||
The second file will contain the actual execution trace as a sequence of 4-byte integers
|
||||
-- these integers are the indices into the array of instrumented points (the first file).
|
||||
|
||||
Basic block tracing is currently supported only for single-threaded applications.
|
||||
|
||||
|
||||
Tracing PCs
|
||||
===========
|
||||
|
||||
**Deprecated, don't use**
|
||||
|
||||
*Experimental* feature similar to tracing basic blocks, but with a different API.
|
||||
With ``-fsanitize-coverage=trace-pc`` the compiler will insert
|
||||
``__sanitizer_cov_trace_pc()`` on every edge.
|
||||
@ -529,62 +396,3 @@ memory-mapped file as soon as it collected.
|
||||
Note that on 64-bit platforms, this method writes 2x more data than the default,
|
||||
because it stores full PC values instead of 32-bit offsets.
|
||||
|
||||
In-process fuzzing
|
||||
==================
|
||||
|
||||
Coverage data could be useful for fuzzers and sometimes it is preferable to run
|
||||
a fuzzer in the same process as the code being fuzzed (in-process fuzzer).
|
||||
|
||||
You can use ``__sanitizer_get_total_unique_coverage()`` from
|
||||
``<sanitizer/coverage_interface.h>`` which returns the number of currently
|
||||
covered entities in the program. This will tell the fuzzer if the coverage has
|
||||
increased after testing every new input.
|
||||
|
||||
If a fuzzer finds a bug in the ASan run, you will need to save the reproducer
|
||||
before exiting the process. Use ``__asan_set_death_callback`` from
|
||||
``<sanitizer/asan_interface.h>`` to do that.
|
||||
|
||||
An example of such fuzzer can be found in `the LLVM tree
|
||||
<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/README.txt?view=markup>`_.
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
This coverage implementation is **fast**. With function-level coverage
|
||||
(``-fsanitize-coverage=func``) the overhead is not measurable. With
|
||||
basic-block-level coverage (``-fsanitize-coverage=bb``) the overhead varies
|
||||
between 0 and 25%.
|
||||
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
benchmark cov0 cov1 diff 0-1 cov2 diff 0-2 diff 1-2
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
400.perlbench 1296.00 1307.00 1.01 1465.00 1.13 1.12
|
||||
401.bzip2 858.00 854.00 1.00 1010.00 1.18 1.18
|
||||
403.gcc 613.00 617.00 1.01 683.00 1.11 1.11
|
||||
429.mcf 605.00 582.00 0.96 610.00 1.01 1.05
|
||||
445.gobmk 896.00 880.00 0.98 1050.00 1.17 1.19
|
||||
456.hmmer 892.00 892.00 1.00 918.00 1.03 1.03
|
||||
458.sjeng 995.00 1009.00 1.01 1217.00 1.22 1.21
|
||||
462.libquantum 497.00 492.00 0.99 534.00 1.07 1.09
|
||||
464.h264ref 1461.00 1467.00 1.00 1543.00 1.06 1.05
|
||||
471.omnetpp 575.00 590.00 1.03 660.00 1.15 1.12
|
||||
473.astar 658.00 652.00 0.99 715.00 1.09 1.10
|
||||
483.xalancbmk 471.00 491.00 1.04 582.00 1.24 1.19
|
||||
433.milc 616.00 627.00 1.02 627.00 1.02 1.00
|
||||
444.namd 602.00 601.00 1.00 654.00 1.09 1.09
|
||||
447.dealII 630.00 634.00 1.01 653.00 1.04 1.03
|
||||
450.soplex 365.00 368.00 1.01 395.00 1.08 1.07
|
||||
453.povray 427.00 434.00 1.02 495.00 1.16 1.14
|
||||
470.lbm 357.00 375.00 1.05 370.00 1.04 0.99
|
||||
482.sphinx3 927.00 928.00 1.00 1000.00 1.08 1.08
|
||||
============== ========= ========= ========= ========= ========= =========
|
||||
|
||||
Why another coverage?
|
||||
=====================
|
||||
|
||||
Why did we implement yet another code coverage?
|
||||
* We needed something that is lightning fast, plays well with
|
||||
AddressSanitizer, and does not significantly increase the binary size.
|
||||
* Traditional coverage implementations based in global counters
|
||||
`suffer from contention on counters
|
||||
<https://groups.google.com/forum/#!topic/llvm-dev/cDqYgnxNEhY>`_.
|
||||
|
@ -132,7 +132,7 @@ INLINE_INHERITED_MEMB = NO
|
||||
# shortest path that makes the file name unique will be used
|
||||
# The default value is: YES.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
|
||||
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
|
||||
# Stripping is only done if one of the specified strings matches the left-hand
|
||||
@ -144,7 +144,7 @@ FULL_PATH_NAMES = NO
|
||||
# will be relative from the directory where doxygen is started.
|
||||
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
|
||||
|
||||
STRIP_FROM_PATH = ../..
|
||||
STRIP_FROM_PATH = @abs_srcdir@/..
|
||||
|
||||
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
|
||||
# path mentioned in the documentation of a class, which tells the reader which
|
||||
@ -153,7 +153,7 @@ STRIP_FROM_PATH = ../..
|
||||
# specify the list of include paths that are normally passed to the compiler
|
||||
# using the -I flag.
|
||||
|
||||
STRIP_FROM_INC_PATH =
|
||||
STRIP_FROM_INC_PATH = @abs_srcdir@/../include
|
||||
|
||||
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
|
||||
# less readable) file names. This can be useful is your file systems doesn't
|
||||
@ -513,7 +513,7 @@ SHOW_GROUPED_MEMB_INC = NO
|
||||
# files with double quotes in the documentation rather than with sharp brackets.
|
||||
# The default value is: NO.
|
||||
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
FORCE_LOCAL_INCLUDES = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
|
||||
# documentation for inline members.
|
||||
|
@ -2082,10 +2082,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
const Attr *getUnusedResultAttr() const;
|
||||
|
||||
/// \brief Returns true if this function or its return type has the
|
||||
/// warn_unused_result attribute. If the return type has the attribute and
|
||||
/// this function is a method of the return type's class, then false will be
|
||||
/// returned to avoid spurious warnings on member methods such as assignment
|
||||
/// operators.
|
||||
/// warn_unused_result attribute.
|
||||
bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; }
|
||||
|
||||
/// \brief Returns the storage class as written in the source. For the
|
||||
|
@ -318,8 +318,9 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
/// \brief Offsets to the stored exprs.
|
||||
/// This enumeration contains offsets to all the pointers to children
|
||||
/// expressions stored in OMPLoopDirective.
|
||||
/// The first 9 children are nesessary for all the loop directives, and
|
||||
/// the next 10 are specific to the worksharing ones.
|
||||
/// The first 9 children are necessary for all the loop directives,
|
||||
/// the next 8 are specific to the worksharing ones, and the next 11 are
|
||||
/// used for combined constructs containing two pragmas associated to loops.
|
||||
/// After the fixed children, three arrays of length CollapsedNum are
|
||||
/// allocated: loop counters, their updates and final values.
|
||||
/// PrevLowerBound and PrevUpperBound are used to communicate blocking
|
||||
@ -344,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
// specify the offset to the end (and start of the following counters/
|
||||
// updates/finals arrays).
|
||||
DefaultEnd = 9,
|
||||
// The following 12 exprs are used by worksharing and distribute loops only.
|
||||
// The following 8 exprs are used by worksharing and distribute loops only.
|
||||
IsLastIterVariableOffset = 9,
|
||||
LowerBoundVariableOffset = 10,
|
||||
UpperBoundVariableOffset = 11,
|
||||
@ -353,13 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
NextLowerBoundOffset = 14,
|
||||
NextUpperBoundOffset = 15,
|
||||
NumIterationsOffset = 16,
|
||||
// Offset to the end for worksharing loop directives.
|
||||
WorksharingEnd = 17,
|
||||
PrevLowerBoundVariableOffset = 17,
|
||||
PrevUpperBoundVariableOffset = 18,
|
||||
DistIncOffset = 19,
|
||||
PrevEnsureUpperBoundOffset = 20,
|
||||
CombinedLowerBoundVariableOffset = 21,
|
||||
CombinedUpperBoundVariableOffset = 22,
|
||||
CombinedEnsureUpperBoundOffset = 23,
|
||||
CombinedInitOffset = 24,
|
||||
CombinedConditionOffset = 25,
|
||||
CombinedNextLowerBoundOffset = 26,
|
||||
CombinedNextUpperBoundOffset = 27,
|
||||
// Offset to the end (and start of the following counters/updates/finals
|
||||
// arrays) for worksharing loop directives.
|
||||
WorksharingEnd = 21,
|
||||
// arrays) for combined distribute loop directives.
|
||||
CombinedDistributeEnd = 28,
|
||||
};
|
||||
|
||||
/// \brief Get the counters storage.
|
||||
@ -423,11 +433,12 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
|
||||
/// \brief Offset to the start of children expression arrays.
|
||||
static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
|
||||
return (isOpenMPWorksharingDirective(Kind) ||
|
||||
isOpenMPTaskLoopDirective(Kind) ||
|
||||
isOpenMPDistributeDirective(Kind))
|
||||
? WorksharingEnd
|
||||
: DefaultEnd;
|
||||
if (isOpenMPLoopBoundSharingDirective(Kind))
|
||||
return CombinedDistributeEnd;
|
||||
if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) ||
|
||||
isOpenMPDistributeDirective(Kind))
|
||||
return WorksharingEnd;
|
||||
return DefaultEnd;
|
||||
}
|
||||
|
||||
/// \brief Children number.
|
||||
@ -515,33 +526,60 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
*std::next(child_begin(), NumIterationsOffset) = NI;
|
||||
}
|
||||
void setPrevLowerBoundVariable(Expr *PrevLB) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB;
|
||||
}
|
||||
void setPrevUpperBoundVariable(Expr *PrevUB) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB;
|
||||
}
|
||||
void setDistInc(Expr *DistInc) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), DistIncOffset) = DistInc;
|
||||
}
|
||||
void setPrevEnsureUpperBound(Expr *PrevEUB) {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB;
|
||||
}
|
||||
void setCombinedLowerBoundVariable(Expr *CombLB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB;
|
||||
}
|
||||
void setCombinedUpperBoundVariable(Expr *CombUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB;
|
||||
}
|
||||
void setCombinedEnsureUpperBound(Expr *CombEUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB;
|
||||
}
|
||||
void setCombinedInit(Expr *CombInit) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedInitOffset) = CombInit;
|
||||
}
|
||||
void setCombinedCond(Expr *CombCond) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedConditionOffset) = CombCond;
|
||||
}
|
||||
void setCombinedNextLowerBound(Expr *CombNLB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB;
|
||||
}
|
||||
void setCombinedNextUpperBound(Expr *CombNUB) {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
*std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB;
|
||||
}
|
||||
void setCounters(ArrayRef<Expr *> A);
|
||||
void setPrivateCounters(ArrayRef<Expr *> A);
|
||||
void setInits(ArrayRef<Expr *> A);
|
||||
@ -549,6 +587,33 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
void setFinals(ArrayRef<Expr *> A);
|
||||
|
||||
public:
|
||||
/// The expressions built to support OpenMP loops in combined/composite
|
||||
/// pragmas (e.g. pragma omp distribute parallel for)
|
||||
struct DistCombinedHelperExprs {
|
||||
/// DistributeLowerBound - used when composing 'omp distribute' with
|
||||
/// 'omp for' in a same construct.
|
||||
Expr *LB;
|
||||
/// DistributeUpperBound - used when composing 'omp distribute' with
|
||||
/// 'omp for' in a same construct.
|
||||
Expr *UB;
|
||||
/// DistributeEnsureUpperBound - used when composing 'omp distribute'
|
||||
/// with 'omp for' in a same construct, EUB depends on DistUB
|
||||
Expr *EUB;
|
||||
/// Distribute loop iteration variable init used when composing 'omp
|
||||
/// distribute'
|
||||
/// with 'omp for' in a same construct
|
||||
Expr *Init;
|
||||
/// Distribute Loop condition used when composing 'omp distribute'
|
||||
/// with 'omp for' in a same construct
|
||||
Expr *Cond;
|
||||
/// Update of LowerBound for statically sheduled omp loops for
|
||||
/// outer loop in combined constructs (e.g. 'distribute parallel for')
|
||||
Expr *NLB;
|
||||
/// Update of UpperBound for statically sheduled omp loops for
|
||||
/// outer loop in combined constructs (e.g. 'distribute parallel for')
|
||||
Expr *NUB;
|
||||
};
|
||||
|
||||
/// \brief The expressions built for the OpenMP loop CodeGen for the
|
||||
/// whole collapsed loop nest.
|
||||
struct HelperExprs {
|
||||
@ -611,6 +676,9 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
/// Init statement for all captured expressions.
|
||||
Stmt *PreInits;
|
||||
|
||||
/// Expressions used when combining OpenMP loop pragmas
|
||||
DistCombinedHelperExprs DistCombinedFields;
|
||||
|
||||
/// \brief Check if all the expressions are built (does not check the
|
||||
/// worksharing ones).
|
||||
bool builtAll() {
|
||||
@ -654,6 +722,13 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
Finals[i] = nullptr;
|
||||
}
|
||||
PreInits = nullptr;
|
||||
DistCombinedFields.LB = nullptr;
|
||||
DistCombinedFields.UB = nullptr;
|
||||
DistCombinedFields.EUB = nullptr;
|
||||
DistCombinedFields.Init = nullptr;
|
||||
DistCombinedFields.Cond = nullptr;
|
||||
DistCombinedFields.NLB = nullptr;
|
||||
DistCombinedFields.NUB = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@ -757,37 +832,71 @@ class OMPLoopDirective : public OMPExecutableDirective {
|
||||
*std::next(child_begin(), NumIterationsOffset)));
|
||||
}
|
||||
Expr *getPrevLowerBoundVariable() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevLowerBoundVariableOffset)));
|
||||
}
|
||||
Expr *getPrevUpperBoundVariable() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevUpperBoundVariableOffset)));
|
||||
}
|
||||
Expr *getDistInc() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), DistIncOffset)));
|
||||
}
|
||||
Expr *getPrevEnsureUpperBound() const {
|
||||
assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
|
||||
isOpenMPTaskLoopDirective(getDirectiveKind()) ||
|
||||
isOpenMPDistributeDirective(getDirectiveKind())) &&
|
||||
"expected worksharing loop directive");
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), PrevEnsureUpperBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedLowerBoundVariable() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedLowerBoundVariableOffset)));
|
||||
}
|
||||
Expr *getCombinedUpperBoundVariable() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedUpperBoundVariableOffset)));
|
||||
}
|
||||
Expr *getCombinedEnsureUpperBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedEnsureUpperBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedInit() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedInitOffset)));
|
||||
}
|
||||
Expr *getCombinedCond() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedConditionOffset)));
|
||||
}
|
||||
Expr *getCombinedNextLowerBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedNextLowerBoundOffset)));
|
||||
}
|
||||
Expr *getCombinedNextUpperBound() const {
|
||||
assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
|
||||
"expected loop bound sharing directive");
|
||||
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
|
||||
*std::next(child_begin(), CombinedNextUpperBoundOffset)));
|
||||
}
|
||||
const Stmt *getBody() const {
|
||||
// This relies on the loop form is already checked by Sema.
|
||||
Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
|
||||
|
@ -1544,7 +1544,11 @@ class DependentSizedArrayTypeLoc :
|
||||
public InheritingConcreteTypeLoc<ArrayTypeLoc,
|
||||
DependentSizedArrayTypeLoc,
|
||||
DependentSizedArrayType> {
|
||||
|
||||
public:
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
ArrayTypeLoc::initializeLocal(Context, Loc);
|
||||
setSizeExpr(getTypePtr()->getSizeExpr());
|
||||
}
|
||||
};
|
||||
|
||||
class VariableArrayTypeLoc :
|
||||
|
@ -248,6 +248,8 @@ def COnly : LangOpt<"CPlusPlus", 1>;
|
||||
def CPlusPlus : LangOpt<"CPlusPlus">;
|
||||
def OpenCL : LangOpt<"OpenCL">;
|
||||
def RenderScript : LangOpt<"RenderScript">;
|
||||
def ObjC : LangOpt<"ObjC1">;
|
||||
def BlocksSupported : LangOpt<"Blocks">;
|
||||
|
||||
// Defines targets for target-specific attributes. The list of strings should
|
||||
// specify architectures for which the target applies, based off the ArchType
|
||||
@ -270,6 +272,112 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
|
||||
let CXXABIs = ["Microsoft"];
|
||||
}
|
||||
|
||||
// Attribute subject match rules that are used for #pragma clang attribute.
|
||||
//
|
||||
// A instance of AttrSubjectMatcherRule represents an individual match rule.
|
||||
// An individual match rule can correspond to a number of different attribute
|
||||
// subjects, e.g. "record" matching rule corresponds to the Record and
|
||||
// CXXRecord attribute subjects.
|
||||
//
|
||||
// Match rules are used in the subject list of the #pragma clang attribute.
|
||||
// Match rules can have sub-match rules that are instances of
|
||||
// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number
|
||||
// of different attribute subjects, and it can have a negated spelling as well.
|
||||
// For example, "variable(unless(is_parameter))" matching rule corresponds to
|
||||
// the NonParmVar attribute subject.
|
||||
class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects,
|
||||
bit negated = 0> {
|
||||
string Name = name;
|
||||
list<AttrSubject> Subjects = subjects;
|
||||
bit Negated = negated;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, the language options are taken
|
||||
// from the parent matcher rule.
|
||||
list<LangOpt> LangOpts = [];
|
||||
}
|
||||
class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects,
|
||||
list<AttrSubjectMatcherSubRule> subrules = []> {
|
||||
string Name = name;
|
||||
list<AttrSubject> Subjects = subjects;
|
||||
list<AttrSubjectMatcherSubRule> Constraints = subrules;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, no language options are required.
|
||||
list<LangOpt> LangOpts = [];
|
||||
}
|
||||
|
||||
// function(is_member)
|
||||
def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> {
|
||||
let LangOpts = [CPlusPlus];
|
||||
}
|
||||
def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [
|
||||
SubRuleForCXXMethod
|
||||
]>;
|
||||
// hasType is abstract, it should be used with one of the sub-rules.
|
||||
def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [
|
||||
AttrSubjectMatcherSubRule<"functionType", [FunctionLike]>
|
||||
|
||||
// FIXME: There's a matcher ambiguity with objc methods and blocks since
|
||||
// functionType excludes them but functionProtoType includes them.
|
||||
// AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]>
|
||||
]>;
|
||||
def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias",
|
||||
[TypedefName]>;
|
||||
def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record,
|
||||
CXXRecord], [
|
||||
// unless(is_union)
|
||||
AttrSubjectMatcherSubRule<"is_union", [Struct], 1>
|
||||
]>;
|
||||
def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>;
|
||||
def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant",
|
||||
[EnumConstant]>;
|
||||
def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [
|
||||
AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>,
|
||||
AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>,
|
||||
AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>,
|
||||
// unless(is_parameter)
|
||||
AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1>
|
||||
]>;
|
||||
def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>;
|
||||
def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace",
|
||||
[Namespace]> {
|
||||
let LangOpts = [CPlusPlus];
|
||||
}
|
||||
def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface",
|
||||
[ObjCInterface]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol",
|
||||
[ObjCProtocol]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
|
||||
[ObjCCategory]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
|
||||
[ObjCMethod], [
|
||||
AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
|
||||
]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property",
|
||||
[ObjCProperty]> {
|
||||
let LangOpts = [ObjC];
|
||||
}
|
||||
def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
|
||||
let LangOpts = [BlocksSupported];
|
||||
}
|
||||
|
||||
// Aggregate attribute subject match rules are abstract match rules that can't
|
||||
// be used directly in #pragma clang attribute. Instead, users have to use
|
||||
// subject match rules that correspond to attribute subjects that derive from
|
||||
// the specified subject.
|
||||
class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
|
||||
AttrSubject Subject = subject;
|
||||
}
|
||||
|
||||
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
|
||||
|
||||
class Attr {
|
||||
// The various ways in which an attribute can be spelled in source
|
||||
list<Spelling> Spellings;
|
||||
@ -305,6 +413,14 @@ class Attr {
|
||||
// Set to true if this attribute meaningful when applied to or inherited
|
||||
// in a class template definition.
|
||||
bit MeaningfulToClassTemplateDefinition = 0;
|
||||
// Set to true if this attribute can be used with '#pragma clang attribute'.
|
||||
// By default, when this value is false, an attribute is supported by the
|
||||
// '#pragma clang attribute' only when:
|
||||
// - It has documentation.
|
||||
// - It has a subject list whose subjects can be represented using subject
|
||||
// match rules.
|
||||
// - It has GNU/CXX11 spelling and doesn't require delayed parsing.
|
||||
bit ForcePragmaAttributeSupport = 0;
|
||||
// Lists language options, one of which is required to be true for the
|
||||
// attribute to be applicable. If empty, no language options are required.
|
||||
list<LangOpt> LangOpts = [];
|
||||
@ -478,6 +594,9 @@ def AnalyzerNoReturn : InheritableAttr {
|
||||
def Annotate : InheritableParamAttr {
|
||||
let Spellings = [GNU<"annotate">];
|
||||
let Args = [StringArgument<"Annotation">];
|
||||
// Ensure that the annotate attribute can be used with
|
||||
// '#pragma clang attribute' even though it has no subject list.
|
||||
let ForcePragmaAttributeSupport = 1;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
@ -536,7 +655,7 @@ def Availability : InheritableAttr {
|
||||
} }];
|
||||
let HasCustomParsing = 1;
|
||||
let DuplicatesAllowedWhileMerging = 1;
|
||||
// let Subjects = SubjectList<[Named]>;
|
||||
let Subjects = SubjectList<[Named]>;
|
||||
let Documentation = [AvailabilityDocs];
|
||||
}
|
||||
|
||||
@ -547,7 +666,7 @@ def ExternalSourceSymbol : InheritableAttr {
|
||||
StringArgument<"definedIn", 1>,
|
||||
BoolArgument<"generatedDeclaration", 1>];
|
||||
let HasCustomParsing = 1;
|
||||
// let Subjects = SubjectList<[Named]>;
|
||||
let Subjects = SubjectList<[Named]>;
|
||||
let Documentation = [ExternalSourceSymbolDocs];
|
||||
}
|
||||
|
||||
@ -2242,9 +2361,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
|
||||
let Documentation = [DLLImportDocs];
|
||||
}
|
||||
|
||||
def SelectAny : InheritableAttr {
|
||||
let Spellings = [Declspec<"selectany">];
|
||||
let LangOpts = [MicrosoftExt];
|
||||
def SelectAny : InheritableAttr, TargetSpecificAttr<TargetWindows> {
|
||||
let Spellings = [Declspec<"selectany">, GCC<"selectany">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
32
include/clang/Basic/AttrSubjectMatchRules.h
Normal file
32
include/clang/Basic/AttrSubjectMatchRules.h
Normal file
@ -0,0 +1,32 @@
|
||||
//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- 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_BASIC_ATTR_SUBJECT_MATCH_RULES_H
|
||||
#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
namespace attr {
|
||||
|
||||
/// \brief A list of all the recognized kinds of attributes.
|
||||
enum SubjectMatchRule {
|
||||
#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X,
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
};
|
||||
|
||||
const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule);
|
||||
|
||||
using ParsedSubjectMatchRuleSet = llvm::DenseMap<int, SourceRange>;
|
||||
|
||||
} // end namespace attr
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -28,6 +28,11 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list
|
||||
SOURCE Attr.td
|
||||
TARGET ClangAttrList)
|
||||
|
||||
clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE Attr.td
|
||||
TARGET ClangAttrSubjectMatchRuleList)
|
||||
|
||||
clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE Attr.td
|
||||
|
@ -36,7 +36,9 @@ def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer"
|
||||
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
|
||||
def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
|
||||
def BitFieldWidth : DiagGroup<"bitfield-width">;
|
||||
def Coroutine : DiagGroup<"coroutine">;
|
||||
def CoroutineMissingUnhandledException :
|
||||
DiagGroup<"coroutine-missing-unhandled-exception">;
|
||||
def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>;
|
||||
def ConstantConversion :
|
||||
DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
|
||||
def LiteralConversion : DiagGroup<"literal-conversion">;
|
||||
@ -459,7 +461,9 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
|
||||
def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
|
||||
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
|
||||
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
|
||||
def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>;
|
||||
def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
|
||||
def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
|
||||
PragmaClangAttribute]>;
|
||||
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
|
||||
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
|
||||
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
|
||||
|
@ -242,6 +242,7 @@ def warn_bad_character_encoding : ExtWarn<
|
||||
"illegal character encoding in character literal">,
|
||||
InGroup<InvalidSourceEncoding>;
|
||||
def err_lexing_string : Error<"failure when lexing a string">;
|
||||
def err_placeholder_in_source : Error<"editor placeholder in source file">;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -594,8 +595,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">;
|
||||
def err_mmap_module_redefinition : Error<
|
||||
"redefinition of module '%0'">;
|
||||
def note_mmap_prev_definition : Note<"previously defined here">;
|
||||
def err_mmap_umbrella_dir_not_found : Error<
|
||||
"umbrella directory '%0' not found">;
|
||||
def err_mmap_umbrella_clash : Error<
|
||||
"umbrella for module '%0' already covers this directory">;
|
||||
def err_mmap_module_id : Error<
|
||||
@ -656,6 +655,9 @@ def note_implicit_top_level_module_import_here : Note<
|
||||
def warn_uncovered_module_header : Warning<
|
||||
"umbrella header for module '%0' does not include header '%1'">,
|
||||
InGroup<IncompleteUmbrella>;
|
||||
def warn_mmap_umbrella_dir_not_found : Warning<
|
||||
"umbrella directory '%0' not found">,
|
||||
InGroup<IncompleteUmbrella>;
|
||||
def err_expected_id_building_module : Error<
|
||||
"expected a module name in '__building_module' expression">;
|
||||
def warn_use_of_private_header_outside_module : Warning<
|
||||
|
@ -979,6 +979,43 @@ def err_pragma_optimize_invalid_argument : Error<
|
||||
"expected 'on' or 'off'">;
|
||||
def err_pragma_optimize_extra_argument : Error<
|
||||
"unexpected extra argument '%0' to '#pragma clang optimize'">;
|
||||
// - #pragma clang attribute
|
||||
def err_pragma_attribute_expected_push_pop : Error<
|
||||
"expected 'push' or 'pop' after '#pragma clang attribute'">;
|
||||
def err_pragma_attribute_invalid_argument : Error<
|
||||
"unexpected argument '%0' to '#pragma clang attribute'; "
|
||||
"expected 'push' or 'pop'">;
|
||||
def err_pragma_attribute_expected_attribute : Error<
|
||||
"expected an attribute after '('">;
|
||||
def err_pragma_attribute_expected_attribute_name : Error<
|
||||
"expected identifier that represents an attribute name">;
|
||||
def err_pragma_attribute_extra_tokens_after_attribute : Error<
|
||||
"extra tokens after attribute in a '#pragma clang attribute push'">;
|
||||
def err_pragma_attribute_unsupported_attribute : Error<
|
||||
"attribute %0 is not supported by '#pragma clang attribute'">;
|
||||
def err_pragma_attribute_multiple_attributes : Error<
|
||||
"more than one attribute specified in '#pragma clang attribute push'">;
|
||||
def err_pragma_attribute_expected_attribute_syntax : Error<
|
||||
"expected an attribute that is specified using the GNU, C++11 or '__declspec'"
|
||||
" syntax">;
|
||||
def note_pragma_attribute_use_attribute_kw : Note<"use the GNU '__attribute__' "
|
||||
"syntax">;
|
||||
def err_pragma_attribute_invalid_subject_set_specifier : Error<
|
||||
"expected attribute subject set specifier 'apply_to'">;
|
||||
def err_pragma_attribute_expected_subject_identifier : Error<
|
||||
"expected an identifier that corresponds to an attribute subject rule">;
|
||||
def err_pragma_attribute_unknown_subject_rule : Error<
|
||||
"unknown attribute subject rule '%0'">;
|
||||
def err_pragma_attribute_expected_subject_sub_identifier : Error<
|
||||
"expected an identifier that corresponds to an attribute subject matcher "
|
||||
"sub-rule; '%0' matcher %select{does not support sub-rules|supports the "
|
||||
"following sub-rules: %2|}1">;
|
||||
def err_pragma_attribute_unknown_subject_sub_rule : Error<
|
||||
"%select{invalid use of|unknown}2 attribute subject matcher sub-rule '%0'; "
|
||||
"'%1' matcher %select{does not support sub-rules|supports the following "
|
||||
"sub-rules: %3}2">;
|
||||
def err_pragma_attribute_duplicate_subject : Error<
|
||||
"duplicate attribute subject matcher '%0'">;
|
||||
|
||||
def err_opencl_unroll_hint_on_non_loop : Error<
|
||||
"OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">;
|
||||
|
@ -750,6 +750,25 @@ def err_pragma_loop_compatibility : Error<
|
||||
def err_pragma_loop_precedes_nonloop : Error<
|
||||
"expected a for, while, or do-while loop to follow '%0'">;
|
||||
|
||||
def err_pragma_attribute_matcher_subrule_contradicts_rule : Error<
|
||||
"redundant attribute subject matcher sub-rule '%0'; '%1' already matches "
|
||||
"those declarations">;
|
||||
def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error<
|
||||
"negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">;
|
||||
def err_pragma_attribute_invalid_matchers : Error<
|
||||
"attribute %0 can't be applied to %1">;
|
||||
def err_pragma_attribute_stack_mismatch : Error<
|
||||
"'#pragma clang attribute pop' with no matching '#pragma clang attribute push'">;
|
||||
def warn_pragma_attribute_unused : Warning<
|
||||
"unused attribute %0 in '#pragma clang attribute push' region">,
|
||||
InGroup<PragmaClangAttribute>;
|
||||
def note_pragma_attribute_region_ends_here : Note<
|
||||
"'#pragma clang attribute push' regions ends here">;
|
||||
def err_pragma_attribute_no_pop_eof : Error<"unterminated "
|
||||
"'#pragma clang attribute push' at end of file">;
|
||||
def note_pragma_attribute_applied_decl_here : Note<
|
||||
"when applied to this declaration">;
|
||||
|
||||
/// Objective-C parser diagnostics
|
||||
def err_duplicate_class_def : Error<
|
||||
"duplicate interface definition for class %0">;
|
||||
@ -4981,6 +5000,8 @@ def note_protected_by_if_available : Note<
|
||||
"jump enters controlled statement of if available">;
|
||||
def note_protected_by_vla : Note<
|
||||
"jump bypasses initialization of variable length array">;
|
||||
def note_protected_by_objc_fast_enumeration : Note<
|
||||
"jump enters Objective-C fast enumeration loop">;
|
||||
def note_protected_by_objc_try : Note<
|
||||
"jump bypasses initialization of @try block">;
|
||||
def note_protected_by_objc_catch : Note<
|
||||
@ -8854,6 +8875,11 @@ def err_coroutine_invalid_func_context : Error<
|
||||
def err_implied_coroutine_type_not_found : Error<
|
||||
"%0 type was not found; include <experimental/coroutine> before defining "
|
||||
"a coroutine">;
|
||||
def err_implicit_coroutine_std_nothrow_type_not_found : Error<
|
||||
"std::nothrow was not found; include <new> before defining a coroutine which "
|
||||
"uses get_return_object_on_allocation_failure()">;
|
||||
def err_malformed_std_nothrow : Error<
|
||||
"std::nothrow must be a valid variable declaration">;
|
||||
def err_malformed_std_coroutine_handle : Error<
|
||||
"std::experimental::coroutine_handle must be a class template">;
|
||||
def err_coroutine_handle_missing_member : Error<
|
||||
@ -8873,16 +8899,21 @@ def err_coroutine_promise_return_ill_formed : Error<
|
||||
"%0 declares both 'return_value' and 'return_void'">;
|
||||
def note_coroutine_promise_implicit_await_transform_required_here : Note<
|
||||
"call to 'await_transform' implicitly required by 'co_await' here">;
|
||||
def note_coroutine_promise_call_implicitly_required : Note<
|
||||
def note_coroutine_promise_suspend_implicitly_required : Note<
|
||||
"call to '%select{initial_suspend|final_suspend}0' implicitly "
|
||||
"required by the %select{initial suspend point|final suspend point}0">;
|
||||
def err_coroutine_promise_unhandled_exception_required : Error<
|
||||
"%0 is required to declare the member 'unhandled_exception()'">;
|
||||
def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning<
|
||||
"%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">,
|
||||
InGroup<Coroutine>;
|
||||
InGroup<CoroutineMissingUnhandledException>;
|
||||
def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
|
||||
"%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
|
||||
def err_coroutine_promise_new_requires_nothrow : Error<
|
||||
"%0 is required to have a non-throwing noexcept specification when the promise "
|
||||
"type declares 'get_return_object_on_allocation_failure()'">;
|
||||
def note_coroutine_promise_call_implicitly_required : Note<
|
||||
"call to %0 implicitly required by coroutine function here">;
|
||||
}
|
||||
|
||||
let CategoryName = "Documentation Issue" in {
|
||||
|
@ -355,6 +355,19 @@ class IdentifierInfo {
|
||||
RecomputeNeedsHandleIdentifier();
|
||||
}
|
||||
|
||||
/// Return true if this identifier is an editor placeholder.
|
||||
///
|
||||
/// Editor placeholders are produced by the code-completion engine and are
|
||||
/// represented as characters between '<#' and '#>' in the source code. An
|
||||
/// example of auto-completed call with a placeholder parameter is shown
|
||||
/// below:
|
||||
/// \code
|
||||
/// function(<#int x#>);
|
||||
/// \endcode
|
||||
bool isEditorPlaceholder() const {
|
||||
return getName().startswith("<#") && getName().endswith("#>");
|
||||
}
|
||||
|
||||
/// \brief Provide less than operator for lexicographical sorting.
|
||||
bool operator<(const IdentifierInfo &RHS) const {
|
||||
return getName() < RHS.getName();
|
||||
|
@ -266,6 +266,8 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
|
||||
|
||||
LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
|
||||
|
||||
LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source")
|
||||
|
||||
#undef LANGOPT
|
||||
#undef COMPATIBLE_LANGOPT
|
||||
#undef BENIGN_LANGOPT
|
||||
|
@ -790,6 +790,9 @@ ANNOTATION(pragma_loop_hint)
|
||||
|
||||
ANNOTATION(pragma_fp)
|
||||
|
||||
// Annotation for the attribute pragma directives - #pragma clang attribute ...
|
||||
ANNOTATION(pragma_attribute)
|
||||
|
||||
// Annotations for module import translated from #include etc.
|
||||
ANNOTATION(module_include)
|
||||
ANNOTATION(module_begin)
|
||||
|
@ -172,6 +172,12 @@ def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">,
|
||||
HelpText<"Enable trigraphs">, Alias<ftrigraphs>;
|
||||
def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">,
|
||||
HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>;
|
||||
def _SLASH_Zc_twoPhase : CLFlag<"Zc:twoPhase">,
|
||||
HelpText<"Enable two-phase name lookup in templates">,
|
||||
Alias<fno_delayed_template_parsing>;
|
||||
def _SLASH_Zc_twoPhase_ : CLFlag<"Zc:twoPhase-">,
|
||||
HelpText<"Disable two-phase name lookup in templates">,
|
||||
Alias<fdelayed_template_parsing>;
|
||||
def _SLASH_Z7 : CLFlag<"Z7">,
|
||||
HelpText<"Enable CodeView debug information in object files">;
|
||||
def _SLASH_Zd : CLFlag<"Zd">,
|
||||
|
@ -1487,6 +1487,12 @@ def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>,
|
||||
def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
|
||||
Flags<[CC1Option]>;
|
||||
|
||||
def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">,
|
||||
Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Treat editor placeholders as valid source code">;
|
||||
def fno_allow_editor_placeholders : Flag<["-"],
|
||||
"fno-allow-editor-placeholders">, Group<f_Group>;
|
||||
|
||||
def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
|
||||
Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
|
||||
def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>,
|
||||
@ -1646,6 +1652,8 @@ def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
|
||||
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
|
||||
def mimplicit_it_EQ : Joined<["-"], "mimplicit-it=">, Group<m_Group>;
|
||||
def mdefault_build_attributes : Joined<["-"], "mdefault-build-attributes">, Group<m_Group>;
|
||||
def mno_default_build_attributes : Joined<["-"], "mno-default-build-attributes">, Group<m_Group>;
|
||||
def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
|
||||
def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
@ -1653,6 +1661,7 @@ def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>;
|
||||
def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>;
|
||||
def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>;
|
||||
def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>;
|
||||
def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>;
|
||||
|
@ -106,8 +106,9 @@ enum class SymbolRole : uint32_t {
|
||||
RelationAccessorOf = 1 << 15,
|
||||
RelationContainedBy = 1 << 16,
|
||||
RelationIBTypeOf = 1 << 17,
|
||||
RelationSpecializationOf = 1 << 18,
|
||||
};
|
||||
static const unsigned SymbolRoleBitNum = 18;
|
||||
static const unsigned SymbolRoleBitNum = 19;
|
||||
typedef unsigned SymbolRoleSet;
|
||||
|
||||
/// Represents a relation to another symbol for a symbol occurrence.
|
||||
|
@ -638,6 +638,8 @@ class Lexer : public PreprocessorLexer {
|
||||
bool IsStartOfConflictMarker(const char *CurPtr);
|
||||
bool HandleEndOfConflictMarker(const char *CurPtr);
|
||||
|
||||
bool lexEditorPlaceholder(Token &Result, const char *CurPtr);
|
||||
|
||||
bool isCodeCompletionPoint(const char *CurPtr) const;
|
||||
void cutOffLexing() { BufferPtr = BufferEnd; }
|
||||
|
||||
|
@ -84,6 +84,7 @@ class Token {
|
||||
StringifiedInMacro = 0x100, // This string or character literal is formed by
|
||||
// macro stringizing or charizing operator.
|
||||
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
|
||||
IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
|
||||
};
|
||||
|
||||
tok::TokenKind getKind() const { return Kind; }
|
||||
@ -298,6 +299,13 @@ class Token {
|
||||
|
||||
/// Returns true if the comma after this token was elided.
|
||||
bool commaAfterElided() const { return getFlag(CommaAfterElided); }
|
||||
|
||||
/// Returns true if this token is an editor placeholder.
|
||||
///
|
||||
/// Editor placeholders are produced by the code-completion engine and are
|
||||
/// represented as characters between '<#' and '#>' in the source code. The
|
||||
/// lexer uses identifier tokens to represent placeholders.
|
||||
bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
|
||||
};
|
||||
|
||||
/// \brief Information about the conditional stack (\#if directives)
|
||||
|
@ -2,3 +2,9 @@ clang_tablegen(AttrParserStringSwitches.inc -gen-clang-attr-parser-string-switch
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE ../Basic/Attr.td
|
||||
TARGET ClangAttrParserStringSwitches)
|
||||
|
||||
clang_tablegen(AttrSubMatchRulesParserStringSwitches.inc
|
||||
-gen-clang-attr-subject-match-rules-parser-string-switches
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||
SOURCE ../Basic/Attr.td
|
||||
TARGET ClangAttrSubMatchRulesParserStringSwitches)
|
||||
|
@ -184,6 +184,7 @@ class Parser : public CodeCompletionHandler {
|
||||
std::unique_ptr<PragmaHandler> UnrollHintHandler;
|
||||
std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
|
||||
std::unique_ptr<PragmaHandler> FPHandler;
|
||||
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
|
||||
|
||||
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
||||
|
||||
@ -565,6 +566,12 @@ class Parser : public CodeCompletionHandler {
|
||||
/// #pragma clang loop and #pragma unroll.
|
||||
bool HandlePragmaLoopHint(LoopHint &Hint);
|
||||
|
||||
bool ParsePragmaAttributeSubjectMatchRuleSet(
|
||||
attr::ParsedSubjectMatchRuleSet &SubjectMatchRules,
|
||||
SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc);
|
||||
|
||||
void HandlePragmaAttribute();
|
||||
|
||||
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
|
||||
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
|
||||
/// returns the token after Tok, etc.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H
|
||||
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
|
||||
|
||||
#include "clang/Basic/AttrSubjectMatchRules.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
@ -509,9 +510,14 @@ class AttributeList { // TODO: This should really be called ParsedAttribute
|
||||
unsigned getMaxArgs() const;
|
||||
bool hasVariadicArg() const;
|
||||
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
|
||||
bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const;
|
||||
void getMatchRules(const LangOptions &LangOpts,
|
||||
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>>
|
||||
&MatchRules) const;
|
||||
bool diagnoseLangOpts(class Sema &S) const;
|
||||
bool existsInTarget(const TargetInfo &Target) const;
|
||||
bool isKnownToGCC() const;
|
||||
bool isSupportedByPragmaAttribute() const;
|
||||
|
||||
/// \brief If the parsed attribute has a semantic equivalent, and it would
|
||||
/// have a semantic Spelling enumeration (due to having semantically-distinct
|
||||
@ -774,6 +780,8 @@ class ParsedAttributes {
|
||||
void clear() { list = nullptr; pool.clear(); }
|
||||
AttributeList *getList() const { return list; }
|
||||
|
||||
void clearListOnly() { list = nullptr; }
|
||||
|
||||
/// Returns a reference to the attribute list. Try not to introduce
|
||||
/// dependencies on this method, it may not be long-lived.
|
||||
AttributeList *&getListRef() { return list; }
|
||||
|
@ -437,6 +437,20 @@ class Sema {
|
||||
/// VisContext - Manages the stack for \#pragma GCC visibility.
|
||||
void *VisContext; // Really a "PragmaVisStack*"
|
||||
|
||||
/// \brief This represents the stack of attributes that were pushed by
|
||||
/// \#pragma clang attribute.
|
||||
struct PragmaAttributeEntry {
|
||||
SourceLocation Loc;
|
||||
AttributeList *Attribute;
|
||||
SmallVector<attr::SubjectMatchRule, 4> MatchRules;
|
||||
bool IsUsed;
|
||||
};
|
||||
SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack;
|
||||
|
||||
/// \brief The declaration that is currently receiving an attribute from the
|
||||
/// #pragma attribute stack.
|
||||
const Decl *PragmaAttributeCurrentTargetDecl;
|
||||
|
||||
/// \brief This represents the last location of a "#pragma clang optimize off"
|
||||
/// directive if such a directive has not been closed by an "on" yet. If
|
||||
/// optimizations are currently "on", this is set to an invalid location.
|
||||
@ -7206,9 +7220,13 @@ class Sema {
|
||||
PrintInstantiationStack();
|
||||
LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
|
||||
}
|
||||
if (PragmaAttributeCurrentTargetDecl)
|
||||
PrintPragmaAttributeInstantiationPoint();
|
||||
}
|
||||
void PrintInstantiationStack();
|
||||
|
||||
void PrintPragmaAttributeInstantiationPoint();
|
||||
|
||||
/// \brief Determines whether we are currently in a context where
|
||||
/// template argument substitution failures are not considered
|
||||
/// errors.
|
||||
@ -8152,6 +8170,20 @@ class Sema {
|
||||
/// the appropriate attribute.
|
||||
void AddCFAuditedAttribute(Decl *D);
|
||||
|
||||
/// \brief Called on well-formed '\#pragma clang attribute push'.
|
||||
void ActOnPragmaAttributePush(AttributeList &Attribute,
|
||||
SourceLocation PragmaLoc,
|
||||
attr::ParsedSubjectMatchRuleSet Rules);
|
||||
|
||||
/// \brief Called on well-formed '\#pragma clang attribute pop'.
|
||||
void ActOnPragmaAttributePop(SourceLocation PragmaLoc);
|
||||
|
||||
/// \brief Adds the attributes that have been specified using the
|
||||
/// '\#pragma clang attribute push' directives to the given declaration.
|
||||
void AddPragmaAttributes(Scope *S, Decl *D);
|
||||
|
||||
void DiagnoseUnterminatedPragmaAttribute();
|
||||
|
||||
/// \brief Called on well formed \#pragma clang optimize.
|
||||
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
|
||||
|
||||
|
@ -9414,10 +9414,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
|
||||
if (!NodeOrVector.template is<ASTContext::ParentVector *>()) {
|
||||
auto *Vector = new ASTContext::ParentVector(
|
||||
1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
|
||||
if (auto *Node =
|
||||
NodeOrVector
|
||||
.template dyn_cast<ast_type_traits::DynTypedNode *>())
|
||||
delete Node;
|
||||
delete NodeOrVector
|
||||
.template dyn_cast<ast_type_traits::DynTypedNode *>();
|
||||
NodeOrVector = Vector;
|
||||
}
|
||||
|
||||
|
@ -3003,9 +3003,7 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
|
||||
const Attr *FunctionDecl::getUnusedResultAttr() const {
|
||||
QualType RetType = getReturnType();
|
||||
if (RetType->isRecordType()) {
|
||||
const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl();
|
||||
const auto *MD = dyn_cast<CXXMethodDecl>(this);
|
||||
if (Ret && !(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
|
||||
if (const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl()) {
|
||||
if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>())
|
||||
return R;
|
||||
}
|
||||
|
@ -478,6 +478,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
||||
|
||||
if (D->isFunctionTemplateSpecialization())
|
||||
Out << "template<> ";
|
||||
else if (!D->getDescribedFunctionTemplate()) {
|
||||
for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists();
|
||||
I < NumTemplateParams; ++I)
|
||||
printTemplateParameters(D->getTemplateParameterList(I));
|
||||
}
|
||||
|
||||
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
|
||||
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
|
||||
@ -1055,6 +1060,12 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
|
||||
|
||||
void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
|
||||
prettyPrintPragmas(D->getTemplatedDecl());
|
||||
// Print any leading template parameter lists.
|
||||
if (const FunctionDecl *FD = D->getTemplatedDecl()) {
|
||||
for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists();
|
||||
I < NumTemplateParams; ++I)
|
||||
printTemplateParameters(FD->getTemplateParameterList(I));
|
||||
}
|
||||
VisitRedeclarableTemplateDecl(D);
|
||||
|
||||
// Never print "instantiations" for deduction guides (they don't really
|
||||
|
@ -89,25 +89,21 @@ bool IsForwardDeclaration(Decl *D) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CallbackType>
|
||||
void ForEachMatchingDC(
|
||||
const DeclContext *DC,
|
||||
llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
|
||||
std::function<void(const ExternalASTMerger::ImporterPair &IP,
|
||||
Source<const DeclContext *> SourceDC)>
|
||||
Callback) {
|
||||
CallbackType Callback) {
|
||||
for (const ExternalASTMerger::ImporterPair &IP : Importers) {
|
||||
Source<TranslationUnitDecl *> SourceTU(
|
||||
IP.Forward->getFromContext().getTranslationUnitDecl());
|
||||
Source<const DeclContext *> SourceDC =
|
||||
LookupSameContext(SourceTU, DC, *IP.Reverse);
|
||||
if (SourceDC.get()) {
|
||||
Source<TranslationUnitDecl *> SourceTU =
|
||||
IP.Forward->getFromContext().getTranslationUnitDecl();
|
||||
if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse))
|
||||
Callback(IP, SourceDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
|
||||
return std::any_of(Decls.begin(), Decls.end(), [&C](const Candidate &D) {
|
||||
return llvm::any_of(Decls, [&](const Candidate &D) {
|
||||
return C.first.get()->getKind() == D.first.get()->getKind();
|
||||
});
|
||||
}
|
||||
@ -139,15 +135,15 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
|
||||
}
|
||||
};
|
||||
|
||||
ForEachMatchingDC(DC, Importers, [Name, &FilterFoundDecl](
|
||||
const ImporterPair &IP,
|
||||
Source<const DeclContext *> SourceDC) {
|
||||
DeclarationName FromName = IP.Reverse->Import(Name);
|
||||
DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
|
||||
for (NamedDecl *FromD : Result) {
|
||||
FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
|
||||
}
|
||||
});
|
||||
ForEachMatchingDC(
|
||||
DC, Importers,
|
||||
[&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
|
||||
DeclarationName FromName = IP.Reverse->Import(Name);
|
||||
DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
|
||||
for (NamedDecl *FromD : Result) {
|
||||
FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
|
||||
}
|
||||
});
|
||||
|
||||
llvm::ArrayRef<Candidate> DeclsToReport =
|
||||
CompleteDecls.empty() ? ForwardDecls : CompleteDecls;
|
||||
@ -170,15 +166,14 @@ void ExternalASTMerger::FindExternalLexicalDecls(
|
||||
const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
|
||||
SmallVectorImpl<Decl *> &Result) {
|
||||
ForEachMatchingDC(
|
||||
DC, Importers, [DC, IsKindWeWant](const ImporterPair &IP,
|
||||
Source<const DeclContext *> SourceDC) {
|
||||
DC, Importers,
|
||||
[&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
|
||||
for (const Decl *SourceDecl : SourceDC.get()->decls()) {
|
||||
if (IsKindWeWant(SourceDecl->getKind())) {
|
||||
Decl *ImportedDecl =
|
||||
IP.Forward->Import(const_cast<Decl *>(SourceDecl));
|
||||
assert(ImportedDecl->getDeclContext() == DC);
|
||||
(void)ImportedDecl;
|
||||
(void)DC;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1455,10 +1455,12 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
|
||||
Out << 'N';
|
||||
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
|
||||
Qualifiers MethodQuals =
|
||||
Qualifiers::fromCVRMask(Method->getTypeQualifiers());
|
||||
Qualifiers::fromCVRUMask(Method->getTypeQualifiers());
|
||||
// We do not consider restrict a distinguishing attribute for overloading
|
||||
// purposes so we must not mangle it.
|
||||
MethodQuals.removeRestrict();
|
||||
// __unaligned is not currently mangled in any way, so remove it.
|
||||
MethodQuals.removeUnaligned();
|
||||
mangleQualifiers(MethodQuals);
|
||||
mangleRefQualifier(Method->getRefQualifier());
|
||||
}
|
||||
|
@ -147,10 +147,6 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -201,10 +197,6 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -368,10 +360,6 @@ OMPParallelForDirective *OMPParallelForDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -421,10 +409,6 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -759,10 +743,6 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -904,10 +884,6 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -957,10 +933,6 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1009,10 +981,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1095,6 +1063,13 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1153,6 +1128,13 @@ OMPDistributeParallelForSimdDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1200,10 +1182,6 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1256,10 +1234,6 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1352,10 +1326,6 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1407,10 +1377,6 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1474,6 +1440,13 @@ OMPTeamsDistributeParallelForSimdDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1534,6 +1507,13 @@ OMPTeamsDistributeParallelForDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1606,10 +1586,6 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
@ -1676,6 +1652,13 @@ OMPTargetTeamsDistributeParallelForDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1739,6 +1722,13 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create(
|
||||
Dir->setUpdates(Exprs.Updates);
|
||||
Dir->setFinals(Exprs.Finals);
|
||||
Dir->setPreInits(Exprs.PreInits);
|
||||
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
|
||||
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
|
||||
Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
|
||||
Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
|
||||
Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
|
||||
Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
|
||||
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
|
||||
return Dir;
|
||||
}
|
||||
|
||||
@ -1789,10 +1779,6 @@ OMPTargetTeamsDistributeSimdDirective::Create(
|
||||
Dir->setNextLowerBound(Exprs.NLB);
|
||||
Dir->setNextUpperBound(Exprs.NUB);
|
||||
Dir->setNumIterations(Exprs.NumIterations);
|
||||
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
|
||||
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
|
||||
Dir->setDistInc(Exprs.DistInc);
|
||||
Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
|
||||
Dir->setCounters(Exprs.Counters);
|
||||
Dir->setPrivateCounters(Exprs.PrivateCounters);
|
||||
Dir->setInits(Exprs.Inits);
|
||||
|
@ -296,6 +296,7 @@ RegistryMaps::RegistryMaps() {
|
||||
REGISTER_MATCHER(isCatchAll);
|
||||
REGISTER_MATCHER(isClass);
|
||||
REGISTER_MATCHER(isConst);
|
||||
REGISTER_MATCHER(isConstexpr);
|
||||
REGISTER_MATCHER(isConstQualified);
|
||||
REGISTER_MATCHER(isCopyAssignmentOperator);
|
||||
REGISTER_MATCHER(isCopyConstructor);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "clang/Basic/Attributes.h"
|
||||
#include "clang/Basic/AttrSubjectMatchRules.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
using namespace clang;
|
||||
@ -15,3 +16,13 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
|
||||
switch (Rule) {
|
||||
#define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \
|
||||
case attr::NAME: \
|
||||
return SPELLING;
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
}
|
||||
llvm_unreachable("Invalid subject match rule");
|
||||
}
|
||||
|
@ -854,14 +854,10 @@ bool clang::isOpenMPTaskingDirective(OpenMPDirectiveKind Kind) {
|
||||
bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
|
||||
return Kind == OMPD_distribute_parallel_for ||
|
||||
Kind == OMPD_distribute_parallel_for_simd ||
|
||||
Kind == OMPD_distribute_simd || Kind == OMPD_teams_distribute ||
|
||||
Kind == OMPD_teams_distribute_simd ||
|
||||
Kind == OMPD_teams_distribute_parallel_for_simd ||
|
||||
Kind == OMPD_teams_distribute_parallel_for ||
|
||||
Kind == OMPD_target_teams_distribute ||
|
||||
Kind == OMPD_target_teams_distribute_parallel_for ||
|
||||
Kind == OMPD_target_teams_distribute_parallel_for_simd ||
|
||||
Kind == OMPD_target_teams_distribute_simd;
|
||||
Kind == OMPD_target_teams_distribute_parallel_for_simd;
|
||||
}
|
||||
|
||||
void clang::getOpenMPCaptureRegions(
|
||||
|
@ -5467,9 +5467,11 @@ class ARMTargetInfo : public TargetInfo {
|
||||
Builder.defineMacro("__arm__");
|
||||
// For bare-metal none-eabi.
|
||||
if (getTriple().getOS() == llvm::Triple::UnknownOS &&
|
||||
getTriple().getEnvironment() == llvm::Triple::EABI)
|
||||
(getTriple().getEnvironment() == llvm::Triple::EABI ||
|
||||
getTriple().getEnvironment() == llvm::Triple::EABIHF))
|
||||
Builder.defineMacro("__ELF__");
|
||||
|
||||
|
||||
// Target properties.
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
|
||||
@ -6118,6 +6120,11 @@ class AArch64TargetInfo : public TargetInfo {
|
||||
MacroBuilder &Builder) const override {
|
||||
// Target identification.
|
||||
Builder.defineMacro("__aarch64__");
|
||||
// For bare-metal none-eabi.
|
||||
if (getTriple().getOS() == llvm::Triple::UnknownOS &&
|
||||
(getTriple().getEnvironment() == llvm::Triple::EABI ||
|
||||
getTriple().getEnvironment() == llvm::Triple::EABIHF))
|
||||
Builder.defineMacro("__ELF__");
|
||||
|
||||
// Target properties.
|
||||
Builder.defineMacro("_LP64");
|
||||
|
@ -83,9 +83,6 @@ class EmitAssemblyHelper {
|
||||
return TargetIRAnalysis();
|
||||
}
|
||||
|
||||
/// Set LLVM command line options passed through -backend-option.
|
||||
void setCommandLineOpts();
|
||||
|
||||
void CreatePasses(legacy::PassManager &MPM, legacy::FunctionPassManager &FPM);
|
||||
|
||||
/// Generates the TargetMachine.
|
||||
@ -372,7 +369,9 @@ static void initTargetOptions(llvm::TargetOptions &Options,
|
||||
// Set FP fusion mode.
|
||||
switch (LangOpts.getDefaultFPContractMode()) {
|
||||
case LangOptions::FPC_Off:
|
||||
Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
|
||||
// Preserve any contraction performed by the front-end. (Strict performs
|
||||
// splitting of the muladd instrinsic in the backend.)
|
||||
Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
|
||||
break;
|
||||
case LangOptions::FPC_On:
|
||||
Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
|
||||
@ -604,7 +603,7 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
|
||||
PMBuilder.populateModulePassManager(MPM);
|
||||
}
|
||||
|
||||
void EmitAssemblyHelper::setCommandLineOpts() {
|
||||
static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
|
||||
SmallVector<const char *, 16> BackendArgs;
|
||||
BackendArgs.push_back("clang"); // Fake program name.
|
||||
if (!CodeGenOpts.DebugPass.empty()) {
|
||||
@ -677,7 +676,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
|
||||
std::unique_ptr<raw_pwrite_stream> OS) {
|
||||
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
|
||||
|
||||
setCommandLineOpts();
|
||||
setCommandLineOpts(CodeGenOpts);
|
||||
|
||||
bool UsesCodeGen = (Action != Backend_EmitNothing &&
|
||||
Action != Backend_EmitBC &&
|
||||
@ -806,7 +805,7 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
|
||||
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
|
||||
BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
|
||||
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
|
||||
setCommandLineOpts();
|
||||
setCommandLineOpts(CodeGenOpts);
|
||||
|
||||
// The new pass manager always makes a target machine available to passes
|
||||
// during construction.
|
||||
@ -944,6 +943,8 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
|
||||
ModuleToDefinedGVSummaries;
|
||||
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
|
||||
|
||||
setCommandLineOpts(CGOpts);
|
||||
|
||||
// We can simply import the values mentioned in the combined index, since
|
||||
// we should only invoke this using the individual indexes written out
|
||||
// via a WriteIndexesThinBackend.
|
||||
|
@ -1586,9 +1586,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
|
||||
|
||||
case ABIArgInfo::Indirect: {
|
||||
assert(NumIRArgs == 1);
|
||||
// indirect arguments are always on the stack, which is addr space #0.
|
||||
// indirect arguments are always on the stack, which is alloca addr space.
|
||||
llvm::Type *LTy = ConvertTypeForMem(it->type);
|
||||
ArgTypes[FirstIRArg] = LTy->getPointerTo();
|
||||
ArgTypes[FirstIRArg] = LTy->getPointerTo(
|
||||
CGM.getDataLayout().getAllocaAddrSpace());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1761,7 +1762,7 @@ void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) {
|
||||
|
||||
void CodeGenModule::ConstructAttributeList(
|
||||
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
|
||||
AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
|
||||
llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) {
|
||||
llvm::AttrBuilder FuncAttrs;
|
||||
llvm::AttrBuilder RetAttrs;
|
||||
|
||||
@ -1930,13 +1931,8 @@ void CodeGenModule::ConstructAttributeList(
|
||||
RetAttrs.addAttribute(llvm::Attribute::NonNull);
|
||||
}
|
||||
|
||||
// Attach return attributes.
|
||||
if (RetAttrs.hasAttributes()) {
|
||||
PAL.push_back(llvm::AttributeList::get(
|
||||
getLLVMContext(), llvm::AttributeList::ReturnIndex, RetAttrs));
|
||||
}
|
||||
|
||||
bool hasUsedSRet = false;
|
||||
SmallVector<llvm::AttributeSet, 4> ArgAttrs(IRFunctionArgs.totalIRArgs());
|
||||
|
||||
// Attach attributes to sret.
|
||||
if (IRFunctionArgs.hasSRetArg()) {
|
||||
@ -1945,16 +1941,16 @@ void CodeGenModule::ConstructAttributeList(
|
||||
hasUsedSRet = true;
|
||||
if (RetAI.getInReg())
|
||||
SRETAttrs.addAttribute(llvm::Attribute::InReg);
|
||||
PAL.push_back(llvm::AttributeList::get(
|
||||
getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs));
|
||||
ArgAttrs[IRFunctionArgs.getSRetArgNo()] =
|
||||
llvm::AttributeSet::get(getLLVMContext(), SRETAttrs);
|
||||
}
|
||||
|
||||
// Attach attributes to inalloca argument.
|
||||
if (IRFunctionArgs.hasInallocaArg()) {
|
||||
llvm::AttrBuilder Attrs;
|
||||
Attrs.addAttribute(llvm::Attribute::InAlloca);
|
||||
PAL.push_back(llvm::AttributeList::get(
|
||||
getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
|
||||
ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
|
||||
llvm::AttributeSet::get(getLLVMContext(), Attrs);
|
||||
}
|
||||
|
||||
unsigned ArgNo = 0;
|
||||
@ -1967,10 +1963,12 @@ void CodeGenModule::ConstructAttributeList(
|
||||
|
||||
// Add attribute for padding argument, if necessary.
|
||||
if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
|
||||
if (AI.getPaddingInReg())
|
||||
PAL.push_back(llvm::AttributeList::get(
|
||||
getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1,
|
||||
llvm::Attribute::InReg));
|
||||
if (AI.getPaddingInReg()) {
|
||||
ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
|
||||
llvm::AttributeSet::get(
|
||||
getLLVMContext(),
|
||||
llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg));
|
||||
}
|
||||
}
|
||||
|
||||
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
|
||||
@ -2085,15 +2083,15 @@ void CodeGenModule::ConstructAttributeList(
|
||||
unsigned FirstIRArg, NumIRArgs;
|
||||
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
|
||||
for (unsigned i = 0; i < NumIRArgs; i++)
|
||||
PAL.push_back(llvm::AttributeList::get(getLLVMContext(),
|
||||
FirstIRArg + i + 1, Attrs));
|
||||
ArgAttrs[FirstIRArg + i] =
|
||||
llvm::AttributeSet::get(getLLVMContext(), Attrs);
|
||||
}
|
||||
}
|
||||
assert(ArgNo == FI.arg_size());
|
||||
|
||||
if (FuncAttrs.hasAttributes())
|
||||
PAL.push_back(llvm::AttributeList::get(
|
||||
getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs));
|
||||
AttrList = llvm::AttributeList::get(
|
||||
getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs),
|
||||
llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs);
|
||||
}
|
||||
|
||||
/// An argument came in as a promoted argument; demote it back to its
|
||||
@ -2204,8 +2202,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
if (IRFunctionArgs.hasSRetArg()) {
|
||||
auto AI = cast<llvm::Argument>(FnArgs[IRFunctionArgs.getSRetArgNo()]);
|
||||
AI->setName("agg.result");
|
||||
AI->addAttr(llvm::AttributeList::get(getLLVMContext(), AI->getArgNo() + 1,
|
||||
llvm::Attribute::NoAlias));
|
||||
AI->addAttr(llvm::Attribute::NoAlias);
|
||||
}
|
||||
|
||||
// Track if we received the parameter as a pointer (indirect, byval, or
|
||||
@ -2296,9 +2293,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
|
||||
if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
|
||||
PVD->getFunctionScopeIndex()))
|
||||
AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
|
||||
AI->getArgNo() + 1,
|
||||
llvm::Attribute::NonNull));
|
||||
AI->addAttr(llvm::Attribute::NonNull);
|
||||
|
||||
QualType OTy = PVD->getOriginalType();
|
||||
if (const auto *ArrTy =
|
||||
@ -2315,12 +2310,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
llvm::AttrBuilder Attrs;
|
||||
Attrs.addDereferenceableAttr(
|
||||
getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
|
||||
AI->addAttr(llvm::AttributeList::get(
|
||||
getLLVMContext(), AI->getArgNo() + 1, Attrs));
|
||||
AI->addAttrs(Attrs);
|
||||
} else if (getContext().getTargetAddressSpace(ETy) == 0) {
|
||||
AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
|
||||
AI->getArgNo() + 1,
|
||||
llvm::Attribute::NonNull));
|
||||
AI->addAttr(llvm::Attribute::NonNull);
|
||||
}
|
||||
}
|
||||
} else if (const auto *ArrTy =
|
||||
@ -2330,34 +2322,26 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
// we know that it must be nonnull.
|
||||
if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
|
||||
!getContext().getTargetAddressSpace(ArrTy->getElementType()))
|
||||
AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
|
||||
AI->getArgNo() + 1,
|
||||
llvm::Attribute::NonNull));
|
||||
AI->addAttr(llvm::Attribute::NonNull);
|
||||
}
|
||||
|
||||
const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
|
||||
if (!AVAttr)
|
||||
if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
|
||||
AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
|
||||
if (AVAttr) {
|
||||
if (AVAttr) {
|
||||
llvm::Value *AlignmentValue =
|
||||
EmitScalarExpr(AVAttr->getAlignment());
|
||||
llvm::ConstantInt *AlignmentCI =
|
||||
cast<llvm::ConstantInt>(AlignmentValue);
|
||||
unsigned Alignment =
|
||||
std::min((unsigned) AlignmentCI->getZExtValue(),
|
||||
+llvm::Value::MaximumAlignment);
|
||||
|
||||
llvm::AttrBuilder Attrs;
|
||||
Attrs.addAlignmentAttr(Alignment);
|
||||
AI->addAttr(llvm::AttributeList::get(getLLVMContext(),
|
||||
AI->getArgNo() + 1, Attrs));
|
||||
unsigned Alignment = std::min((unsigned)AlignmentCI->getZExtValue(),
|
||||
+llvm::Value::MaximumAlignment);
|
||||
AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
|
||||
}
|
||||
}
|
||||
|
||||
if (Arg->getType().isRestrictQualified())
|
||||
AI->addAttr(llvm::AttributeList::get(
|
||||
getLLVMContext(), AI->getArgNo() + 1, llvm::Attribute::NoAlias));
|
||||
AI->addAttr(llvm::Attribute::NoAlias);
|
||||
|
||||
// LLVM expects swifterror parameters to be used in very restricted
|
||||
// ways. Copy the value into a less-restricted temporary.
|
||||
@ -4113,13 +4097,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
// Compute the calling convention and attributes.
|
||||
unsigned CallingConv;
|
||||
CodeGen::AttributeListType AttributeList;
|
||||
llvm::AttributeList Attrs;
|
||||
CGM.ConstructAttributeList(CalleePtr->getName(), CallInfo,
|
||||
Callee.getAbstractInfo(),
|
||||
AttributeList, CallingConv,
|
||||
Callee.getAbstractInfo(), Attrs, CallingConv,
|
||||
/*AttrOnCallSite=*/true);
|
||||
llvm::AttributeList Attrs =
|
||||
llvm::AttributeList::get(getLLVMContext(), AttributeList);
|
||||
|
||||
// Apply some call-site-specific attributes.
|
||||
// TODO: work this into building the attribute set.
|
||||
|
@ -39,7 +39,6 @@ namespace clang {
|
||||
class VarDecl;
|
||||
|
||||
namespace CodeGen {
|
||||
typedef SmallVector<llvm::AttributeList, 8> AttributeListType;
|
||||
|
||||
/// Abstract information about a function or function prototype.
|
||||
class CGCalleeInfo {
|
||||
|
@ -3466,17 +3466,17 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
|
||||
// functions there won't be an implicit param at arg1 and
|
||||
// otherwise it is 'self' or 'this'.
|
||||
if (isa<ImplicitParamDecl>(VD) && ArgNo && *ArgNo == 1)
|
||||
Flags |= llvm::DINode::FlagObjectPointer;
|
||||
if (auto *Arg = dyn_cast<llvm::Argument>(Storage))
|
||||
if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() &&
|
||||
!VD->getType()->isPointerType())
|
||||
Expr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
Flags |= llvm::DINode::FlagObjectPointer;
|
||||
|
||||
// Note: Older versions of clang used to emit byval references with an extra
|
||||
// DW_OP_deref, because they referenced the IR arg directly instead of
|
||||
// referencing an alloca. Newer versions of LLVM don't treat allocas
|
||||
// differently from other function arguments when used in a dbg.declare.
|
||||
auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
|
||||
|
||||
StringRef Name = VD->getName();
|
||||
if (!Name.empty()) {
|
||||
if (VD->hasAttr<BlocksAttr>()) {
|
||||
// Here, we need an offset *into* the alloca.
|
||||
CharUnits offset = CharUnits::fromQuantity(32);
|
||||
Expr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
// offset of __forwarding field
|
||||
@ -3488,22 +3488,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
|
||||
// offset of x field
|
||||
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
|
||||
Expr.push_back(offset.getQuantity());
|
||||
|
||||
// Create the descriptor for the variable.
|
||||
auto *D = ArgNo
|
||||
? DBuilder.createParameterVariable(Scope, VD->getName(),
|
||||
*ArgNo, Unit, Line, Ty)
|
||||
: DBuilder.createAutoVariable(Scope, VD->getName(), Unit,
|
||||
Line, Ty, Align);
|
||||
|
||||
// Insert an llvm.dbg.declare into the current block.
|
||||
DBuilder.insertDeclare(
|
||||
Storage, D, DBuilder.createExpression(Expr),
|
||||
llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
|
||||
Builder.GetInsertBlock());
|
||||
return;
|
||||
} else if (isa<VariableArrayType>(VD->getType()))
|
||||
Expr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
}
|
||||
} else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) {
|
||||
// If VD is an anonymous union then Storage represents value for
|
||||
// all union fields.
|
||||
@ -3606,8 +3591,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
|
||||
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
|
||||
|
||||
SmallVector<int64_t, 9> addr;
|
||||
if (isa<llvm::AllocaInst>(Storage))
|
||||
addr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
addr.push_back(llvm::dwarf::DW_OP_deref);
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
addr.push_back(offset.getQuantity());
|
||||
if (isByRef) {
|
||||
@ -3633,12 +3617,11 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
|
||||
// Insert an llvm.dbg.declare into the current block.
|
||||
auto DL =
|
||||
llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt);
|
||||
auto *Expr = DBuilder.createExpression(addr);
|
||||
if (InsertPoint)
|
||||
DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
|
||||
InsertPoint);
|
||||
DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint);
|
||||
else
|
||||
DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
|
||||
Builder.GetInsertBlock());
|
||||
DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock());
|
||||
}
|
||||
|
||||
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
|
||||
|
@ -924,7 +924,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
|
||||
return nullptr;
|
||||
|
||||
llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size);
|
||||
Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
|
||||
Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
|
||||
llvm::CallInst *C =
|
||||
Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr});
|
||||
C->setDoesNotThrow();
|
||||
@ -932,7 +932,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
|
||||
Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
|
||||
Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
|
||||
llvm::CallInst *C =
|
||||
Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr});
|
||||
C->setDoesNotThrow();
|
||||
@ -1728,7 +1728,7 @@ llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
|
||||
if (LifetimeStartFn)
|
||||
return LifetimeStartFn;
|
||||
LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
|
||||
llvm::Intrinsic::lifetime_start, Int8PtrTy);
|
||||
llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy);
|
||||
return LifetimeStartFn;
|
||||
}
|
||||
|
||||
@ -1737,7 +1737,7 @@ llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
|
||||
if (LifetimeEndFn)
|
||||
return LifetimeEndFn;
|
||||
LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
|
||||
llvm::Intrinsic::lifetime_end, Int8PtrTy);
|
||||
llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy);
|
||||
return LifetimeEndFn;
|
||||
}
|
||||
|
||||
|
@ -533,6 +533,15 @@ bool CodeGenFunction::sanitizePerformTypeCheck() const {
|
||||
SanOpts.has(SanitizerKind::Vptr);
|
||||
}
|
||||
|
||||
/// Check if a runtime null check for \p Ptr can be omitted.
|
||||
static bool canOmitPointerNullCheck(llvm::Value *Ptr) {
|
||||
// Note: do not perform any constant-folding in this function. That is best
|
||||
// left to the IR builder.
|
||||
|
||||
// Pointers to alloca'd memory are non-null.
|
||||
return isa<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
|
||||
llvm::Value *Ptr, QualType Ty,
|
||||
CharUnits Alignment,
|
||||
@ -554,19 +563,28 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
|
||||
bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
|
||||
TCK == TCK_UpcastToVirtualBase;
|
||||
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
|
||||
!SkippedChecks.has(SanitizerKind::Null)) {
|
||||
!SkippedChecks.has(SanitizerKind::Null) &&
|
||||
!canOmitPointerNullCheck(Ptr)) {
|
||||
// The glvalue must not be an empty glvalue.
|
||||
llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr);
|
||||
|
||||
if (AllowNullPointers) {
|
||||
// When performing pointer casts, it's OK if the value is null.
|
||||
// Skip the remaining checks in that case.
|
||||
Done = createBasicBlock("null");
|
||||
llvm::BasicBlock *Rest = createBasicBlock("not.null");
|
||||
Builder.CreateCondBr(IsNonNull, Rest, Done);
|
||||
EmitBlock(Rest);
|
||||
} else {
|
||||
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
|
||||
// The IR builder can constant-fold the null check if the pointer points to
|
||||
// a constant.
|
||||
bool PtrIsNonNull =
|
||||
IsNonNull == llvm::ConstantInt::getTrue(getLLVMContext());
|
||||
|
||||
// Skip the null check if the pointer is known to be non-null.
|
||||
if (!PtrIsNonNull) {
|
||||
if (AllowNullPointers) {
|
||||
// When performing pointer casts, it's OK if the value is null.
|
||||
// Skip the remaining checks in that case.
|
||||
Done = createBasicBlock("null");
|
||||
llvm::BasicBlock *Rest = createBasicBlock("not.null");
|
||||
Builder.CreateCondBr(IsNonNull, Rest, Done);
|
||||
EmitBlock(Rest);
|
||||
} else {
|
||||
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
|
||||
unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
|
||||
|
||||
if (CGM.getDataLayout().isBigEndian()) {
|
||||
Tmp = Tmp.lshr(NewFieldWidth);
|
||||
Tmp.lshrInPlace(NewFieldWidth);
|
||||
Tmp = Tmp.trunc(BitsInPreviousByte);
|
||||
|
||||
// We want the remaining high bits.
|
||||
@ -210,7 +210,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
|
||||
Tmp = Tmp.trunc(BitsInPreviousByte);
|
||||
|
||||
// We want the remaining low bits.
|
||||
FieldValue = FieldValue.lshr(BitsInPreviousByte);
|
||||
FieldValue.lshrInPlace(BitsInPreviousByte);
|
||||
FieldValue = FieldValue.trunc(NewFieldWidth);
|
||||
}
|
||||
}
|
||||
@ -273,7 +273,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
|
||||
// We want the low bits.
|
||||
Tmp = FieldValue.trunc(CharWidth);
|
||||
|
||||
FieldValue = FieldValue.lshr(CharWidth);
|
||||
FieldValue.lshrInPlace(CharWidth);
|
||||
}
|
||||
|
||||
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
|
||||
|
@ -126,10 +126,12 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
|
||||
QualType IdTy(CGM.getContext().getObjCIdType());
|
||||
llvm::Constant *Constant =
|
||||
CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
|
||||
Address Addr(Constant, Context.getTypeAlignInChars(IdTy));
|
||||
LValue LV = MakeAddrLValue(Addr, IdTy);
|
||||
return Builder.CreateBitCast(EmitLoadOfScalar(LV, E->getLocStart()),
|
||||
ConvertType(E->getType()));
|
||||
LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
|
||||
llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getLocStart());
|
||||
cast<llvm::LoadInst>(Ptr)->setMetadata(
|
||||
CGM.getModule().getMDKindID("invariant.load"),
|
||||
llvm::MDNode::get(getLLVMContext(), None));
|
||||
return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
|
||||
}
|
||||
|
||||
// Compute the type of the array we're initializing.
|
||||
@ -1848,12 +1850,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
|
||||
F->addFnAttr(llvm::Attribute::NonLazyBind);
|
||||
}
|
||||
|
||||
if (IsForwarding(Name)) {
|
||||
llvm::AttrBuilder B;
|
||||
B.addAttribute(llvm::Attribute::Returned);
|
||||
|
||||
F->arg_begin()->addAttr(llvm::AttributeList::get(F->getContext(), 1, B));
|
||||
}
|
||||
if (IsForwarding(Name))
|
||||
F->arg_begin()->addAttr(llvm::Attribute::Returned);
|
||||
}
|
||||
|
||||
return RTF;
|
||||
|
@ -1166,7 +1166,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
|
||||
if (Rem)
|
||||
Rem--;
|
||||
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
|
||||
LHS++;
|
||||
++LHS;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -379,12 +379,9 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
|
||||
|
||||
// Apply the standard set of call attributes.
|
||||
unsigned CallingConv;
|
||||
CodeGen::AttributeListType AttributeList;
|
||||
CGM.ConstructAttributeList(CalleePtr->getName(),
|
||||
*CurFnInfo, MD, AttributeList,
|
||||
llvm::AttributeList Attrs;
|
||||
CGM.ConstructAttributeList(CalleePtr->getName(), *CurFnInfo, MD, Attrs,
|
||||
CallingConv, /*AttrOnCallSite=*/true);
|
||||
llvm::AttributeList Attrs =
|
||||
llvm::AttributeList::get(getLLVMContext(), AttributeList);
|
||||
Call->setAttributes(Attrs);
|
||||
Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
|
||||
|
||||
|
@ -111,6 +111,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
|
||||
C.getTargetInfo().getMaxPointerWidth());
|
||||
Int8PtrTy = Int8Ty->getPointerTo(0);
|
||||
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
|
||||
AllocaInt8PtrTy = Int8Ty->getPointerTo(
|
||||
M.getDataLayout().getAllocaAddrSpace());
|
||||
|
||||
RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
|
||||
BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC();
|
||||
@ -839,10 +841,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
|
||||
const CGFunctionInfo &Info,
|
||||
llvm::Function *F) {
|
||||
unsigned CallingConv;
|
||||
AttributeListType AttributeList;
|
||||
ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
|
||||
false);
|
||||
F->setAttributes(llvm::AttributeList::get(getLLVMContext(), AttributeList));
|
||||
llvm::AttributeList PAL;
|
||||
ConstructAttributeList(F->getName(), Info, D, PAL, CallingConv, false);
|
||||
F->setAttributes(PAL);
|
||||
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
|
||||
}
|
||||
|
||||
@ -3793,6 +3794,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
|
||||
AddDeferredUnusedCoverageMapping(D);
|
||||
break;
|
||||
|
||||
case Decl::CXXDeductionGuide:
|
||||
// Function-like, but does not result in code emission.
|
||||
break;
|
||||
|
||||
case Decl::Var:
|
||||
case Decl::Decomposition:
|
||||
// Skip variable templates
|
||||
|
@ -1020,11 +1020,12 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// \param CalleeInfo - The callee information these attributes are being
|
||||
/// constructed for. If valid, the attributes applied to this decl may
|
||||
/// contribute to the function attributes and calling convention.
|
||||
/// \param PAL [out] - On return, the attribute list to use.
|
||||
/// \param Attrs [out] - On return, the attribute list to use.
|
||||
/// \param CallingConv [out] - On return, the LLVM calling convention to use.
|
||||
void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
|
||||
CGCalleeInfo CalleeInfo, AttributeListType &PAL,
|
||||
unsigned &CallingConv, bool AttrOnCallSite);
|
||||
CGCalleeInfo CalleeInfo,
|
||||
llvm::AttributeList &Attrs, unsigned &CallingConv,
|
||||
bool AttrOnCallSite);
|
||||
|
||||
/// Adds attributes to F according to our CodeGenOptions and LangOptions, as
|
||||
/// though we had emitted it ourselves. We remove any attributes on F that
|
||||
|
@ -60,6 +60,12 @@ struct CodeGenTypeCache {
|
||||
llvm::PointerType *Int8PtrPtrTy;
|
||||
};
|
||||
|
||||
/// void* in alloca address space
|
||||
union {
|
||||
llvm::PointerType *AllocaVoidPtrTy;
|
||||
llvm::PointerType *AllocaInt8PtrTy;
|
||||
};
|
||||
|
||||
/// The size and alignment of the builtin C type 'int'. This comes
|
||||
/// up enough in various ABI lowering tasks to be worth pre-computing.
|
||||
union {
|
||||
|
@ -197,7 +197,7 @@ namespace {
|
||||
// Provide some coverage mapping even for methods that aren't emitted.
|
||||
// Don't do this for templated classes though, as they may not be
|
||||
// instantiable.
|
||||
if (!MD->getParent()->getDescribedClassTemplate())
|
||||
if (!MD->getParent()->isDependentContext())
|
||||
Builder->AddDeferredUnusedCoverageMapping(MD);
|
||||
}
|
||||
|
||||
|
@ -469,34 +469,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
||||
int LegacySanitizeCoverage;
|
||||
if (Arg->getNumValues() == 1 &&
|
||||
!StringRef(Arg->getValue(0))
|
||||
.getAsInteger(0, LegacySanitizeCoverage) &&
|
||||
LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
|
||||
switch (LegacySanitizeCoverage) {
|
||||
case 0:
|
||||
CoverageFeatures = 0;
|
||||
Arg->claim();
|
||||
break;
|
||||
case 1:
|
||||
D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
|
||||
<< "-fsanitize-coverage=func";
|
||||
CoverageFeatures = CoverageFunc;
|
||||
break;
|
||||
case 2:
|
||||
D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
|
||||
<< "-fsanitize-coverage=bb";
|
||||
CoverageFeatures = CoverageBB;
|
||||
break;
|
||||
case 3:
|
||||
D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
|
||||
<< "-fsanitize-coverage=edge";
|
||||
CoverageFeatures = CoverageEdge;
|
||||
break;
|
||||
case 4:
|
||||
.getAsInteger(0, LegacySanitizeCoverage)) {
|
||||
CoverageFeatures = 0;
|
||||
Arg->claim();
|
||||
if (LegacySanitizeCoverage != 0) {
|
||||
D.Diag(diag::warn_drv_deprecated_arg)
|
||||
<< Arg->getAsString(Args)
|
||||
<< "-fsanitize-coverage=edge,indirect-calls";
|
||||
CoverageFeatures = CoverageEdge | CoverageIndirCall;
|
||||
break;
|
||||
<< Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -530,16 +508,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
||||
// Basic block tracing and 8-bit counters require some type of coverage
|
||||
// enabled.
|
||||
int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
|
||||
if ((CoverageFeatures & CoverageTraceBB) &&
|
||||
!(CoverageFeatures & CoverageTypes))
|
||||
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
||||
if (CoverageFeatures & CoverageTraceBB)
|
||||
D.Diag(clang::diag::warn_drv_deprecated_arg)
|
||||
<< "-fsanitize-coverage=trace-bb"
|
||||
<< "-fsanitize-coverage=(func|bb|edge)";
|
||||
if ((CoverageFeatures & Coverage8bitCounters) &&
|
||||
!(CoverageFeatures & CoverageTypes))
|
||||
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
||||
<< "-fsanitize-coverage=trace-pc-guard";
|
||||
if (CoverageFeatures & Coverage8bitCounters)
|
||||
D.Diag(clang::diag::warn_drv_deprecated_arg)
|
||||
<< "-fsanitize-coverage=8bit-counters"
|
||||
<< "-fsanitize-coverage=(func|bb|edge)";
|
||||
<< "-fsanitize-coverage=trace-pc-guard";
|
||||
// trace-pc w/o func/bb/edge implies edge.
|
||||
if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) &&
|
||||
!(CoverageFeatures & CoverageTypes))
|
||||
|
@ -649,8 +649,24 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
|
||||
CmdArgs.push_back("-x");
|
||||
if (Args.hasArg(options::OPT_rewrite_objc))
|
||||
CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
|
||||
else
|
||||
CmdArgs.push_back(types::getTypeName(Input.getType()));
|
||||
else {
|
||||
// Map the driver type to the frontend type. This is mostly an identity
|
||||
// mapping, except that the distinction between module interface units
|
||||
// and other source files does not exist at the frontend layer.
|
||||
const char *ClangType;
|
||||
switch (Input.getType()) {
|
||||
case types::TY_CXXModule:
|
||||
ClangType = "c++";
|
||||
break;
|
||||
case types::TY_PP_CXXModule:
|
||||
ClangType = "c++-cpp-output";
|
||||
break;
|
||||
default:
|
||||
ClangType = types::getTypeName(Input.getType());
|
||||
break;
|
||||
}
|
||||
CmdArgs.push_back(ClangType);
|
||||
}
|
||||
}
|
||||
|
||||
static void appendUserToPath(SmallVectorImpl<char> &Result) {
|
||||
@ -2290,6 +2306,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
|
||||
true))
|
||||
CmdArgs.push_back("-fno-strict-return");
|
||||
if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
|
||||
options::OPT_fno_allow_editor_placeholders, false))
|
||||
CmdArgs.push_back("-fallow-editor-placeholders");
|
||||
if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
|
||||
options::OPT_fno_strict_vtable_pointers,
|
||||
false))
|
||||
@ -4996,6 +5015,19 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
case llvm::Triple::x86_64:
|
||||
AddX86TargetArgs(Args, CmdArgs);
|
||||
break;
|
||||
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::armeb:
|
||||
case llvm::Triple::thumb:
|
||||
case llvm::Triple::thumbeb:
|
||||
// This isn't in AddARMTargetArgs because we want to do this for assembly
|
||||
// only, not C/C++.
|
||||
if (Args.hasFlag(options::OPT_mdefault_build_attributes,
|
||||
options::OPT_mno_default_build_attributes, true)) {
|
||||
CmdArgs.push_back("-mllvm");
|
||||
CmdArgs.push_back("-arm-add-build-attributes");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Consume all the warning flags. Usually this would be handled more
|
||||
|
@ -261,6 +261,12 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
|
||||
arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs);
|
||||
return arm::getARMTargetCPU(MCPU, MArch, T);
|
||||
}
|
||||
|
||||
case llvm::Triple::avr:
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ))
|
||||
return A->getValue();
|
||||
return "";
|
||||
|
||||
case llvm::Triple::mips:
|
||||
case llvm::Triple::mipsel:
|
||||
case llvm::Triple::mips64:
|
||||
@ -426,11 +432,12 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
|
||||
}
|
||||
}
|
||||
|
||||
void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
const ArgList &Args) {
|
||||
bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
const ArgList &Args, bool IsOffloadingHost,
|
||||
bool GompNeedsRT) {
|
||||
if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
options::OPT_fno_openmp, false))
|
||||
return;
|
||||
return false;
|
||||
|
||||
switch (TC.getDriver().getOpenMPRuntime(Args)) {
|
||||
case Driver::OMPRT_OMP:
|
||||
@ -438,16 +445,24 @@ void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
break;
|
||||
case Driver::OMPRT_GOMP:
|
||||
CmdArgs.push_back("-lgomp");
|
||||
|
||||
if (GompNeedsRT)
|
||||
CmdArgs.push_back("-lrt");
|
||||
break;
|
||||
case Driver::OMPRT_IOMP5:
|
||||
CmdArgs.push_back("-liomp5");
|
||||
break;
|
||||
case Driver::OMPRT_Unknown:
|
||||
// Already diagnosed.
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsOffloadingHost)
|
||||
CmdArgs.push_back("-lomptarget");
|
||||
|
||||
addArchSpecificRPath(TC, Args, CmdArgs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
|
||||
|
@ -59,8 +59,10 @@ void AddAssemblerKPIC(const ToolChain &ToolChain,
|
||||
|
||||
void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs);
|
||||
void addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
const llvm::opt::ArgList &Args);
|
||||
/// Returns true, if an OpenMP runtime has been added.
|
||||
bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
const llvm::opt::ArgList &Args,
|
||||
bool IsOffloadingHost = false, bool GompNeedsRT = false);
|
||||
|
||||
llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
|
||||
llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args);
|
||||
|
@ -586,37 +586,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
|
||||
Args.hasArg(options::OPT_pthreads);
|
||||
|
||||
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
options::OPT_fno_openmp, false)) {
|
||||
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
|
||||
// require librt. Most modern Linux platforms do, but some may not.
|
||||
if (addOpenMPRuntime(CmdArgs, ToolChain, Args,
|
||||
JA.isHostOffloading(Action::OFK_OpenMP),
|
||||
/* GompNeedsRT= */ true))
|
||||
// OpenMP runtimes implies pthreads when using the GNU toolchain.
|
||||
// FIXME: Does this really make sense for all GNU toolchains?
|
||||
WantPthread = true;
|
||||
|
||||
// Also link the particular OpenMP runtimes.
|
||||
switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
|
||||
case Driver::OMPRT_OMP:
|
||||
CmdArgs.push_back("-lomp");
|
||||
break;
|
||||
case Driver::OMPRT_GOMP:
|
||||
CmdArgs.push_back("-lgomp");
|
||||
|
||||
// FIXME: Exclude this for platforms with libgomp that don't require
|
||||
// librt. Most modern Linux platforms require it, but some may not.
|
||||
CmdArgs.push_back("-lrt");
|
||||
break;
|
||||
case Driver::OMPRT_IOMP5:
|
||||
CmdArgs.push_back("-liomp5");
|
||||
break;
|
||||
case Driver::OMPRT_Unknown:
|
||||
// Already diagnosed.
|
||||
break;
|
||||
}
|
||||
if (JA.isHostOffloading(Action::OFK_OpenMP))
|
||||
CmdArgs.push_back("-lomptarget");
|
||||
|
||||
addArchSpecificRPath(ToolChain, Args, CmdArgs);
|
||||
}
|
||||
|
||||
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
|
||||
|
||||
if (WantPthread && !isAndroid)
|
||||
@ -770,6 +748,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
|
||||
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::aarch64_be: {
|
||||
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::mips:
|
||||
case llvm::Triple::mipsel:
|
||||
case llvm::Triple::mips64:
|
||||
|
@ -285,28 +285,30 @@ void toolchains::MinGW::findGccLibDir() {
|
||||
}
|
||||
}
|
||||
|
||||
llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() {
|
||||
llvm::SmallVector<llvm::SmallString<32>, 2> Gccs;
|
||||
Gccs.emplace_back(getTriple().getArchName());
|
||||
Gccs[0] += "-w64-mingw32-gcc";
|
||||
Gccs.emplace_back("mingw32-gcc");
|
||||
// Please do not add "gcc" here
|
||||
for (StringRef CandidateGcc : Gccs)
|
||||
if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc))
|
||||
return GPPName;
|
||||
return make_error_code(std::errc::no_such_file_or_directory);
|
||||
}
|
||||
|
||||
toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
|
||||
const ArgList &Args)
|
||||
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
|
||||
getProgramPaths().push_back(getDriver().getInstalledDir());
|
||||
|
||||
// In Windows there aren't any standard install locations, we search
|
||||
// for gcc on the PATH. In Linux the base is always /usr.
|
||||
#ifdef LLVM_ON_WIN32
|
||||
if (getDriver().SysRoot.size())
|
||||
Base = getDriver().SysRoot;
|
||||
else if (llvm::ErrorOr<std::string> GPPName =
|
||||
llvm::sys::findProgramByName("gcc"))
|
||||
else if (llvm::ErrorOr<std::string> GPPName = findGcc())
|
||||
Base = llvm::sys::path::parent_path(
|
||||
llvm::sys::path::parent_path(GPPName.get()));
|
||||
else
|
||||
Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
|
||||
#else
|
||||
if (getDriver().SysRoot.size())
|
||||
Base = getDriver().SysRoot;
|
||||
else
|
||||
Base = "/usr";
|
||||
#endif
|
||||
|
||||
Base += llvm::sys::path::get_separator();
|
||||
findGccLibDir();
|
||||
|
@ -93,6 +93,7 @@ class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain {
|
||||
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
|
||||
mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
|
||||
void findGccLibDir();
|
||||
llvm::ErrorOr<std::string> findGcc();
|
||||
};
|
||||
|
||||
} // end namespace toolchains
|
||||
|
@ -467,6 +467,9 @@ FormatToken *FormatTokenLexer::getNextToken() {
|
||||
if (pos >= 0 && Text[pos] == '\r')
|
||||
--pos;
|
||||
// See whether there is an odd number of '\' before this.
|
||||
// FIXME: This is wrong. A '\' followed by a newline is always removed,
|
||||
// regardless of whether there is another '\' before it.
|
||||
// FIXME: Newlines can also be escaped by a '?' '?' '/' trigraph.
|
||||
unsigned count = 0;
|
||||
for (; pos >= 0; --pos, ++count)
|
||||
if (Text[pos] != '\\')
|
||||
|
@ -796,10 +796,11 @@ class AnnotatingParser {
|
||||
while (CurrentToken) {
|
||||
FormatToken *Tok = CurrentToken;
|
||||
next();
|
||||
if (Tok->isOneOf(Keywords.kw___has_include,
|
||||
Keywords.kw___has_include_next)) {
|
||||
if (Tok->is(tok::l_paren))
|
||||
parseParens();
|
||||
else if (Tok->isOneOf(Keywords.kw___has_include,
|
||||
Keywords.kw___has_include_next))
|
||||
parseHasInclude();
|
||||
}
|
||||
}
|
||||
return Type;
|
||||
}
|
||||
|
@ -1353,13 +1353,11 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||
.Case("cl", IK_OpenCL)
|
||||
.Case("cuda", IK_CUDA)
|
||||
.Case("c++", IK_CXX)
|
||||
.Case("c++-module", IK_CXX)
|
||||
.Case("objective-c", IK_ObjC)
|
||||
.Case("objective-c++", IK_ObjCXX)
|
||||
.Case("cpp-output", IK_PreprocessedC)
|
||||
.Case("assembler-with-cpp", IK_Asm)
|
||||
.Case("c++-cpp-output", IK_PreprocessedCXX)
|
||||
.Case("c++-module-cpp-output", IK_PreprocessedCXX)
|
||||
.Case("cuda-cpp-output", IK_PreprocessedCuda)
|
||||
.Case("objective-c-cpp-output", IK_PreprocessedObjC)
|
||||
.Case("objc-cpp-output", IK_PreprocessedObjC)
|
||||
@ -2324,6 +2322,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
||||
Args.getAllArgValues(OPT_fxray_always_instrument);
|
||||
Opts.XRayNeverInstrumentFiles =
|
||||
Args.getAllArgValues(OPT_fxray_never_instrument);
|
||||
|
||||
// -fallow-editor-placeholders
|
||||
Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
|
||||
}
|
||||
|
||||
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
||||
|
@ -56,8 +56,7 @@
|
||||
/// __m128 _mm_ceil_ps(__m128 X);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float] values to be rounded up.
|
||||
@ -74,8 +73,7 @@
|
||||
/// __m128d _mm_ceil_pd(__m128d X);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double] values to be rounded up.
|
||||
@ -94,8 +92,7 @@
|
||||
/// __m128 _mm_ceil_ss(__m128 X, __m128 Y);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
|
||||
@ -120,8 +117,7 @@
|
||||
/// __m128d _mm_ceil_sd(__m128d X, __m128d Y);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
|
||||
@ -144,8 +140,7 @@
|
||||
/// __m128 _mm_floor_ps(__m128 X);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float] values to be rounded down.
|
||||
@ -162,8 +157,7 @@
|
||||
/// __m128d _mm_floor_pd(__m128d X);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double].
|
||||
@ -182,8 +176,7 @@
|
||||
/// __m128 _mm_floor_ss(__m128 X, __m128 Y);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
|
||||
@ -208,8 +201,7 @@
|
||||
/// __m128d _mm_floor_sd(__m128d X, __m128d Y);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
|
||||
@ -233,8 +225,7 @@
|
||||
/// __m128 _mm_round_ps(__m128 X, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float].
|
||||
@ -269,8 +260,7 @@
|
||||
/// __m128 _mm_round_ss(__m128 X, __m128 Y, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
|
||||
@ -310,8 +300,7 @@
|
||||
/// __m128d _mm_round_pd(__m128d X, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double].
|
||||
@ -333,7 +322,6 @@
|
||||
#define _mm_round_pd(X, M) __extension__ ({ \
|
||||
(__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M)); })
|
||||
|
||||
|
||||
/// \brief Copies the upper element of the first 128-bit vector operand to the
|
||||
/// corresponding upper element of the 128-bit result vector of [2 x double].
|
||||
/// Rounds the lower element of the second 128-bit vector operand to an
|
||||
@ -347,8 +335,7 @@
|
||||
/// __m128d _mm_round_sd(__m128d X, __m128d Y, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
|
||||
@ -388,8 +375,7 @@
|
||||
/// __m128d _mm_blend_pd(__m128d V1, __m128d V2, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VBLENDPD / BLENDPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction.
|
||||
///
|
||||
/// \param V1
|
||||
/// A 128-bit vector of [2 x double].
|
||||
@ -419,8 +405,7 @@
|
||||
/// __m128 _mm_blend_ps(__m128 V1, __m128 V2, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VBLENDPS / BLENDPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VBLENDPS / BLENDPS </c> instruction.
|
||||
///
|
||||
/// \param V1
|
||||
/// A 128-bit vector of [4 x float].
|
||||
@ -447,8 +432,7 @@
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VBLENDVPD / BLENDVPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VBLENDVPD / BLENDVPD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [2 x double].
|
||||
@ -475,8 +459,7 @@ _mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VBLENDVPS / BLENDVPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VBLENDVPS / BLENDVPS </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x float].
|
||||
@ -503,8 +486,7 @@ _mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPBLENDVB / PBLENDVB </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPBLENDVB / PBLENDVB </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [16 x i8].
|
||||
@ -535,8 +517,7 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
|
||||
/// __m128i _mm_blend_epi16(__m128i V1, __m128i V2, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPBLENDW / PBLENDW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPBLENDW / PBLENDW </c> instruction.
|
||||
///
|
||||
/// \param V1
|
||||
/// A 128-bit vector of [8 x i16].
|
||||
@ -569,8 +550,7 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMULLD / PMULLD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMULLD / PMULLD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit integer vector.
|
||||
@ -589,8 +569,7 @@ _mm_mullo_epi32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMULDQ / PMULDQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMULDQ / PMULDQ </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x i32].
|
||||
@ -617,8 +596,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128 _mm_dp_ps(__m128 X, __m128 Y, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VDPPS / DPPS </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VDPPS / DPPS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [4 x float].
|
||||
@ -652,8 +630,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128d _mm_dp_pd(__m128d X, __m128d Y, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VDPPD / DPPD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VDPPD / DPPD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [2 x double].
|
||||
@ -680,8 +657,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VMOVNTDQA / MOVNTDQA </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VMOVNTDQA / MOVNTDQA </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A pointer to a 128-bit aligned memory location that contains the integer
|
||||
@ -701,8 +677,7 @@ _mm_stream_load_si128 (__m128i const *__V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMINSB / PMINSB </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMINSB / PMINSB </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [16 x i8].
|
||||
@ -721,8 +696,7 @@ _mm_min_epi8 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMAXSB / PMAXSB </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMAXSB / PMAXSB </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [16 x i8].
|
||||
@ -741,8 +715,7 @@ _mm_max_epi8 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMINUW / PMINUW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMINUW / PMINUW </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [8 x u16].
|
||||
@ -761,8 +734,7 @@ _mm_min_epu16 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMAXUW / PMAXUW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMAXUW / PMAXUW </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [8 x u16].
|
||||
@ -781,8 +753,7 @@ _mm_max_epu16 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMINSD / PMINSD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMINSD / PMINSD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x i32].
|
||||
@ -801,8 +772,7 @@ _mm_min_epi32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMAXSD / PMAXSD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMAXSD / PMAXSD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x i32].
|
||||
@ -821,8 +791,7 @@ _mm_max_epi32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMINUD / PMINUD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMINUD / PMINUD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x u32].
|
||||
@ -841,8 +810,7 @@ _mm_min_epu32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMAXUD / PMAXUD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMAXUD / PMAXUD </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x u32].
|
||||
@ -867,7 +835,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128 _mm_insert_ps(__m128 X, __m128 Y, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VINSERTPS </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> VINSERTPS </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector source operand of [4 x float]. With the exception of
|
||||
@ -907,7 +875,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// int _mm_extract_ps(__m128 X, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VEXTRACTPS / EXTRACTPS </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VEXTRACTPS / EXTRACTPS </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param X
|
||||
@ -951,8 +919,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128i _mm_insert_epi8(__m128i X, int I, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPINSRB / PINSRB </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPINSRB / PINSRB </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector of [16 x i8]. This vector is copied to the
|
||||
@ -997,8 +964,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128i _mm_insert_epi32(__m128i X, int I, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPINSRD / PINSRD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPINSRD / PINSRD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector of [4 x i32]. This vector is copied to the
|
||||
@ -1009,7 +975,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// specified by \a N.
|
||||
/// \param N
|
||||
/// An immediate value. Bits [1:0] specify the bit offset in the result at
|
||||
/// which the integer \a I is written.
|
||||
/// which the integer \a I is written. \n
|
||||
/// 00: Bits [31:0] of the result are used for insertion. \n
|
||||
/// 01: Bits [63:32] of the result are used for insertion. \n
|
||||
/// 10: Bits [95:64] of the result are used for insertion. \n
|
||||
@ -1019,6 +985,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
({ __v4si __a = (__v4si)(__m128i)(X); \
|
||||
__a[(N) & 3] = (I); \
|
||||
(__m128i)__a;}))
|
||||
|
||||
#ifdef __x86_64__
|
||||
/// \brief Constructs a 128-bit vector of [2 x i64] by first making a copy of
|
||||
/// the 128-bit integer vector parameter, and then inserting the 64-bit
|
||||
@ -1031,8 +998,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// __m128i _mm_insert_epi64(__m128i X, long long I, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPINSRQ / PINSRQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPINSRQ / PINSRQ </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector of [2 x i64]. This vector is copied to the
|
||||
@ -1043,7 +1009,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// specified by \a N.
|
||||
/// \param N
|
||||
/// An immediate value. Bit [0] specifies the bit offset in the result at
|
||||
/// which the integer \a I is written.
|
||||
/// which the integer \a I is written. \n
|
||||
/// 0: Bits [63:0] of the result are used for insertion. \n
|
||||
/// 1: Bits [127:64] of the result are used for insertion. \n
|
||||
/// \returns A 128-bit integer vector containing the constructed values.
|
||||
@ -1065,14 +1031,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// int _mm_extract_epi8(__m128i X, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPEXTRB / PEXTRB </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPEXTRB / PEXTRB </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector.
|
||||
/// \param N
|
||||
/// An immediate value. Bits [3:0] specify which 8-bit vector element
|
||||
/// from the argument \a X to extract and copy to the result. \n
|
||||
/// An immediate value. Bits [3:0] specify which 8-bit vector element from
|
||||
/// the argument \a X to extract and copy to the result. \n
|
||||
/// 0000: Bits [7:0] of parameter \a X are extracted. \n
|
||||
/// 0001: Bits [15:8] of the parameter \a X are extracted. \n
|
||||
/// 0010: Bits [23:16] of the parameter \a X are extracted. \n
|
||||
@ -1105,14 +1070,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// int _mm_extract_epi32(__m128i X, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPEXTRD / PEXTRD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPEXTRD / PEXTRD </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector.
|
||||
/// \param N
|
||||
/// An immediate value. Bits [1:0] specify which 32-bit vector element
|
||||
/// from the argument \a X to extract and copy to the result. \n
|
||||
/// An immediate value. Bits [1:0] specify which 32-bit vector element from
|
||||
/// the argument \a X to extract and copy to the result. \n
|
||||
/// 00: Bits [31:0] of the parameter \a X are extracted. \n
|
||||
/// 01: Bits [63:32] of the parameter \a X are extracted. \n
|
||||
/// 10: Bits [95:64] of the parameter \a X are extracted. \n
|
||||
@ -1122,6 +1086,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
#define _mm_extract_epi32(X, N) (__extension__ \
|
||||
({ __v4si __a = (__v4si)(__m128i)(X); \
|
||||
(int)__a[(N) & 3];}))
|
||||
|
||||
#ifdef __x86_64__
|
||||
/// \brief Extracts a 64-bit element from the 128-bit integer vector of
|
||||
/// [2 x i64], using the immediate value parameter \a N as a selector.
|
||||
@ -1132,14 +1097,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
/// long long _mm_extract_epi64(__m128i X, const int N);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPEXTRQ / PEXTRQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPEXTRQ / PEXTRQ </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit integer vector.
|
||||
/// \param N
|
||||
/// An immediate value. Bit [0] specifies which 64-bit vector element
|
||||
/// from the argument \a X to return. \n
|
||||
/// An immediate value. Bit [0] specifies which 64-bit vector element from
|
||||
/// the argument \a X to return. \n
|
||||
/// 0: Bits [63:0] are returned. \n
|
||||
/// 1: Bits [127:64] are returned. \n
|
||||
/// \returns A 64-bit integer.
|
||||
@ -1154,8 +1118,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param __M
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1173,8 +1136,7 @@ _mm_testz_si128(__m128i __M, __m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param __M
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1192,8 +1154,7 @@ _mm_testc_si128(__m128i __M, __m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param __M
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1216,8 +1177,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
|
||||
/// int _mm_test_all_ones(__m128i V);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param V
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1234,8 +1194,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
|
||||
/// int _mm_test_mix_ones_zeros(__m128i M, __m128i V);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param M
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1254,8 +1213,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
|
||||
/// int _mm_test_all_zeros(__m128i M, __m128i V);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
|
||||
///
|
||||
/// \param M
|
||||
/// A 128-bit integer vector containing the bits to be tested.
|
||||
@ -1270,8 +1228,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPEQQ / PCMPEQQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPCMPEQQ / PCMPEQQ </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit integer vector.
|
||||
@ -1292,8 +1249,7 @@ _mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXBW / PMOVSXBW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXBW / PMOVSXBW </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are sign-
|
||||
@ -1314,8 +1270,7 @@ _mm_cvtepi8_epi16(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXBD / PMOVSXBD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXBD / PMOVSXBD </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are sign-
|
||||
@ -1336,8 +1291,7 @@ _mm_cvtepi8_epi32(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXBQ / PMOVSXBQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXBQ / PMOVSXBQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are sign-
|
||||
@ -1358,8 +1312,7 @@ _mm_cvtepi8_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXWD / PMOVSXWD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXWD / PMOVSXWD </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are sign-
|
||||
@ -1378,8 +1331,7 @@ _mm_cvtepi16_epi32(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXWQ / PMOVSXWQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXWQ / PMOVSXWQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are sign-
|
||||
@ -1398,8 +1350,7 @@ _mm_cvtepi16_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVSXDQ / PMOVSXDQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVSXDQ / PMOVSXDQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are sign-
|
||||
@ -1419,8 +1370,7 @@ _mm_cvtepi32_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXBW / PMOVZXBW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXBW / PMOVZXBW </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are zero-
|
||||
@ -1439,8 +1389,7 @@ _mm_cvtepu8_epi16(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXBD / PMOVZXBD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXBD / PMOVZXBD </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are zero-
|
||||
@ -1459,8 +1408,7 @@ _mm_cvtepu8_epi32(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXBQ / PMOVZXBQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXBQ / PMOVZXBQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are zero-
|
||||
@ -1479,8 +1427,7 @@ _mm_cvtepu8_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXWD / PMOVZXWD </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXWD / PMOVZXWD </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are zero-
|
||||
@ -1499,8 +1446,7 @@ _mm_cvtepu16_epi32(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXWQ / PMOVZXWQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXWQ / PMOVZXWQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are zero-
|
||||
@ -1519,8 +1465,7 @@ _mm_cvtepu16_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPMOVZXDQ / PMOVZXDQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPMOVZXDQ / PMOVZXDQ </c> instruction.
|
||||
///
|
||||
/// \param __V
|
||||
/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are zero-
|
||||
@ -1540,8 +1485,7 @@ _mm_cvtepu32_epi64(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPACKUSDW / PACKUSDW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPACKUSDW / PACKUSDW </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit vector of [4 x i32]. Each 32-bit element is treated as a
|
||||
@ -1574,8 +1518,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
|
||||
/// __m128i _mm_mpsadbw_epu8(__m128i X, __m128i Y, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VMPSADBW / MPSADBW </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VMPSADBW / MPSADBW </c> instruction.
|
||||
///
|
||||
/// \param X
|
||||
/// A 128-bit vector of [16 x i8].
|
||||
@ -1608,7 +1551,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPHMINPOSUW / PHMINPOSUW </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPHMINPOSUW / PHMINPOSUW </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param __V
|
||||
@ -1668,7 +1611,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// __m128i _mm_cmpistrm(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRM / PCMPISTRM </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRM / PCMPISTRM </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1724,7 +1667,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistri(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1778,7 +1721,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// __m128i _mm_cmpestrm(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRM / PCMPESTRM </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRM / PCMPESTRM </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1839,7 +1782,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestri(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1899,7 +1842,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistra(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1949,7 +1892,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistrc(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -1997,7 +1940,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistro(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2046,7 +1989,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistrs(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2096,7 +2039,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpistrz(__m128i A, __m128i B, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2146,7 +2089,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestra(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2201,7 +2144,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestrc(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2243,6 +2186,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
(int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \
|
||||
(__v16qi)(__m128i)(B), (int)(LB), \
|
||||
(int)(M))
|
||||
|
||||
/// \brief Uses the immediate operand \a M to perform a comparison of string
|
||||
/// data with explicitly defined lengths that is contained in source operands
|
||||
/// \a A and \a B. Returns bit 0 of the resulting bit mask.
|
||||
@ -2253,7 +2197,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestro(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2307,7 +2251,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestrs(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI / PCMPESTRI </i> </c>
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
|
||||
/// instruction.
|
||||
///
|
||||
/// \param A
|
||||
@ -2362,7 +2306,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
/// int _mm_cmpestrz(__m128i A, int LA, __m128i B, int LB, const int M);
|
||||
/// \endcode
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPESTRI </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> VPCMPESTRI </c> instruction.
|
||||
///
|
||||
/// \param A
|
||||
/// A 128-bit integer vector containing one of the source operands to be
|
||||
@ -2412,8 +2356,7 @@ _mm_minpos_epu16(__m128i __V)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> VPCMPGTQ / PCMPGTQ </i> </c>
|
||||
/// instruction.
|
||||
/// This intrinsic corresponds to the <c> VPCMPGTQ / PCMPGTQ </c> instruction.
|
||||
///
|
||||
/// \param __V1
|
||||
/// A 128-bit integer vector.
|
||||
@ -2432,7 +2375,7 @@ _mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> CRC32B </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> CRC32B </c> instruction.
|
||||
///
|
||||
/// \param __C
|
||||
/// An unsigned integer operand to add to the CRC-32C checksum of operand
|
||||
@ -2452,7 +2395,7 @@ _mm_crc32_u8(unsigned int __C, unsigned char __D)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> CRC32W </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> CRC32W </c> instruction.
|
||||
///
|
||||
/// \param __C
|
||||
/// An unsigned integer operand to add to the CRC-32C checksum of operand
|
||||
@ -2472,7 +2415,7 @@ _mm_crc32_u16(unsigned int __C, unsigned short __D)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> CRC32L </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> CRC32L </c> instruction.
|
||||
///
|
||||
/// \param __C
|
||||
/// An unsigned integer operand to add to the CRC-32C checksum of operand
|
||||
@ -2493,7 +2436,7 @@ _mm_crc32_u32(unsigned int __C, unsigned int __D)
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> <i> CRC32Q </i> </c> instruction.
|
||||
/// This intrinsic corresponds to the <c> CRC32Q </c> instruction.
|
||||
///
|
||||
/// \param __C
|
||||
/// An unsigned integer operand to add to the CRC-32C checksum of operand
|
||||
|
@ -2540,7 +2540,7 @@ void _mm_setcsr(unsigned int __i);
|
||||
/// A 128-bit vector of [4 x float].
|
||||
/// \param mask
|
||||
/// An immediate value containing an 8-bit value specifying which elements to
|
||||
/// copy from \ a and \a b. \n
|
||||
/// copy from \a a and \a b. \n
|
||||
/// Bits [3:0] specify the values copied from operand \a a. \n
|
||||
/// Bits [7:4] specify the values copied from operand \a b. \n
|
||||
/// The destinations within the 128-bit destination are assigned values as
|
||||
|
@ -592,12 +592,10 @@ void CommentASTToXMLConverter::formatTextOfDeclaration(
|
||||
unsigned Offset = 0;
|
||||
unsigned Length = Declaration.size();
|
||||
|
||||
bool IncompleteFormat = false;
|
||||
format::FormatStyle Style = format::getLLVMStyle();
|
||||
Style.FixNamespaceComments = false;
|
||||
tooling::Replacements Replaces =
|
||||
reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd",
|
||||
&IncompleteFormat);
|
||||
reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd");
|
||||
auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
|
||||
if (static_cast<bool>(FormattedStringDecl)) {
|
||||
Declaration = *FormattedStringDecl;
|
||||
|
@ -495,8 +495,18 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
|
||||
ClassTemplateSpecializationDecl *D) {
|
||||
// FIXME: Notify subsequent callbacks if info comes from implicit
|
||||
// instantiation.
|
||||
if (D->isThisDeclarationADefinition())
|
||||
IndexCtx.indexTagDecl(D);
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
Template = D->getSpecializedTemplateOrPartial();
|
||||
const Decl *SpecializationOf =
|
||||
Template.is<ClassTemplateDecl *>()
|
||||
? (Decl *)Template.get<ClassTemplateDecl *>()
|
||||
: Template.get<ClassTemplatePartialSpecializationDecl *>();
|
||||
IndexCtx.indexTagDecl(
|
||||
D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
|
||||
SpecializationOf));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -346,6 +346,7 @@ bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
|
||||
APPLY_FOR_ROLE(RelationAccessorOf);
|
||||
APPLY_FOR_ROLE(RelationContainedBy);
|
||||
APPLY_FOR_ROLE(RelationIBTypeOf);
|
||||
APPLY_FOR_ROLE(RelationSpecializationOf);
|
||||
|
||||
#undef APPLY_FOR_ROLE
|
||||
|
||||
@ -386,6 +387,7 @@ void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
|
||||
case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break;
|
||||
case SymbolRole::RelationContainedBy: OS << "RelCont"; break;
|
||||
case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break;
|
||||
case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -208,11 +208,12 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
|
||||
}
|
||||
}
|
||||
|
||||
void IndexingContext::indexTagDecl(const TagDecl *D) {
|
||||
void IndexingContext::indexTagDecl(const TagDecl *D,
|
||||
ArrayRef<SymbolRelation> Relations) {
|
||||
if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
|
||||
return;
|
||||
|
||||
if (handleDecl(D)) {
|
||||
if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
|
||||
if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
|
@ -233,6 +233,7 @@ static bool shouldReportOccurrenceForSystemDeclOnlyMode(
|
||||
case SymbolRole::RelationReceivedBy:
|
||||
case SymbolRole::RelationCalledBy:
|
||||
case SymbolRole::RelationContainedBy:
|
||||
case SymbolRole::RelationSpecializationOf:
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("Unsupported SymbolRole value!");
|
||||
|
@ -80,7 +80,8 @@ class IndexingContext {
|
||||
|
||||
bool indexDecl(const Decl *D);
|
||||
|
||||
void indexTagDecl(const TagDecl *D);
|
||||
void indexTagDecl(const TagDecl *D,
|
||||
ArrayRef<SymbolRelation> Relations = None);
|
||||
|
||||
void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
|
||||
const DeclContext *DC = nullptr,
|
||||
|
@ -1171,6 +1171,8 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
|
||||
// If not a trigraph for escape, bail out.
|
||||
if (P[1] != '?' || P[2] != '/')
|
||||
return P;
|
||||
// FIXME: Take LangOpts into account; the language might not
|
||||
// support trigraphs.
|
||||
AfterEscape = P+3;
|
||||
} else {
|
||||
return P;
|
||||
@ -1282,12 +1284,6 @@ char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
|
||||
Size += EscapedNewLineSize;
|
||||
Ptr += EscapedNewLineSize;
|
||||
|
||||
// If the char that we finally got was a \n, then we must have had
|
||||
// something like \<newline><newline>. We don't want to consume the
|
||||
// second newline.
|
||||
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
|
||||
return ' ';
|
||||
|
||||
// Use slow version to accumulate a correct size field.
|
||||
return getCharAndSizeSlow(Ptr, Size, Tok);
|
||||
}
|
||||
@ -1338,12 +1334,6 @@ char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
|
||||
Size += EscapedNewLineSize;
|
||||
Ptr += EscapedNewLineSize;
|
||||
|
||||
// If the char that we finally got was a \n, then we must have had
|
||||
// something like \<newline><newline>. We don't want to consume the
|
||||
// second newline.
|
||||
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
|
||||
return ' ';
|
||||
|
||||
// Use slow version to accumulate a correct size field.
|
||||
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
|
||||
}
|
||||
@ -2070,8 +2060,11 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
|
||||
// Scan over the body of the comment. The common case, when scanning, is that
|
||||
// the comment contains normal ascii characters with nothing interesting in
|
||||
// them. As such, optimize for this case with the inner loop.
|
||||
//
|
||||
// This loop terminates with CurPtr pointing at the newline (or end of buffer)
|
||||
// character that ends the line comment.
|
||||
char C;
|
||||
do {
|
||||
while (true) {
|
||||
C = *CurPtr;
|
||||
// Skip over characters in the fast loop.
|
||||
while (C != 0 && // Potentially EOF.
|
||||
@ -2088,10 +2081,12 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
|
||||
HasSpace = true;
|
||||
}
|
||||
|
||||
if (*EscapePtr == '\\') // Escaped newline.
|
||||
if (*EscapePtr == '\\')
|
||||
// Escaped newline.
|
||||
CurPtr = EscapePtr;
|
||||
else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
|
||||
EscapePtr[-2] == '?') // Trigraph-escaped newline.
|
||||
EscapePtr[-2] == '?' && LangOpts.Trigraphs)
|
||||
// Trigraph-escaped newline.
|
||||
CurPtr = EscapePtr-2;
|
||||
else
|
||||
break; // This is a newline, we're done.
|
||||
@ -2140,9 +2135,9 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
|
||||
}
|
||||
}
|
||||
|
||||
if (CurPtr == BufferEnd+1) {
|
||||
--CurPtr;
|
||||
break;
|
||||
if (C == '\r' || C == '\n' || CurPtr == BufferEnd + 1) {
|
||||
--CurPtr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
|
||||
@ -2150,8 +2145,7 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
|
||||
cutOffLexing();
|
||||
return false;
|
||||
}
|
||||
|
||||
} while (C != '\n' && C != '\r');
|
||||
}
|
||||
|
||||
// Found but did not consume the newline. Notify comment handlers about the
|
||||
// comment unless we're in a #if 0 block.
|
||||
@ -2722,6 +2716,37 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *findPlaceholderEnd(const char *CurPtr,
|
||||
const char *BufferEnd) {
|
||||
if (CurPtr == BufferEnd)
|
||||
return nullptr;
|
||||
BufferEnd -= 1; // Scan until the second last character.
|
||||
for (; CurPtr != BufferEnd; ++CurPtr) {
|
||||
if (CurPtr[0] == '#' && CurPtr[1] == '>')
|
||||
return CurPtr + 2;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
|
||||
assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
|
||||
if (!PP || LexingRawMode)
|
||||
return false;
|
||||
const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
|
||||
if (!End)
|
||||
return false;
|
||||
const char *Start = CurPtr - 1;
|
||||
if (!LangOpts.AllowEditorPlaceholders)
|
||||
Diag(Start, diag::err_placeholder_in_source);
|
||||
Result.startToken();
|
||||
FormTokenWithChars(Result, End, tok::raw_identifier);
|
||||
Result.setRawIdentifierData(Start);
|
||||
PP->LookUpIdentifierInfo(Result);
|
||||
Result.setFlag(Token::IsEditorPlaceholder);
|
||||
BufferPtr = End;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
|
||||
if (PP && PP->isCodeCompletionEnabled()) {
|
||||
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
|
||||
@ -3479,6 +3504,8 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
|
||||
} else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{'
|
||||
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
|
||||
Kind = tok::l_brace;
|
||||
} else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) {
|
||||
return true;
|
||||
} else {
|
||||
Kind = tok::less;
|
||||
}
|
||||
|
@ -2002,9 +2002,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
|
||||
}
|
||||
|
||||
if (!Dir) {
|
||||
Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found)
|
||||
Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)
|
||||
<< DirName;
|
||||
HadError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -303,9 +303,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
||||
if (const FileEntry *FE = CurPPLexer->getFileEntry()) {
|
||||
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
|
||||
if (MacroInfo *MI =
|
||||
getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
|
||||
MI->UsedForHeaderGuard = true;
|
||||
}
|
||||
getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro)))
|
||||
MI->setUsedForHeaderGuard(true);
|
||||
if (const IdentifierInfo *DefinedMacro =
|
||||
CurPPLexer->MIOpt.GetDefinedMacro()) {
|
||||
if (!isMacroDefined(ControllingMacro) &&
|
||||
|
@ -183,6 +183,17 @@ struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler {
|
||||
Sema &Actions;
|
||||
};
|
||||
|
||||
/// PragmaAttributeHandler - "\#pragma clang attribute ...".
|
||||
struct PragmaAttributeHandler : public PragmaHandler {
|
||||
PragmaAttributeHandler(AttributeFactory &AttrFactory)
|
||||
: PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {}
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &FirstToken) override;
|
||||
|
||||
/// A pool of attributes that were parsed in \#pragma clang attribute.
|
||||
ParsedAttributes AttributesForPragmaAttribute;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
void Parser::initializePragmaHandlers() {
|
||||
@ -275,6 +286,9 @@ void Parser::initializePragmaHandlers() {
|
||||
|
||||
FPHandler.reset(new PragmaFPHandler());
|
||||
PP.AddPragmaHandler("clang", FPHandler.get());
|
||||
|
||||
AttributePragmaHandler.reset(new PragmaAttributeHandler(AttrFactory));
|
||||
PP.AddPragmaHandler("clang", AttributePragmaHandler.get());
|
||||
}
|
||||
|
||||
void Parser::resetPragmaHandlers() {
|
||||
@ -356,6 +370,9 @@ void Parser::resetPragmaHandlers() {
|
||||
|
||||
PP.RemovePragmaHandler("clang", FPHandler.get());
|
||||
FPHandler.reset();
|
||||
|
||||
PP.RemovePragmaHandler("clang", AttributePragmaHandler.get());
|
||||
AttributePragmaHandler.reset();
|
||||
}
|
||||
|
||||
/// \brief Handle the annotation token produced for #pragma unused(...)
|
||||
@ -966,6 +983,422 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct PragmaAttributeInfo {
|
||||
enum ActionType { Push, Pop };
|
||||
ParsedAttributes &Attributes;
|
||||
ActionType Action;
|
||||
ArrayRef<Token> Tokens;
|
||||
|
||||
PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {}
|
||||
};
|
||||
|
||||
#include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc"
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static StringRef getIdentifier(const Token &Tok) {
|
||||
if (Tok.is(tok::identifier))
|
||||
return Tok.getIdentifierInfo()->getName();
|
||||
const char *S = tok::getKeywordSpelling(Tok.getKind());
|
||||
if (!S)
|
||||
return "";
|
||||
return S;
|
||||
}
|
||||
|
||||
static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) {
|
||||
using namespace attr;
|
||||
switch (Rule) {
|
||||
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \
|
||||
case Value: \
|
||||
return IsAbstract;
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
}
|
||||
llvm_unreachable("Invalid attribute subject match rule");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void diagnoseExpectedAttributeSubjectSubRule(
|
||||
Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
|
||||
SourceLocation SubRuleLoc) {
|
||||
auto Diagnostic =
|
||||
PRef.Diag(SubRuleLoc,
|
||||
diag::err_pragma_attribute_expected_subject_sub_identifier)
|
||||
<< PrimaryRuleName;
|
||||
if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
|
||||
Diagnostic << /*SubRulesSupported=*/1 << SubRules;
|
||||
else
|
||||
Diagnostic << /*SubRulesSupported=*/0;
|
||||
}
|
||||
|
||||
static void diagnoseUnknownAttributeSubjectSubRule(
|
||||
Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
|
||||
StringRef SubRuleName, SourceLocation SubRuleLoc) {
|
||||
|
||||
auto Diagnostic =
|
||||
PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule)
|
||||
<< SubRuleName << PrimaryRuleName;
|
||||
if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
|
||||
Diagnostic << /*SubRulesSupported=*/1 << SubRules;
|
||||
else
|
||||
Diagnostic << /*SubRulesSupported=*/0;
|
||||
}
|
||||
|
||||
bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
|
||||
attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc,
|
||||
SourceLocation &LastMatchRuleEndLoc) {
|
||||
bool IsAny = false;
|
||||
BalancedDelimiterTracker AnyParens(*this, tok::l_paren);
|
||||
if (getIdentifier(Tok) == "any") {
|
||||
AnyLoc = ConsumeToken();
|
||||
IsAny = true;
|
||||
if (AnyParens.expectAndConsume())
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
// Parse the subject matcher rule.
|
||||
StringRef Name = getIdentifier(Tok);
|
||||
if (Name.empty()) {
|
||||
Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier);
|
||||
return true;
|
||||
}
|
||||
std::pair<Optional<attr::SubjectMatchRule>,
|
||||
Optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
|
||||
Rule = isAttributeSubjectMatchRule(Name);
|
||||
if (!Rule.first) {
|
||||
Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name;
|
||||
return true;
|
||||
}
|
||||
attr::SubjectMatchRule PrimaryRule = *Rule.first;
|
||||
SourceLocation RuleLoc = ConsumeToken();
|
||||
|
||||
BalancedDelimiterTracker Parens(*this, tok::l_paren);
|
||||
if (isAbstractAttrMatcherRule(PrimaryRule)) {
|
||||
if (Parens.expectAndConsume())
|
||||
return true;
|
||||
} else if (Parens.consumeOpen()) {
|
||||
if (!SubjectMatchRules
|
||||
.insert(
|
||||
std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc)))
|
||||
.second)
|
||||
Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
|
||||
<< Name
|
||||
<< FixItHint::CreateRemoval(SourceRange(
|
||||
RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc));
|
||||
LastMatchRuleEndLoc = RuleLoc;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse the sub-rules.
|
||||
StringRef SubRuleName = getIdentifier(Tok);
|
||||
if (SubRuleName.empty()) {
|
||||
diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
|
||||
Tok.getLocation());
|
||||
return true;
|
||||
}
|
||||
attr::SubjectMatchRule SubRule;
|
||||
if (SubRuleName == "unless") {
|
||||
SourceLocation SubRuleLoc = ConsumeToken();
|
||||
BalancedDelimiterTracker Parens(*this, tok::l_paren);
|
||||
if (Parens.expectAndConsume())
|
||||
return true;
|
||||
SubRuleName = getIdentifier(Tok);
|
||||
if (SubRuleName.empty()) {
|
||||
diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
|
||||
SubRuleLoc);
|
||||
return true;
|
||||
}
|
||||
auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true);
|
||||
if (!SubRuleOrNone) {
|
||||
std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")";
|
||||
diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
|
||||
SubRuleUnlessName, SubRuleLoc);
|
||||
return true;
|
||||
}
|
||||
SubRule = *SubRuleOrNone;
|
||||
ConsumeToken();
|
||||
if (Parens.consumeClose())
|
||||
return true;
|
||||
} else {
|
||||
auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false);
|
||||
if (!SubRuleOrNone) {
|
||||
diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
|
||||
SubRuleName, Tok.getLocation());
|
||||
return true;
|
||||
}
|
||||
SubRule = *SubRuleOrNone;
|
||||
ConsumeToken();
|
||||
}
|
||||
SourceLocation RuleEndLoc = Tok.getLocation();
|
||||
LastMatchRuleEndLoc = RuleEndLoc;
|
||||
if (Parens.consumeClose())
|
||||
return true;
|
||||
if (!SubjectMatchRules
|
||||
.insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc)))
|
||||
.second) {
|
||||
Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
|
||||
<< attr::getSubjectMatchRuleSpelling(SubRule)
|
||||
<< FixItHint::CreateRemoval(SourceRange(
|
||||
RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc));
|
||||
continue;
|
||||
}
|
||||
} while (IsAny && TryConsumeToken(tok::comma));
|
||||
|
||||
if (IsAny)
|
||||
if (AnyParens.consumeClose())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// Describes the stage at which attribute subject rule parsing was interruped.
|
||||
enum class MissingAttributeSubjectRulesRecoveryPoint {
|
||||
Comma,
|
||||
ApplyTo,
|
||||
Equals,
|
||||
Any,
|
||||
None,
|
||||
};
|
||||
|
||||
MissingAttributeSubjectRulesRecoveryPoint
|
||||
getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
|
||||
if (const auto *II = Tok.getIdentifierInfo()) {
|
||||
if (II->isStr("apply_to"))
|
||||
return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
|
||||
if (II->isStr("any"))
|
||||
return MissingAttributeSubjectRulesRecoveryPoint::Any;
|
||||
}
|
||||
if (Tok.is(tok::equal))
|
||||
return MissingAttributeSubjectRulesRecoveryPoint::Equals;
|
||||
return MissingAttributeSubjectRulesRecoveryPoint::None;
|
||||
}
|
||||
|
||||
/// Creates a diagnostic for the attribute subject rule parsing diagnostic that
|
||||
/// suggests the possible attribute subject rules in a fix-it together with
|
||||
/// any other missing tokens.
|
||||
DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic(
|
||||
unsigned DiagID, AttributeList &Attribute,
|
||||
MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) {
|
||||
SourceLocation Loc = PRef.getEndOfPreviousToken();
|
||||
if (Loc.isInvalid())
|
||||
Loc = PRef.getCurToken().getLocation();
|
||||
auto Diagnostic = PRef.Diag(Loc, DiagID);
|
||||
std::string FixIt;
|
||||
MissingAttributeSubjectRulesRecoveryPoint EndPoint =
|
||||
getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken());
|
||||
if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma)
|
||||
FixIt = ", ";
|
||||
if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo &&
|
||||
EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo)
|
||||
FixIt += "apply_to";
|
||||
if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals &&
|
||||
EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals)
|
||||
FixIt += " = ";
|
||||
SourceRange FixItRange(Loc);
|
||||
if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) {
|
||||
// Gather the subject match rules that are supported by the attribute.
|
||||
SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet;
|
||||
Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet);
|
||||
if (SubjectMatchRuleSet.empty()) {
|
||||
// FIXME: We can emit a "fix-it" with a subject list placeholder when
|
||||
// placeholders will be supported by the fix-its.
|
||||
return Diagnostic;
|
||||
}
|
||||
FixIt += "any(";
|
||||
bool NeedsComma = false;
|
||||
for (const auto &I : SubjectMatchRuleSet) {
|
||||
// Ensure that the missing rule is reported in the fix-it only when it's
|
||||
// supported in the current language mode.
|
||||
if (!I.second)
|
||||
continue;
|
||||
if (NeedsComma)
|
||||
FixIt += ", ";
|
||||
else
|
||||
NeedsComma = true;
|
||||
FixIt += attr::getSubjectMatchRuleSpelling(I.first);
|
||||
}
|
||||
FixIt += ")";
|
||||
// Check if we need to remove the range
|
||||
PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch);
|
||||
FixItRange.setEnd(PRef.getCurToken().getLocation());
|
||||
}
|
||||
if (FixItRange.getBegin() == FixItRange.getEnd())
|
||||
Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt);
|
||||
else
|
||||
Diagnostic << FixItHint::CreateReplacement(
|
||||
CharSourceRange::getCharRange(FixItRange), FixIt);
|
||||
return Diagnostic;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void Parser::HandlePragmaAttribute() {
|
||||
assert(Tok.is(tok::annot_pragma_attribute) &&
|
||||
"Expected #pragma attribute annotation token");
|
||||
SourceLocation PragmaLoc = Tok.getLocation();
|
||||
auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue());
|
||||
if (Info->Action == PragmaAttributeInfo::Pop) {
|
||||
ConsumeToken();
|
||||
Actions.ActOnPragmaAttributePop(PragmaLoc);
|
||||
return;
|
||||
}
|
||||
// Parse the actual attribute with its arguments.
|
||||
assert(Info->Action == PragmaAttributeInfo::Push &&
|
||||
"Unexpected #pragma attribute command");
|
||||
PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false);
|
||||
ConsumeToken();
|
||||
|
||||
ParsedAttributes &Attrs = Info->Attributes;
|
||||
Attrs.clearListOnly();
|
||||
|
||||
auto SkipToEnd = [this]() {
|
||||
SkipUntil(tok::eof, StopBeforeMatch);
|
||||
ConsumeToken();
|
||||
};
|
||||
|
||||
if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
|
||||
// Parse the CXX11 style attribute.
|
||||
ParseCXX11AttributeSpecifier(Attrs);
|
||||
} else if (Tok.is(tok::kw___attribute)) {
|
||||
ConsumeToken();
|
||||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
||||
"attribute"))
|
||||
return SkipToEnd();
|
||||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "("))
|
||||
return SkipToEnd();
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok, diag::err_pragma_attribute_expected_attribute_name);
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||
SourceLocation AttrNameLoc = ConsumeToken();
|
||||
|
||||
if (Tok.isNot(tok::l_paren))
|
||||
Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
|
||||
AttributeList::AS_GNU);
|
||||
else
|
||||
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr,
|
||||
/*ScopeName=*/nullptr,
|
||||
/*ScopeLoc=*/SourceLocation(),
|
||||
AttributeList::AS_GNU,
|
||||
/*Declarator=*/nullptr);
|
||||
|
||||
if (ExpectAndConsume(tok::r_paren))
|
||||
return SkipToEnd();
|
||||
if (ExpectAndConsume(tok::r_paren))
|
||||
return SkipToEnd();
|
||||
} else if (Tok.is(tok::kw___declspec)) {
|
||||
ParseMicrosoftDeclSpecs(Attrs);
|
||||
} else {
|
||||
Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
|
||||
if (Tok.getIdentifierInfo()) {
|
||||
// If we suspect that this is an attribute suggest the use of
|
||||
// '__attribute__'.
|
||||
if (AttributeList::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
|
||||
AttributeList::AS_GNU) !=
|
||||
AttributeList::UnknownAttribute) {
|
||||
SourceLocation InsertStartLoc = Tok.getLocation();
|
||||
ConsumeToken();
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
ConsumeAnyToken();
|
||||
SkipUntil(tok::r_paren, StopBeforeMatch);
|
||||
if (Tok.isNot(tok::r_paren))
|
||||
return SkipToEnd();
|
||||
}
|
||||
Diag(Tok, diag::note_pragma_attribute_use_attribute_kw)
|
||||
<< FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((")
|
||||
<< FixItHint::CreateInsertion(Tok.getEndLoc(), "))");
|
||||
}
|
||||
}
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Attrs.getList() || Attrs.getList()->isInvalid()) {
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that we don't have more than one attribute.
|
||||
if (Attrs.getList()->getNext()) {
|
||||
SourceLocation Loc = Attrs.getList()->getNext()->getLoc();
|
||||
Diag(Loc, diag::err_pragma_attribute_multiple_attributes);
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Attrs.getList()->isSupportedByPragmaAttribute()) {
|
||||
Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute)
|
||||
<< Attrs.getList()->getName();
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
AttributeList &Attribute = *Attrs.getList();
|
||||
|
||||
// Parse the subject-list.
|
||||
if (!TryConsumeToken(tok::comma)) {
|
||||
createExpectedAttributeSubjectRulesTokenDiagnostic(
|
||||
diag::err_expected, Attribute,
|
||||
MissingAttributeSubjectRulesRecoveryPoint::Comma, *this)
|
||||
<< tok::comma;
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
createExpectedAttributeSubjectRulesTokenDiagnostic(
|
||||
diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
|
||||
MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
if (!II->isStr("apply_to")) {
|
||||
createExpectedAttributeSubjectRulesTokenDiagnostic(
|
||||
diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
|
||||
MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
ConsumeToken();
|
||||
|
||||
if (!TryConsumeToken(tok::equal)) {
|
||||
createExpectedAttributeSubjectRulesTokenDiagnostic(
|
||||
diag::err_expected, Attribute,
|
||||
MissingAttributeSubjectRulesRecoveryPoint::Equals, *this)
|
||||
<< tok::equal;
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
attr::ParsedSubjectMatchRuleSet SubjectMatchRules;
|
||||
SourceLocation AnyLoc, LastMatchRuleEndLoc;
|
||||
if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc,
|
||||
LastMatchRuleEndLoc)) {
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
// Tokens following an ill-formed attribute will remain in the token stream
|
||||
// and must be removed.
|
||||
if (Tok.isNot(tok::eof)) {
|
||||
Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute);
|
||||
SkipToEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
// Consume the eof terminator token.
|
||||
ConsumeToken();
|
||||
|
||||
Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc,
|
||||
std::move(SubjectMatchRules));
|
||||
}
|
||||
|
||||
// #pragma GCC visibility comes in two variants:
|
||||
// 'push' '(' [visibility] ')'
|
||||
// 'pop'
|
||||
@ -2395,3 +2828,104 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
|
||||
PP.Diag(FirstTok.getLocation(),
|
||||
diag::warn_pragma_force_cuda_host_device_bad_arg);
|
||||
}
|
||||
|
||||
/// \brief Handle the #pragma clang attribute directive.
|
||||
///
|
||||
/// The syntax is:
|
||||
/// \code
|
||||
/// #pragma clang attribute push(attribute, subject-set)
|
||||
/// #pragma clang attribute pop
|
||||
/// \endcode
|
||||
///
|
||||
/// The subject-set clause defines the set of declarations which receive the
|
||||
/// attribute. Its exact syntax is described in the LanguageExtensions document
|
||||
/// in Clang's documentation.
|
||||
///
|
||||
/// This directive instructs the compiler to begin/finish applying the specified
|
||||
/// attribute to the set of attribute-specific declarations in the active range
|
||||
/// of the pragma.
|
||||
void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
|
||||
PragmaIntroducerKind Introducer,
|
||||
Token &FirstToken) {
|
||||
Token Tok;
|
||||
PP.Lex(Tok);
|
||||
auto *Info = new (PP.getPreprocessorAllocator())
|
||||
PragmaAttributeInfo(AttributesForPragmaAttribute);
|
||||
|
||||
// Parse the 'push' or 'pop'.
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_push_pop);
|
||||
return;
|
||||
}
|
||||
const auto *II = Tok.getIdentifierInfo();
|
||||
if (II->isStr("push"))
|
||||
Info->Action = PragmaAttributeInfo::Push;
|
||||
else if (II->isStr("pop"))
|
||||
Info->Action = PragmaAttributeInfo::Pop;
|
||||
else {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument)
|
||||
<< PP.getSpelling(Tok);
|
||||
return;
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
// Parse the actual attribute.
|
||||
if (Info->Action == PragmaAttributeInfo::Push) {
|
||||
if (Tok.isNot(tok::l_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
|
||||
return;
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
// Lex the attribute tokens.
|
||||
SmallVector<Token, 16> AttributeTokens;
|
||||
int OpenParens = 1;
|
||||
while (Tok.isNot(tok::eod)) {
|
||||
if (Tok.is(tok::l_paren))
|
||||
OpenParens++;
|
||||
else if (Tok.is(tok::r_paren)) {
|
||||
OpenParens--;
|
||||
if (OpenParens == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
AttributeTokens.push_back(Tok);
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
|
||||
if (AttributeTokens.empty()) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute);
|
||||
return;
|
||||
}
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
|
||||
return;
|
||||
}
|
||||
SourceLocation EndLoc = Tok.getLocation();
|
||||
PP.Lex(Tok);
|
||||
|
||||
// Terminate the attribute for parsing.
|
||||
Token EOFTok;
|
||||
EOFTok.startToken();
|
||||
EOFTok.setKind(tok::eof);
|
||||
EOFTok.setLocation(EndLoc);
|
||||
AttributeTokens.push_back(EOFTok);
|
||||
|
||||
Info->Tokens =
|
||||
llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::eod))
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< "clang attribute";
|
||||
|
||||
// Generate the annotated pragma token.
|
||||
auto TokenArray = llvm::make_unique<Token[]>(1);
|
||||
TokenArray[0].startToken();
|
||||
TokenArray[0].setKind(tok::annot_pragma_attribute);
|
||||
TokenArray[0].setLocation(FirstToken.getLocation());
|
||||
TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation());
|
||||
TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
|
||||
PP.EnterTokenStream(std::move(TokenArray), 1,
|
||||
/*DisableMacroExpansion=*/false);
|
||||
}
|
||||
|
@ -382,6 +382,10 @@ Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
|
||||
case tok::annot_pragma_dump:
|
||||
HandlePragmaDump();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_attribute:
|
||||
HandlePragmaAttribute();
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
// If we reached this code, the statement must end in a semicolon.
|
||||
|
@ -602,6 +602,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
|
||||
ConsumeToken();
|
||||
return false;
|
||||
|
||||
case tok::annot_pragma_attribute:
|
||||
HandlePragmaAttribute();
|
||||
return false;
|
||||
|
||||
case tok::eof:
|
||||
// Late template parsing can begin.
|
||||
if (getLangOpts().DelayedTemplateParsing)
|
||||
@ -847,6 +851,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
|
||||
|
||||
default:
|
||||
dont_know:
|
||||
if (Tok.isEditorPlaceholder()) {
|
||||
ConsumeToken();
|
||||
return nullptr;
|
||||
}
|
||||
// We can't tell whether this is a function-definition or declaration yet.
|
||||
return ParseDeclarationOrFunctionDefinition(attrs, DS);
|
||||
}
|
||||
@ -1675,6 +1683,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Tok.isEditorPlaceholder())
|
||||
return true;
|
||||
|
||||
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
|
||||
return true;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Basic/AttrSubjectMatchRules.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
@ -160,12 +161,16 @@ struct ParsedAttrInfo {
|
||||
unsigned IsType : 1;
|
||||
unsigned IsStmt : 1;
|
||||
unsigned IsKnownToGCC : 1;
|
||||
unsigned IsSupportedByPragmaAttribute : 1;
|
||||
|
||||
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
|
||||
const Decl *);
|
||||
bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
|
||||
bool (*ExistsInTarget)(const TargetInfo &Target);
|
||||
unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
|
||||
void (*GetPragmaAttributeMatchRules)(
|
||||
llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
|
||||
const LangOptions &LangOpts);
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -192,6 +197,18 @@ bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
|
||||
return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
|
||||
}
|
||||
|
||||
bool AttributeList::appliesToDecl(const Decl *D,
|
||||
attr::SubjectMatchRule MatchRule) const {
|
||||
return checkAttributeMatchRuleAppliesTo(D, MatchRule);
|
||||
}
|
||||
|
||||
void AttributeList::getMatchRules(
|
||||
const LangOptions &LangOpts,
|
||||
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
|
||||
const {
|
||||
return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
|
||||
}
|
||||
|
||||
bool AttributeList::diagnoseLangOpts(Sema &S) const {
|
||||
return getInfo(*this).DiagLangOpts(S, *this);
|
||||
}
|
||||
@ -216,6 +233,10 @@ bool AttributeList::isKnownToGCC() const {
|
||||
return getInfo(*this).IsKnownToGCC;
|
||||
}
|
||||
|
||||
bool AttributeList::isSupportedByPragmaAttribute() const {
|
||||
return getInfo(*this).IsSupportedByPragmaAttribute;
|
||||
}
|
||||
|
||||
unsigned AttributeList::getSemanticSpelling() const {
|
||||
return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
|
||||
}
|
||||
|
@ -287,6 +287,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
||||
IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
|
||||
break;
|
||||
|
||||
case Stmt::ObjCForCollectionStmtClass: {
|
||||
auto *CS = cast<ObjCForCollectionStmt>(S);
|
||||
unsigned Diag = diag::note_protected_by_objc_fast_enumeration;
|
||||
unsigned NewParentScope = Scopes.size();
|
||||
Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getLocStart()));
|
||||
BuildScopeInformation(CS->getBody(), NewParentScope);
|
||||
return;
|
||||
}
|
||||
|
||||
case Stmt::IndirectGotoStmtClass:
|
||||
// "goto *&&lbl;" is a special case which we treat as equivalent
|
||||
// to a normal goto. In addition, we don't calculate scope in the
|
||||
|
@ -71,42 +71,35 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
|
||||
}
|
||||
|
||||
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
||||
TranslationUnitKind TUKind,
|
||||
CodeCompleteConsumer *CodeCompleter)
|
||||
: ExternalSource(nullptr),
|
||||
isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
|
||||
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
|
||||
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
|
||||
CollectStats(false), CodeCompleter(CodeCompleter),
|
||||
CurContext(nullptr), OriginalLexicalContext(nullptr),
|
||||
MSStructPragmaOn(false),
|
||||
MSPointerToMemberRepresentationMethod(
|
||||
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
||||
VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
|
||||
PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr),
|
||||
ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
|
||||
VisContext(nullptr),
|
||||
IsBuildingRecoveryCallExpr(false),
|
||||
Cleanup{}, LateTemplateParser(nullptr),
|
||||
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
|
||||
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
|
||||
CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
|
||||
NSNumberDecl(nullptr), NSValueDecl(nullptr),
|
||||
NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
|
||||
ValueWithBytesObjCTypeMethod(nullptr),
|
||||
NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
|
||||
NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
|
||||
GlobalNewDeleteDeclared(false),
|
||||
TUKind(TUKind),
|
||||
NumSFINAEErrors(0),
|
||||
CachedFakeTopLevelModule(nullptr),
|
||||
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
|
||||
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
|
||||
CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
|
||||
TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
|
||||
VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
|
||||
Ident_super(nullptr), Ident___float128(nullptr)
|
||||
{
|
||||
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
|
||||
: ExternalSource(nullptr), isMultiplexExternalSource(false),
|
||||
FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
|
||||
Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
|
||||
SourceMgr(PP.getSourceManager()), CollectStats(false),
|
||||
CodeCompleter(CodeCompleter), CurContext(nullptr),
|
||||
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
|
||||
MSPointerToMemberRepresentationMethod(
|
||||
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
||||
VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
|
||||
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
|
||||
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
|
||||
PragmaAttributeCurrentTargetDecl(nullptr),
|
||||
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
|
||||
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
|
||||
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
|
||||
CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr),
|
||||
NSValueDecl(nullptr), NSStringDecl(nullptr),
|
||||
StringWithUTF8StringMethod(nullptr),
|
||||
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
|
||||
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
|
||||
DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
|
||||
TUKind(TUKind), NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr),
|
||||
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
|
||||
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
|
||||
CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
|
||||
TyposCorrected(0), AnalysisWarnings(*this),
|
||||
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
|
||||
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
|
||||
TUScope = nullptr;
|
||||
|
||||
LoadedExternalKnownNamespaces = false;
|
||||
@ -731,6 +724,8 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
CheckDelayedMemberExceptionSpecs();
|
||||
}
|
||||
|
||||
DiagnoseUnterminatedPragmaAttribute();
|
||||
|
||||
// All delayed member exception specs should be checked or we end up accepting
|
||||
// incompatible declarations.
|
||||
// FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
|
||||
|
@ -368,6 +368,219 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
|
||||
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Optional<attr::SubjectMatchRule>
|
||||
getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
|
||||
using namespace attr;
|
||||
switch (Rule) {
|
||||
default:
|
||||
return None;
|
||||
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
|
||||
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
|
||||
case Value: \
|
||||
return Parent;
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
}
|
||||
}
|
||||
|
||||
bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) {
|
||||
using namespace attr;
|
||||
switch (Rule) {
|
||||
default:
|
||||
return false;
|
||||
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
|
||||
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
|
||||
case Value: \
|
||||
return IsNegated;
|
||||
#include "clang/Basic/AttrSubMatchRulesList.inc"
|
||||
}
|
||||
}
|
||||
|
||||
CharSourceRange replacementRangeForListElement(const Sema &S,
|
||||
SourceRange Range) {
|
||||
// Make sure that the ',' is removed as well.
|
||||
SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken(
|
||||
Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(),
|
||||
/*SkipTrailingWhitespaceAndNewLine=*/false);
|
||||
if (AfterCommaLoc.isValid())
|
||||
return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc);
|
||||
else
|
||||
return CharSourceRange::getTokenRange(Range);
|
||||
}
|
||||
|
||||
std::string
|
||||
attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
for (const auto &I : llvm::enumerate(Rules)) {
|
||||
if (I.index())
|
||||
OS << (I.index() == Rules.size() - 1 ? ", and " : ", ");
|
||||
OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'";
|
||||
}
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void Sema::ActOnPragmaAttributePush(AttributeList &Attribute,
|
||||
SourceLocation PragmaLoc,
|
||||
attr::ParsedSubjectMatchRuleSet Rules) {
|
||||
SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
|
||||
// Gather the subject match rules that are supported by the attribute.
|
||||
SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
|
||||
StrictSubjectMatchRuleSet;
|
||||
Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet);
|
||||
|
||||
// Figure out which subject matching rules are valid.
|
||||
if (StrictSubjectMatchRuleSet.empty()) {
|
||||
// Check for contradicting match rules. Contradicting match rules are
|
||||
// either:
|
||||
// - a top-level rule and one of its sub-rules. E.g. variable and
|
||||
// variable(is_parameter).
|
||||
// - a sub-rule and a sibling that's negated. E.g.
|
||||
// variable(is_thread_local) and variable(unless(is_parameter))
|
||||
llvm::SmallDenseMap<int, std::pair<int, SourceRange>, 2>
|
||||
RulesToFirstSpecifiedNegatedSubRule;
|
||||
for (const auto &Rule : Rules) {
|
||||
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
|
||||
Optional<attr::SubjectMatchRule> ParentRule =
|
||||
getParentAttrMatcherRule(MatchRule);
|
||||
if (!ParentRule)
|
||||
continue;
|
||||
auto It = Rules.find(*ParentRule);
|
||||
if (It != Rules.end()) {
|
||||
// A sub-rule contradicts a parent rule.
|
||||
Diag(Rule.second.getBegin(),
|
||||
diag::err_pragma_attribute_matcher_subrule_contradicts_rule)
|
||||
<< attr::getSubjectMatchRuleSpelling(MatchRule)
|
||||
<< attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second
|
||||
<< FixItHint::CreateRemoval(
|
||||
replacementRangeForListElement(*this, Rule.second));
|
||||
// Keep going without removing this rule as it won't change the set of
|
||||
// declarations that receive the attribute.
|
||||
continue;
|
||||
}
|
||||
if (isNegatedAttrMatcherSubRule(MatchRule))
|
||||
RulesToFirstSpecifiedNegatedSubRule.insert(
|
||||
std::make_pair(*ParentRule, Rule));
|
||||
}
|
||||
bool IgnoreNegatedSubRules = false;
|
||||
for (const auto &Rule : Rules) {
|
||||
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
|
||||
Optional<attr::SubjectMatchRule> ParentRule =
|
||||
getParentAttrMatcherRule(MatchRule);
|
||||
if (!ParentRule)
|
||||
continue;
|
||||
auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule);
|
||||
if (It != RulesToFirstSpecifiedNegatedSubRule.end() &&
|
||||
It->second != Rule) {
|
||||
// Negated sub-rule contradicts another sub-rule.
|
||||
Diag(
|
||||
It->second.second.getBegin(),
|
||||
diag::
|
||||
err_pragma_attribute_matcher_negated_subrule_contradicts_subrule)
|
||||
<< attr::getSubjectMatchRuleSpelling(
|
||||
attr::SubjectMatchRule(It->second.first))
|
||||
<< attr::getSubjectMatchRuleSpelling(MatchRule) << Rule.second
|
||||
<< FixItHint::CreateRemoval(
|
||||
replacementRangeForListElement(*this, It->second.second));
|
||||
// Keep going but ignore all of the negated sub-rules.
|
||||
IgnoreNegatedSubRules = true;
|
||||
RulesToFirstSpecifiedNegatedSubRule.erase(It);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IgnoreNegatedSubRules) {
|
||||
for (const auto &Rule : Rules)
|
||||
SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
|
||||
} else {
|
||||
for (const auto &Rule : Rules) {
|
||||
if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first)))
|
||||
SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
|
||||
}
|
||||
}
|
||||
Rules.clear();
|
||||
} else {
|
||||
for (const auto &Rule : StrictSubjectMatchRuleSet) {
|
||||
if (Rules.erase(Rule.first)) {
|
||||
// Add the rule to the set of attribute receivers only if it's supported
|
||||
// in the current language mode.
|
||||
if (Rule.second)
|
||||
SubjectMatchRules.push_back(Rule.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Rules.empty()) {
|
||||
auto Diagnostic =
|
||||
Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
|
||||
<< Attribute.getName();
|
||||
SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
|
||||
for (const auto &Rule : Rules) {
|
||||
ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
|
||||
Diagnostic << FixItHint::CreateRemoval(
|
||||
replacementRangeForListElement(*this, Rule.second));
|
||||
}
|
||||
Diagnostic << attrMatcherRuleListToString(ExtraRules);
|
||||
}
|
||||
|
||||
PragmaAttributeStack.push_back(
|
||||
{PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
|
||||
if (PragmaAttributeStack.empty()) {
|
||||
Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
|
||||
return;
|
||||
}
|
||||
const PragmaAttributeEntry &Entry = PragmaAttributeStack.back();
|
||||
if (!Entry.IsUsed) {
|
||||
assert(Entry.Attribute && "Expected an attribute");
|
||||
Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
|
||||
<< Entry.Attribute->getName();
|
||||
Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
|
||||
}
|
||||
PragmaAttributeStack.pop_back();
|
||||
}
|
||||
|
||||
void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
|
||||
if (PragmaAttributeStack.empty())
|
||||
return;
|
||||
for (auto &Entry : PragmaAttributeStack) {
|
||||
const AttributeList *Attribute = Entry.Attribute;
|
||||
assert(Attribute && "Expected an attribute");
|
||||
|
||||
// Ensure that the attribute can be applied to the given declaration.
|
||||
bool Applies = false;
|
||||
for (const auto &Rule : Entry.MatchRules) {
|
||||
if (Attribute->appliesToDecl(D, Rule)) {
|
||||
Applies = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Applies)
|
||||
continue;
|
||||
Entry.IsUsed = true;
|
||||
assert(!Attribute->getNext() && "Expected just one attribute");
|
||||
PragmaAttributeCurrentTargetDecl = D;
|
||||
ProcessDeclAttributeList(S, D, Attribute);
|
||||
PragmaAttributeCurrentTargetDecl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::PrintPragmaAttributeInstantiationPoint() {
|
||||
assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
|
||||
Diags.Report(PragmaAttributeCurrentTargetDecl->getLocStart(),
|
||||
diag::note_pragma_attribute_applied_decl_here);
|
||||
}
|
||||
|
||||
void Sema::DiagnoseUnterminatedPragmaAttribute() {
|
||||
if (PragmaAttributeStack.empty())
|
||||
return;
|
||||
Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof);
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
|
||||
if(On)
|
||||
OptimizeOffPragmaLocation = SourceLocation();
|
||||
|
@ -480,6 +480,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
|
||||
bool ErrorRecoveryLookup,
|
||||
bool *IsCorrectedToColon,
|
||||
bool OnlyNamespace) {
|
||||
if (IdInfo.Identifier->isEditorPlaceholder())
|
||||
return true;
|
||||
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
|
||||
OnlyNamespace ? LookupNamespaceName
|
||||
: LookupNestedNameSpecifierName);
|
||||
|
@ -1391,8 +1391,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
|
||||
}
|
||||
|
||||
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
||||
llvm::APSInt Result;
|
||||
|
||||
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
|
||||
BuiltinID == ARM::BI__builtin_arm_ldaex ||
|
||||
BuiltinID == ARM::BI__builtin_arm_strex ||
|
||||
@ -1439,8 +1437,6 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
||||
|
||||
bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
|
||||
CallExpr *TheCall) {
|
||||
llvm::APSInt Result;
|
||||
|
||||
if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
|
||||
BuiltinID == AArch64::BI__builtin_arm_ldaex ||
|
||||
BuiltinID == AArch64::BI__builtin_arm_strex ||
|
||||
|
@ -454,7 +454,7 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
|
||||
/*IsImplicit*/ true);
|
||||
Suspend = S.ActOnFinishFullExpr(Suspend.get());
|
||||
if (Suspend.isInvalid()) {
|
||||
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
|
||||
S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
|
||||
<< ((Name == "initial_suspend") ? 0 : 1);
|
||||
S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
|
||||
return StmtError();
|
||||
@ -660,6 +660,39 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// Look up the std::nothrow object.
|
||||
static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
|
||||
NamespaceDecl *Std = S.getStdNamespace();
|
||||
assert(Std && "Should already be diagnosed");
|
||||
|
||||
LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc,
|
||||
Sema::LookupOrdinaryName);
|
||||
if (!S.LookupQualifiedName(Result, Std)) {
|
||||
// FIXME: <experimental/coroutine> should have been included already.
|
||||
// If we require it to include <new> then this diagnostic is no longer
|
||||
// needed.
|
||||
S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// FIXME: Mark the variable as ODR used. This currently does not work
|
||||
// likely due to the scope at in which this function is called.
|
||||
auto *VD = Result.getAsSingle<VarDecl>();
|
||||
if (!VD) {
|
||||
Result.suppressDiagnostics();
|
||||
// We found something weird. Complain about the first thing we found.
|
||||
NamedDecl *Found = *Result.begin();
|
||||
S.Diag(Found->getLocation(), diag::err_malformed_std_nothrow);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult DR = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, Loc);
|
||||
if (DR.isInvalid())
|
||||
return nullptr;
|
||||
|
||||
return DR.get();
|
||||
}
|
||||
|
||||
// Find an appropriate delete for the promise.
|
||||
static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
|
||||
QualType PromiseType) {
|
||||
@ -847,23 +880,53 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
|
||||
if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type))
|
||||
return false;
|
||||
|
||||
// FIXME: Add nothrow_t placement arg for global alloc
|
||||
// if ReturnStmtOnAllocFailure != nullptr.
|
||||
const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr;
|
||||
|
||||
// FIXME: Add support for stateful allocators.
|
||||
|
||||
FunctionDecl *OperatorNew = nullptr;
|
||||
FunctionDecl *OperatorDelete = nullptr;
|
||||
FunctionDecl *UnusedResult = nullptr;
|
||||
bool PassAlignment = false;
|
||||
SmallVector<Expr *, 1> PlacementArgs;
|
||||
|
||||
S.FindAllocationFunctions(Loc, SourceRange(),
|
||||
/*UseGlobal*/ false, PromiseType,
|
||||
/*isArray*/ false, PassAlignment,
|
||||
/*PlacementArgs*/ None, OperatorNew, UnusedResult);
|
||||
/*isArray*/ false, PassAlignment, PlacementArgs,
|
||||
OperatorNew, UnusedResult);
|
||||
|
||||
OperatorDelete = findDeleteForPromise(S, Loc, PromiseType);
|
||||
bool IsGlobalOverload =
|
||||
OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
|
||||
// If we didn't find a class-local new declaration and non-throwing new
|
||||
// was is required then we need to lookup the non-throwing global operator
|
||||
// instead.
|
||||
if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) {
|
||||
auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc);
|
||||
if (!StdNoThrow)
|
||||
return false;
|
||||
PlacementArgs = {StdNoThrow};
|
||||
OperatorNew = nullptr;
|
||||
S.FindAllocationFunctions(Loc, SourceRange(),
|
||||
/*UseGlobal*/ true, PromiseType,
|
||||
/*isArray*/ false, PassAlignment, PlacementArgs,
|
||||
OperatorNew, UnusedResult);
|
||||
}
|
||||
|
||||
if (!OperatorDelete || !OperatorNew)
|
||||
assert(OperatorNew && "expected definition of operator new to be found");
|
||||
|
||||
if (RequiresNoThrowAlloc) {
|
||||
const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>();
|
||||
if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) {
|
||||
S.Diag(OperatorNew->getLocation(),
|
||||
diag::err_coroutine_promise_new_requires_nothrow)
|
||||
<< OperatorNew;
|
||||
S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
|
||||
<< OperatorNew;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr)
|
||||
return false;
|
||||
|
||||
Expr *FramePtr =
|
||||
@ -879,8 +942,13 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
|
||||
if (NewRef.isInvalid())
|
||||
return false;
|
||||
|
||||
SmallVector<Expr *, 2> NewArgs(1, FrameSize);
|
||||
for (auto Arg : PlacementArgs)
|
||||
NewArgs.push_back(Arg);
|
||||
|
||||
ExprResult NewExpr =
|
||||
S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc);
|
||||
S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
|
||||
NewExpr = S.ActOnFinishFullExpr(NewExpr.get());
|
||||
if (NewExpr.isInvalid())
|
||||
return false;
|
||||
|
||||
@ -906,6 +974,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
|
||||
|
||||
ExprResult DeleteExpr =
|
||||
S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
|
||||
DeleteExpr = S.ActOnFinishFullExpr(DeleteExpr.get());
|
||||
if (DeleteExpr.isInvalid())
|
||||
return false;
|
||||
|
||||
|
@ -628,6 +628,9 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
|
||||
CXXScopeSpec *SS,
|
||||
ParsedType &SuggestedType,
|
||||
bool AllowClassTemplates) {
|
||||
// Don't report typename errors for editor placeholders.
|
||||
if (II->isEditorPlaceholder())
|
||||
return;
|
||||
// We don't have anything to suggest (yet).
|
||||
SuggestedType = nullptr;
|
||||
|
||||
@ -13674,6 +13677,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
|
||||
if (Attr)
|
||||
ProcessDeclAttributeList(S, New, Attr);
|
||||
AddPragmaAttributes(S, New);
|
||||
|
||||
// If this has an identifier, add it to the scope stack.
|
||||
if (TUK == TUK_Friend) {
|
||||
@ -15185,6 +15189,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
|
||||
|
||||
// Process attributes.
|
||||
if (Attr) ProcessDeclAttributeList(S, New, Attr);
|
||||
AddPragmaAttributes(S, New);
|
||||
|
||||
// Register this decl in the current scope stack.
|
||||
New->setAccess(TheEnumDecl->getAccess());
|
||||
|
@ -2398,10 +2398,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
||||
<< Platform->Ident;
|
||||
|
||||
NamedDecl *ND = dyn_cast<NamedDecl>(D);
|
||||
if (!ND) {
|
||||
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
|
||||
if (!ND) // We warned about this already, so just return.
|
||||
return;
|
||||
}
|
||||
|
||||
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
|
||||
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
|
||||
@ -2511,12 +2509,6 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
|
||||
assert(checkAttributeAtMostNumArgs(S, Attr, 3) &&
|
||||
"Invalid number of arguments in an external_source_symbol attribute");
|
||||
|
||||
if (!isa<NamedDecl>(D)) {
|
||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||
<< Attr.getName() << ExpectedNamedDecl;
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Language;
|
||||
if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0)))
|
||||
Language = SE->getString();
|
||||
@ -5765,18 +5757,21 @@ static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
|
||||
const AttributeList &Attr) {
|
||||
// Several attributes carry different semantics than the parsing requires, so
|
||||
// those are opted out of the common handling.
|
||||
// those are opted out of the common argument checks.
|
||||
//
|
||||
// We also bail on unknown and ignored attributes because those are handled
|
||||
// as part of the target-specific handling logic.
|
||||
if (Attr.hasCustomParsing() ||
|
||||
Attr.getKind() == AttributeList::UnknownAttribute)
|
||||
if (Attr.getKind() == AttributeList::UnknownAttribute)
|
||||
return false;
|
||||
|
||||
// Check whether the attribute requires specific language extensions to be
|
||||
// enabled.
|
||||
if (!Attr.diagnoseLangOpts(S))
|
||||
return true;
|
||||
// Check whether the attribute appertains to the given subject.
|
||||
if (!Attr.diagnoseAppertainsTo(S, D))
|
||||
return true;
|
||||
if (Attr.hasCustomParsing())
|
||||
return false;
|
||||
|
||||
if (Attr.getMinArgs() == Attr.getMaxArgs()) {
|
||||
// If there are no optional arguments, then checking for the argument count
|
||||
@ -5793,10 +5788,6 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check whether the attribute appertains to the given subject.
|
||||
if (!Attr.diagnoseAppertainsTo(S, D))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -6676,6 +6667,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
|
||||
// Finally, apply any attributes on the decl itself.
|
||||
if (const AttributeList *Attrs = PD.getAttributes())
|
||||
ProcessDeclAttributeList(S, D, Attrs);
|
||||
|
||||
// Apply additional attributes specified by '#pragma clang attribute'.
|
||||
AddPragmaAttributes(S, D);
|
||||
}
|
||||
|
||||
/// Is the given declaration allowed to use a forbidden type?
|
||||
|
@ -8445,6 +8445,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
||||
Namespc->setInvalidDecl();
|
||||
|
||||
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
|
||||
AddPragmaAttributes(DeclRegionScope, Namespc);
|
||||
|
||||
// FIXME: Should we be merging attributes?
|
||||
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
|
||||
@ -9931,6 +9932,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
|
||||
NewTD->setInvalidDecl();
|
||||
|
||||
ProcessDeclAttributeList(S, NewTD, AttrList);
|
||||
AddPragmaAttributes(S, NewTD);
|
||||
|
||||
CheckTypedefForVariablyModifiedType(S, NewTD);
|
||||
Invalid |= NewTD->isInvalidDecl();
|
||||
|
@ -993,6 +993,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
|
||||
|
||||
if (AttrList)
|
||||
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
|
||||
AddPragmaAttributes(TUScope, IDecl);
|
||||
PushOnScopeChains(IDecl, TUScope);
|
||||
|
||||
// Start the definition of this class. If we're in a redefinition case, there
|
||||
@ -1176,7 +1177,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
|
||||
|
||||
if (AttrList)
|
||||
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
|
||||
|
||||
AddPragmaAttributes(TUScope, PDecl);
|
||||
|
||||
// Merge attributes from previous declarations.
|
||||
if (PrevDecl)
|
||||
mergeDeclAttributes(PDecl, PrevDecl);
|
||||
@ -1706,7 +1708,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
|
||||
|
||||
if (attrList)
|
||||
ProcessDeclAttributeList(TUScope, PDecl, attrList);
|
||||
|
||||
AddPragmaAttributes(TUScope, PDecl);
|
||||
|
||||
if (PrevDecl)
|
||||
mergeDeclAttributes(PDecl, PrevDecl);
|
||||
|
||||
@ -1805,6 +1808,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||
|
||||
if (AttrList)
|
||||
ProcessDeclAttributeList(TUScope, CDecl, AttrList);
|
||||
AddPragmaAttributes(TUScope, CDecl);
|
||||
|
||||
CheckObjCDeclScope(CDecl);
|
||||
return ActOnObjCContainerStartDefinition(CDecl);
|
||||
@ -1954,6 +1958,7 @@ Decl *Sema::ActOnStartClassImplementation(
|
||||
ClassName, /*typeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr, ClassLoc,
|
||||
true);
|
||||
AddPragmaAttributes(TUScope, IDecl);
|
||||
IDecl->startDefinition();
|
||||
if (SDecl) {
|
||||
IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
|
||||
@ -3043,7 +3048,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||
ClassName, TypeParams, PrevIDecl,
|
||||
IdentLocs[i]);
|
||||
IDecl->setAtEndRange(IdentLocs[i]);
|
||||
|
||||
|
||||
PushOnScopeChains(IDecl, TUScope);
|
||||
CheckObjCDeclScope(IDecl);
|
||||
DeclsInGroup.push_back(IDecl);
|
||||
@ -4399,6 +4404,7 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||
|
||||
// Apply the attributes to the parameter.
|
||||
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
|
||||
AddPragmaAttributes(TUScope, Param);
|
||||
|
||||
if (Param->hasAttr<BlocksAttr>()) {
|
||||
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
|
||||
@ -4429,6 +4435,7 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||
|
||||
if (AttrList)
|
||||
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
|
||||
AddPragmaAttributes(TUScope, ObjCMethod);
|
||||
|
||||
// Add the method now.
|
||||
const ObjCMethodDecl *PrevMethod = nullptr;
|
||||
|
@ -2129,6 +2129,12 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
|
||||
IdentifierInfo *II = Name.getAsIdentifierInfo();
|
||||
SourceLocation NameLoc = NameInfo.getLoc();
|
||||
|
||||
if (II && II->isEditorPlaceholder()) {
|
||||
// FIXME: When typed placeholders are supported we can create a typed
|
||||
// placeholder expression node.
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// C++ [temp.dep.expr]p3:
|
||||
// An id-expression is type-dependent if it contains:
|
||||
// -- an identifier that was declared with a dependent type,
|
||||
|
@ -4068,7 +4068,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
|
||||
|
||||
// Build variables passed into runtime, necessary for worksharing directives.
|
||||
ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB;
|
||||
ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB;
|
||||
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
|
||||
isOpenMPDistributeDirective(DKind)) {
|
||||
// Lower bound variable, initialized with zero.
|
||||
@ -4116,8 +4116,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
// enclosing region. E.g. in 'distribute parallel for' the bounds obtained
|
||||
// by scheduling 'distribute' have to be passed to the schedule of 'for'.
|
||||
if (isOpenMPLoopBoundSharingDirective(DKind)) {
|
||||
auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
|
||||
|
||||
// Lower bound variable, initialized with zero.
|
||||
VarDecl *CombLBDecl =
|
||||
buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb");
|
||||
CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc);
|
||||
SemaRef.AddInitializerToDecl(
|
||||
CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
|
||||
/*DirectInit*/ false);
|
||||
|
||||
// Upper bound variable, initialized with last iteration number.
|
||||
VarDecl *CombUBDecl =
|
||||
buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub");
|
||||
CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc);
|
||||
SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(),
|
||||
/*DirectInit*/ false);
|
||||
|
||||
ExprResult CombIsUBGreater = SemaRef.BuildBinOp(
|
||||
CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get());
|
||||
ExprResult CombCondOp =
|
||||
SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(),
|
||||
LastIteration.get(), CombUB.get());
|
||||
CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(),
|
||||
CombCondOp.get());
|
||||
CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get());
|
||||
|
||||
auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
|
||||
// We expect to have at least 2 more parameters than the 'parallel'
|
||||
// directive does - the lower and upper bounds of the previous schedule.
|
||||
assert(CD->getNumParams() >= 4 &&
|
||||
@ -4139,7 +4163,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
|
||||
// Build the iteration variable and its initialization before loop.
|
||||
ExprResult IV;
|
||||
ExprResult Init;
|
||||
ExprResult Init, CombInit;
|
||||
{
|
||||
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv");
|
||||
IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc);
|
||||
@ -4150,6 +4174,18 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
|
||||
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
|
||||
Init = SemaRef.ActOnFinishFullExpr(Init.get());
|
||||
|
||||
if (isOpenMPLoopBoundSharingDirective(DKind)) {
|
||||
Expr *CombRHS =
|
||||
(isOpenMPWorksharingDirective(DKind) ||
|
||||
isOpenMPTaskLoopDirective(DKind) ||
|
||||
isOpenMPDistributeDirective(DKind))
|
||||
? CombLB.get()
|
||||
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
|
||||
CombInit =
|
||||
SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS);
|
||||
CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
|
||||
@ -4160,7 +4196,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
|
||||
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
|
||||
NumIterations.get());
|
||||
|
||||
ExprResult CombCond;
|
||||
if (isOpenMPLoopBoundSharingDirective(DKind)) {
|
||||
CombCond =
|
||||
SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
|
||||
}
|
||||
// Loop increment (IV = IV + 1)
|
||||
SourceLocation IncLoc;
|
||||
ExprResult Inc =
|
||||
@ -4175,7 +4215,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
|
||||
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
|
||||
// Used for directives with static scheduling.
|
||||
ExprResult NextLB, NextUB;
|
||||
// In combined construct, add combined version that use CombLB and CombUB
|
||||
// base variables for the update
|
||||
ExprResult NextLB, NextUB, CombNextLB, CombNextUB;
|
||||
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
|
||||
isOpenMPDistributeDirective(DKind)) {
|
||||
// LB + ST
|
||||
@ -4198,9 +4240,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get());
|
||||
if (!NextUB.isUsable())
|
||||
return 0;
|
||||
if (isOpenMPLoopBoundSharingDirective(DKind)) {
|
||||
CombNextLB =
|
||||
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get());
|
||||
if (!NextLB.isUsable())
|
||||
return 0;
|
||||
// LB = LB + ST
|
||||
CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(),
|
||||
CombNextLB.get());
|
||||
CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get());
|
||||
if (!CombNextLB.isUsable())
|
||||
return 0;
|
||||
// UB + ST
|
||||
CombNextUB =
|
||||
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get());
|
||||
if (!CombNextUB.isUsable())
|
||||
return 0;
|
||||
// UB = UB + ST
|
||||
CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(),
|
||||
CombNextUB.get());
|
||||
CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get());
|
||||
if (!CombNextUB.isUsable())
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create: increment expression for distribute loop when combined in a same
|
||||
// Create increment expression for distribute loop when combined in a same
|
||||
// directive with for as IV = IV + ST; ensure upper bound expression based
|
||||
// on PrevUB instead of NumIterations - used to implement 'for' when found
|
||||
// in combination with 'distribute', like in 'distribute parallel for'
|
||||
@ -4346,6 +4411,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
|
||||
Built.PrevUB = PrevUB.get();
|
||||
Built.DistInc = DistInc.get();
|
||||
Built.PrevEUB = PrevEUB.get();
|
||||
Built.DistCombinedFields.LB = CombLB.get();
|
||||
Built.DistCombinedFields.UB = CombUB.get();
|
||||
Built.DistCombinedFields.EUB = CombEUB.get();
|
||||
Built.DistCombinedFields.Init = CombInit.get();
|
||||
Built.DistCombinedFields.Cond = CombCond.get();
|
||||
Built.DistCombinedFields.NLB = CombNextLB.get();
|
||||
Built.DistCombinedFields.NUB = CombNextUB.get();
|
||||
|
||||
Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
|
||||
// Fill data for doacross depend clauses.
|
||||
|
@ -1783,6 +1783,7 @@ StmtResult
|
||||
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
|
||||
Stmt *First, Expr *collection,
|
||||
SourceLocation RParenLoc) {
|
||||
getCurFunction()->setHasBranchProtectedScope();
|
||||
|
||||
ExprResult CollectionExprResult =
|
||||
CheckObjCForCollectionOperand(ForLoc, collection);
|
||||
|
@ -1636,11 +1636,22 @@ struct ConvertConstructorToDeductionGuideTransform {
|
||||
transformFunctionTypeParam(ParmVarDecl *OldParam,
|
||||
MultiLevelTemplateArgumentList &Args) {
|
||||
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
|
||||
TypeSourceInfo *NewDI =
|
||||
Args.getNumLevels()
|
||||
? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
|
||||
OldParam->getDeclName())
|
||||
: OldDI;
|
||||
TypeSourceInfo *NewDI;
|
||||
if (!Args.getNumLevels())
|
||||
NewDI = OldDI;
|
||||
else if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
|
||||
// Expand out the one and only element in each inner pack.
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
|
||||
NewDI =
|
||||
SemaRef.SubstType(PackTL.getPatternLoc(), Args,
|
||||
OldParam->getLocation(), OldParam->getDeclName());
|
||||
if (!NewDI) return nullptr;
|
||||
NewDI =
|
||||
SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(),
|
||||
PackTL.getTypePtr()->getNumExpansions());
|
||||
} else
|
||||
NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
|
||||
OldParam->getDeclName());
|
||||
if (!NewDI)
|
||||
return nullptr;
|
||||
|
||||
|
@ -2605,10 +2605,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
||||
== TSK_ExplicitSpecialization)
|
||||
continue;
|
||||
|
||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
|
||||
if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
|
||||
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
|
||||
TSK == TSK_ExplicitInstantiationDeclaration) {
|
||||
// In MSVC mode, explicit instantiation decl of the outer class doesn't
|
||||
// affect the inner class.
|
||||
// In MSVC and Windows Itanium mode, explicit instantiation decl of the
|
||||
// outer class doesn't affect the inner class.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2578,6 +2578,13 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
|
||||
D->setPrevUpperBoundVariable(Record.readSubExpr());
|
||||
D->setDistInc(Record.readSubExpr());
|
||||
D->setPrevEnsureUpperBound(Record.readSubExpr());
|
||||
D->setCombinedLowerBoundVariable(Record.readSubExpr());
|
||||
D->setCombinedUpperBoundVariable(Record.readSubExpr());
|
||||
D->setCombinedEnsureUpperBound(Record.readSubExpr());
|
||||
D->setCombinedInit(Record.readSubExpr());
|
||||
D->setCombinedCond(Record.readSubExpr());
|
||||
D->setCombinedNextLowerBound(Record.readSubExpr());
|
||||
D->setCombinedNextUpperBound(Record.readSubExpr());
|
||||
}
|
||||
SmallVector<Expr *, 4> Sub;
|
||||
unsigned CollapsedNum = D->getCollapsedNumber();
|
||||
|
@ -2248,6 +2248,13 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
|
||||
Record.AddStmt(D->getPrevUpperBoundVariable());
|
||||
Record.AddStmt(D->getDistInc());
|
||||
Record.AddStmt(D->getPrevEnsureUpperBound());
|
||||
Record.AddStmt(D->getCombinedLowerBoundVariable());
|
||||
Record.AddStmt(D->getCombinedUpperBoundVariable());
|
||||
Record.AddStmt(D->getCombinedEnsureUpperBound());
|
||||
Record.AddStmt(D->getCombinedInit());
|
||||
Record.AddStmt(D->getCombinedCond());
|
||||
Record.AddStmt(D->getCombinedNextLowerBound());
|
||||
Record.AddStmt(D->getCombinedNextUpperBound());
|
||||
}
|
||||
for (auto I : D->counters()) {
|
||||
Record.AddStmt(I);
|
||||
|
@ -4,8 +4,8 @@ void testVLAwithSize(int s)
|
||||
{
|
||||
// CHECK: dbg.declare
|
||||
// CHECK: dbg.declare({{.*}}, metadata ![[VAR:.*]], metadata ![[EXPR:.*]])
|
||||
// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+2]]
|
||||
// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref)
|
||||
// CHECK: ![[EXPR]] = !DIExpression()
|
||||
// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+1]]
|
||||
int vla[s];
|
||||
int i;
|
||||
for (i = 0; i < s; i++) {
|
||||
|
18
test/CodeGen/fp-contract-on-asm.c
Normal file
18
test/CodeGen/fp-contract-on-asm.c
Normal file
@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -O3 -triple=aarch64-apple-ios -S -o - %s | FileCheck %s
|
||||
// REQUIRES: aarch64-registered-target
|
||||
|
||||
float fma_test1(float a, float b, float c) {
|
||||
#pragma STDC FP_CONTRACT ON
|
||||
// CHECK-LABEL: fma_test1:
|
||||
// CHECK: fmadd
|
||||
float x = a * b + c;
|
||||
return x;
|
||||
}
|
||||
|
||||
float fma_test2(float a, float b, float c) {
|
||||
// CHECK-LABEL: fma_test2:
|
||||
// CHECK: fmul
|
||||
// CHECK: fadd
|
||||
float x = a * b + c;
|
||||
return x;
|
||||
}
|
13
test/CodeGen/thinlto-backend-option.ll
Normal file
13
test/CodeGen/thinlto-backend-option.ll
Normal file
@ -0,0 +1,13 @@
|
||||
; Test to ensure -backend-options work when invoking the ThinLTO backend path.
|
||||
|
||||
; This test uses a non-existent backend option to test that backend options are
|
||||
; being parsed. While it's more important that the existing options are parsed
|
||||
; than that this error is produced, this provides a reliable way to test this
|
||||
; scenario independent of any particular backend options that may exist now or
|
||||
; in the future.
|
||||
|
||||
; RUN: %clang -flto=thin -c -o %t.o %s
|
||||
; RUN: llvm-lto -thinlto -o %t %t.o
|
||||
; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: clang: Unknown command line argument '-nonexistent'
|
21
test/CodeGenCXX/cxx1z-class-deduction.cpp
Normal file
21
test/CodeGenCXX/cxx1z-class-deduction.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
// RUN: %clang_cc1 -std=c++1z %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
|
||||
|
||||
template<typename T> struct A {
|
||||
A(T = 0);
|
||||
A(void*);
|
||||
};
|
||||
|
||||
template<typename T> A(T*) -> A<long>;
|
||||
A() -> A<int>;
|
||||
|
||||
// CHECK-LABEL: @_Z1fPi(
|
||||
void f(int *p) {
|
||||
// CHECK: @_ZN1AIiEC
|
||||
A a{};
|
||||
|
||||
// CHECK: @_ZN1AIlEC
|
||||
A b = p;
|
||||
|
||||
// CHECK: @_ZN1AIxEC
|
||||
A c = 123LL;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
// CHECK: ![[INCTYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "incomplete"
|
||||
// CHECK-SAME: DIFlagFwdDecl
|
||||
// CHECK: ![[EXPR]] = !DIExpression()
|
||||
|
||||
template<typename T> struct Identity {
|
||||
typedef T Type;
|
||||
@ -117,7 +118,6 @@ struct foo {
|
||||
// For some reason function arguments ended up down here
|
||||
// CHECK: ![[F]] = !DILocalVariable(name: "f", arg: 1, scope: ![[FUNC]]
|
||||
// CHECK-SAME: type: ![[FOO]]
|
||||
// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref)
|
||||
foo func(foo f) {
|
||||
return f; // reference 'f' for now because otherwise we hit another bug
|
||||
}
|
||||
|
@ -2,6 +2,20 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s --check-prefixes=CHECK,NULL
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment,null -DCHECK_LAMBDA | FileCheck %s --check-prefixes=LAMBDA
|
||||
|
||||
// CHECK-LABEL: define void @_Z22load_non_null_pointersv
|
||||
void load_non_null_pointers() {
|
||||
int var;
|
||||
var = *&var;
|
||||
|
||||
int arr[1];
|
||||
arr[0] = arr[0];
|
||||
|
||||
char c = "foo"[0];
|
||||
|
||||
// CHECK-NOT: icmp ne {{.*}}, null, !nosanitize
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
struct A {
|
||||
int foo;
|
||||
|
||||
@ -29,8 +43,7 @@ struct A {
|
||||
};
|
||||
f();
|
||||
|
||||
// LAMBDA: icmp ne %class.anon* %[[FUNCVAR:.*]], null, !nosanitize
|
||||
// LAMBDA: %[[LAMBDAINT:[0-9]+]] = ptrtoint %class.anon* %[[FUNCVAR]] to i64, !nosanitize
|
||||
// LAMBDA: %[[LAMBDAINT:[0-9]+]] = ptrtoint %class.anon* %[[FUNCVAR:.*]] to i64, !nosanitize
|
||||
// LAMBDA: and i64 %[[LAMBDAINT]], 7, !nosanitize
|
||||
// LAMBDA: call void @__ubsan_handle_type_mismatch
|
||||
|
||||
@ -127,8 +140,8 @@ struct A {
|
||||
struct B {
|
||||
operator A*() const { return nullptr; }
|
||||
|
||||
// CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEv
|
||||
static int load_member() {
|
||||
// CHECK-LABEL: define linkonce_odr i32 @_ZN1B11load_memberEPS_
|
||||
static int load_member(B *bp) {
|
||||
// Check &b before converting it to an A*.
|
||||
// CHECK: call void @__ubsan_handle_type_mismatch
|
||||
//
|
||||
@ -136,8 +149,7 @@ struct B {
|
||||
// NULL: call void @__ubsan_handle_type_mismatch
|
||||
//
|
||||
// CHECK-NOT: call void @__ubsan_handle_type_mismatch
|
||||
B b;
|
||||
return static_cast<A *>(b)->load_member();
|
||||
return static_cast<A *>(*bp)->load_member();
|
||||
// CHECK: ret i32
|
||||
}
|
||||
};
|
||||
@ -210,7 +222,7 @@ void force_irgen() {
|
||||
A::call_through_reference(*a);
|
||||
A::call_through_pointer(a);
|
||||
|
||||
B::load_member();
|
||||
B::load_member(nullptr);
|
||||
|
||||
Base *b = new Derived;
|
||||
b->load_member_1();
|
||||
@ -218,4 +230,6 @@ void force_irgen() {
|
||||
Derived *d;
|
||||
d->load_member_2();
|
||||
d->load_member_3();
|
||||
|
||||
load_non_null_pointers();
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user