aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-02-13 14:58:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-02-13 14:58:13 +0000
commitd4aec3a22f5b4c987be1c3815fdadbac72c6de5b (patch)
treea57d2c8ef3c5eaafb94bf394eb3dacdfeb6df08b
parentc2f1760e15d4e9e7a9eeadc99e8575fa1b2f7389 (diff)
downloadsrc-d4aec3a22f5b4c987be1c3815fdadbac72c6de5b.tar.gz
src-d4aec3a22f5b4c987be1c3815fdadbac72c6de5b.zip
Vendor import of clang release_38 branch r260756:vendor/clang/clang-release_38-r260756
Notes
Notes: svn path=/vendor/clang/dist/; revision=295592 svn path=/vendor/clang/clang-release_38-r260756/; revision=295593; tag=vendor/clang/clang-release_38-r260756
-rw-r--r--docs/AttributeReference.rst2034
-rw-r--r--docs/ReleaseNotes.rst75
-rw-r--r--docs/UndefinedBehaviorSanitizer.rst32
-rw-r--r--docs/UsersManual.rst12
-rw-r--r--include/clang/Sema/Sema.h20
-rw-r--r--lib/AST/ASTDiagnostic.cpp1367
-rw-r--r--lib/Basic/Targets.cpp6
-rw-r--r--lib/CodeGen/Address.h20
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp17
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp226
-rw-r--r--lib/Driver/ToolChains.cpp2
-rw-r--r--lib/Driver/Tools.cpp2
-rw-r--r--lib/Sema/SemaDeclCXX.cpp19
-rw-r--r--lib/Sema/SemaExpr.cpp290
-rw-r--r--lib/Sema/SemaExprObjC.cpp134
-rw-r--r--lib/Sema/SemaOverload.cpp25
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp53
-rw-r--r--test/CodeGenOpenCL/pipe_types.cl2
-rw-r--r--test/Driver/netbsd.c61
-rw-r--r--test/Driver/netbsd.cpp100
-rw-r--r--test/Misc/diag-template-diffing-color.cpp22
-rw-r--r--test/Misc/diag-template-diffing.cpp165
-rw-r--r--test/OpenMP/cancel_codegen.cpp14
-rw-r--r--test/OpenMP/cancellation_point_codegen.cpp26
-rw-r--r--test/OpenMP/parallel_sections_codegen.cpp11
-rw-r--r--test/OpenMP/sections_codegen.cpp16
-rw-r--r--test/OpenMP/sections_firstprivate_codegen.cpp19
-rw-r--r--test/OpenMP/sections_lastprivate_codegen.cpp29
-rw-r--r--test/OpenMP/sections_private_codegen.cpp12
-rw-r--r--test/OpenMP/sections_reduction_codegen.cpp15
-rw-r--r--test/Preprocessor/predefined-arch-macros.c8
-rw-r--r--test/SemaObjC/ovl-check.m55
32 files changed, 3741 insertions, 1148 deletions
diff --git a/docs/AttributeReference.rst b/docs/AttributeReference.rst
index a763ddeaeb10..4a3649de57a7 100644
--- a/docs/AttributeReference.rst
+++ b/docs/AttributeReference.rst
@@ -1,13 +1,2035 @@
..
-------------------------------------------------------------------
NOTE: This file is automatically generated by running clang-tblgen
- -gen-attr-docs. Do not edit this file by hand!! The contents for
- this file are automatically generated by a server-side process.
-
- Please do not commit this file. The file exists for local testing
- purposes only.
+ -gen-attr-docs. Do not edit this file by hand!!
-------------------------------------------------------------------
===================
Attributes in Clang
-=================== \ No newline at end of file
+===================
+.. contents::
+ :local:
+
+Introduction
+============
+
+This page lists the attributes currently supported by Clang.
+
+Function Attributes
+===================
+
+
+interrupt
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
+ARM targets. This attribute may be attached to a function definition and
+instructs the backend to generate appropriate function entry/exit code so that
+it can be used directly as an interrupt service routine.
+
+The parameter passed to the interrupt attribute is optional, but if
+provided it must be a string literal with one of the following values: "IRQ",
+"FIQ", "SWI", "ABORT", "UNDEF".
+
+The semantics are as follows:
+
+- If the function is AAPCS, Clang instructs the backend to realign the stack to
+ 8 bytes on entry. This is a general requirement of the AAPCS at public
+ interfaces, but may not hold when an exception is taken. Doing this allows
+ other AAPCS functions to be called.
+- If the CPU is M-class this is all that needs to be done since the architecture
+ itself is designed in such a way that functions obeying the normal AAPCS ABI
+ constraints are valid exception handlers.
+- If the CPU is not M-class, the prologue and epilogue are modified to save all
+ non-banked registers that are used, so that upon return the user-mode state
+ will not be corrupted. Note that to avoid unnecessary overhead, only
+ general-purpose (integer) registers are saved in this way. If VFP operations
+ are needed, that state must be saved manually.
+
+ Specifically, interrupt kinds other than "FIQ" will save all core registers
+ except "lr" and "sp". "FIQ" interrupts will save r0-r7.
+- If the CPU is not M-class, the return instruction is changed to one of the
+ canonical sequences permitted by the architecture for exception return. Where
+ possible the function itself will make the necessary "lr" adjustments so that
+ the "preferred return address" is selected.
+
+ Unfortunately the compiler is unable to make this guarantee for an "UNDEF"
+ handler, where the offset from "lr" to the preferred return address depends on
+ the execution state of the code which generated the exception. In this case
+ a sequence equivalent to "movs pc, lr" will be used.
+
+
+acquire_capability (acquire_shared_capability, clang::acquire_capability, clang::acquire_shared_capability)
+-----------------------------------------------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Marks a function as acquiring a capability.
+
+
+assert_capability (assert_shared_capability, clang::assert_capability, clang::assert_shared_capability)
+-------------------------------------------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Marks a function that dynamically tests whether a capability is held, and halts
+the program if it is not held.
+
+
+assume_aligned (gnu::assume_aligned)
+------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Use ``__attribute__((assume_aligned(<alignment>[,<offset>]))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) has the specified offset, in bytes, from an address with the
+specified alignment. The offset is taken to be zero if omitted.
+
+.. code-block:: c++
+
+ // The returned pointer value has 32-byte alignment.
+ void *a() __attribute__((assume_aligned (32)));
+
+ // The returned pointer value is 4 bytes greater than an address having
+ // 32-byte alignment.
+ void *b() __attribute__((assume_aligned (32, 4)));
+
+Note that this attribute provides information to the compiler regarding a
+condition that the code already ensures is true. It does not cause the compiler
+to enforce the provided alignment assumption.
+
+
+availability
+------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+The ``availability`` attribute can be placed on declarations to describe the
+lifecycle of that declaration relative to operating system versions. Consider
+the function declaration for a hypothetical function ``f``:
+
+.. code-block:: c++
+
+ void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
+
+The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
+deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
+is used by Clang to determine when it is safe to use ``f``: for example, if
+Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
+succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
+succeeds but Clang emits a warning specifying that the function is deprecated.
+Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
+fails because ``f()`` is no longer available.
+
+The availability attribute is a comma-separated list starting with the
+platform name and then including clauses specifying important milestones in the
+declaration's lifetime (in any order) along with additional information. Those
+clauses can be:
+
+introduced=\ *version*
+ The first version in which this declaration was introduced.
+
+deprecated=\ *version*
+ The first version in which this declaration was deprecated, meaning that
+ users should migrate away from this API.
+
+obsoleted=\ *version*
+ The first version in which this declaration was obsoleted, meaning that it
+ was removed completely and can no longer be used.
+
+unavailable
+ This declaration is never available on this platform.
+
+message=\ *string-literal*
+ Additional message text that Clang will provide when emitting a warning or
+ error about use of a deprecated or obsoleted declaration. Useful to direct
+ users to replacement APIs.
+
+Multiple availability attributes can be placed on a declaration, which may
+correspond to different platforms. Only the availability attribute with the
+platform corresponding to the target platform will be used; any others will be
+ignored. If no availability attribute specifies availability for the current
+target platform, the availability attributes are ignored. Supported platforms
+are:
+
+``ios``
+ Apple's iOS operating system. The minimum deployment target is specified by
+ the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*``
+ command-line arguments.
+
+``macosx``
+ Apple's Mac OS X operating system. The minimum deployment target is
+ specified by the ``-mmacosx-version-min=*version*`` command-line argument.
+
+``tvos``
+ Apple's tvOS operating system. The minimum deployment target is specified by
+ the ``-mtvos-version-min=*version*`` command-line argument.
+
+``watchos``
+ Apple's watchOS operating system. The minimum deployment target is specified by
+ the ``-mwatchos-version-min=*version*`` command-line argument.
+
+A declaration can be used even when deploying back to a platform version prior
+to when the declaration was introduced. When this happens, the declaration is
+`weakly linked
+<https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html>`_,
+as if the ``weak_import`` attribute were added to the declaration. A
+weakly-linked declaration may or may not be present a run-time, and a program
+can determine whether the declaration is present by checking whether the
+address of that declaration is non-NULL.
+
+If there are multiple declarations of the same entity, the availability
+attributes must either match on a per-platform basis or later
+declarations must not have availability attributes for that
+platform. For example:
+
+.. code-block:: c
+
+ void g(void) __attribute__((availability(macosx,introduced=10.4)));
+ void g(void) __attribute__((availability(macosx,introduced=10.4))); // okay, matches
+ void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform
+ void g(void); // okay, inherits both macosx and ios availability from above.
+ void g(void) __attribute__((availability(macosx,introduced=10.5))); // error: mismatch
+
+When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,:
+
+.. code-block:: objc
+
+ @interface A
+ - (id)method __attribute__((availability(macosx,introduced=10.4)));
+ - (id)method2 __attribute__((availability(macosx,introduced=10.4)));
+ @end
+
+ @interface B : A
+ - (id)method __attribute__((availability(macosx,introduced=10.3))); // okay: method moved into base class later
+ - (id)method __attribute__((availability(macosx,introduced=10.5))); // error: this method was available via the base class in 10.4
+ @end
+
+
+_Noreturn
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+A function declared as ``_Noreturn`` shall not return to its caller. The
+compiler will generate a diagnostic for a function declared as ``_Noreturn``
+that appears to be capable of returning to its caller.
+
+
+noreturn
+--------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","X","","", ""
+
+A function declared as ``[[noreturn]]`` shall not return to its caller. The
+compiler will generate a diagnostic for a function declared as ``[[noreturn]]``
+that appears to be capable of returning to its caller.
+
+
+carries_dependency
+------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``carries_dependency`` attribute specifies dependency propagation into and
+out of functions.
+
+When specified on a function or Objective-C method, the ``carries_dependency``
+attribute means that the return value carries a dependency out of the function,
+so that the implementation need not constrain ordering upon return from that
+function. Implementations of the function and its caller may choose to preserve
+dependencies instead of emitting memory ordering instructions such as fences.
+
+Note, this attribute does not change the meaning of the program, but may result
+in generation of more efficient code.
+
+
+disable_tail_calls (clang::disable_tail_calls)
+----------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function.
+
+For example:
+
+ .. code-block:: c
+
+ int callee(int);
+
+ int foo(int a) __attribute__((disable_tail_calls)) {
+ return callee(a); // This call is not tail-call optimized.
+ }
+
+Marking virtual functions as ``disable_tail_calls`` is legal.
+
+ .. code-block: c++
+
+ int callee(int);
+
+ class Base {
+ public:
+ [[clang::disable_tail_calls]] virtual int foo1() {
+ return callee(); // This call is not tail-call optimized.
+ }
+ };
+
+ class Derived1 : public Base {
+ public:
+ int foo1() override {
+ return callee(); // This call is tail-call optimized.
+ }
+ };
+
+
+enable_if
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+.. Note:: Some features of this attribute are experimental. The meaning of
+ multiple enable_if attributes on a single declaration is subject to change in
+ a future version of clang. Also, the ABI is not standardized and the name
+ mangling may change in future versions. To avoid that, use asm labels.
+
+The ``enable_if`` attribute can be placed on function declarations to control
+which overload is selected based on the values of the function's arguments.
+When combined with the ``overloadable`` attribute, this feature is also
+available in C.
+
+.. code-block:: c++
+
+ int isdigit(int c);
+ int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF")));
+
+ void foo(char c) {
+ isdigit(c);
+ isdigit(10);
+ isdigit(-10); // results in a compile-time error.
+ }
+
+The enable_if attribute takes two arguments, the first is an expression written
+in terms of the function parameters, the second is a string explaining why this
+overload candidate could not be selected to be displayed in diagnostics. The
+expression is part of the function signature for the purposes of determining
+whether it is a redeclaration (following the rules used when determining
+whether a C++ template specialization is ODR-equivalent), but is not part of
+the type.
+
+The enable_if expression is evaluated as if it were the body of a
+bool-returning constexpr function declared with the arguments of the function
+it is being applied to, then called with the parameters at the call site. If the
+result is false or could not be determined through constant expression
+evaluation, then this overload will not be chosen and the provided string may
+be used in a diagnostic if the compile fails as a result.
+
+Because the enable_if expression is an unevaluated context, there are no global
+state changes, nor the ability to pass information from the enable_if
+expression to the function body. For example, suppose we want calls to
+strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of
+strbuf) only if the size of strbuf can be determined:
+
+.. code-block:: c++
+
+ __attribute__((always_inline))
+ static inline size_t strnlen(const char *s, size_t maxlen)
+ __attribute__((overloadable))
+ __attribute__((enable_if(__builtin_object_size(s, 0) != -1))),
+ "chosen when the buffer size is known but 'maxlen' is not")))
+ {
+ return strnlen_chk(s, maxlen, __builtin_object_size(s, 0));
+ }
+
+Multiple enable_if attributes may be applied to a single declaration. In this
+case, the enable_if expressions are evaluated from left to right in the
+following manner. First, the candidates whose enable_if expressions evaluate to
+false or cannot be evaluated are discarded. If the remaining candidates do not
+share ODR-equivalent enable_if expressions, the overload resolution is
+ambiguous. Otherwise, enable_if overload resolution continues with the next
+enable_if attribute on the candidates that have not been discarded and have
+remaining enable_if attributes. In this way, we pick the most specific
+overload out of a number of viable overloads using enable_if.
+
+.. code-block:: c++
+
+ void f() __attribute__((enable_if(true, ""))); // #1
+ void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2
+
+ void g(int i, int j) __attribute__((enable_if(i, ""))); // #1
+ void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2
+
+In this example, a call to f() is always resolved to #2, as the first enable_if
+expression is ODR-equivalent for both declarations, but #1 does not have another
+enable_if expression to continue evaluating, so the next round of evaluation has
+only a single candidate. In a call to g(1, 1), the call is ambiguous even though
+#2 has more enable_if attributes, because the first enable_if expressions are
+not ODR-equivalent.
+
+Query for this feature with ``__has_attribute(enable_if)``.
+
+
+flatten (gnu::flatten)
+----------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``flatten`` attribute causes calls within the attributed function to
+be inlined unless it is impossible to do so, for example if the body of the
+callee is unavailable or if the callee has the ``noinline`` attribute.
+
+
+format (gnu::format)
+--------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Clang supports the ``format`` attribute, which indicates that the function
+accepts a ``printf`` or ``scanf``-like format string and corresponding
+arguments or a ``va_list`` that contains these arguments.
+
+Please see `GCC documentation about format attribute
+<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details
+about attribute syntax.
+
+Clang implements two kinds of checks with this attribute.
+
+#. Clang checks that the function with the ``format`` attribute is called with
+ a format string that uses format specifiers that are allowed, and that
+ arguments match the format string. This is the ``-Wformat`` warning, it is
+ on by default.
+
+#. Clang checks that the format string argument is a literal string. This is
+ the ``-Wformat-nonliteral`` warning, it is off by default.
+
+ Clang implements this mostly the same way as GCC, but there is a difference
+ for functions that accept a ``va_list`` argument (for example, ``vprintf``).
+ GCC does not emit ``-Wformat-nonliteral`` warning for calls to such
+ functions. Clang does not warn if the format string comes from a function
+ parameter, where the function is annotated with a compatible attribute,
+ otherwise it warns. For example:
+
+ .. code-block:: c
+
+ __attribute__((__format__ (__scanf__, 1, 3)))
+ void foo(const char* s, char *buf, ...) {
+ va_list ap;
+ va_start(ap, buf);
+
+ vprintf(s, ap); // warning: format string is not a string literal
+ }
+
+ In this case we warn because ``s`` contains a format string for a
+ ``scanf``-like function, but it is passed to a ``printf``-like function.
+
+ If the attribute is removed, clang still warns, because the format string is
+ not a string literal.
+
+ Another example:
+
+ .. code-block:: c
+
+ __attribute__((__format__ (__printf__, 1, 3)))
+ void foo(const char* s, char *buf, ...) {
+ va_list ap;
+ va_start(ap, buf);
+
+ vprintf(s, ap); // warning
+ }
+
+ In this case Clang does not warn because the format string ``s`` and
+ the corresponding arguments are annotated. If the arguments are
+ incorrect, the caller of ``foo`` will receive a warning.
+
+
+internal_linkage (clang::internal_linkage)
+------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``internal_linkage`` attribute changes the linkage type of the declaration to internal.
+This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition,
+this attribute affects all methods and static data members of that class.
+This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables.
+
+
+interrupt
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
+MIPS targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+By default, the compiler will produce a function prologue and epilogue suitable for
+an interrupt service routine that handles an External Interrupt Controller (eic)
+generated interrupt. This behaviour can be explicitly requested with the "eic"
+argument.
+
+Otherwise, for use with vectored interrupt mode, the argument passed should be
+of the form "vector=LEVEL" where LEVEL is one of the following values:
+"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will
+then set the interrupt mask to the corresponding level which will mask all
+interrupts up to and including the argument.
+
+The semantics are as follows:
+
+- The prologue is modified so that the Exception Program Counter (EPC) and
+ Status coprocessor registers are saved to the stack. The interrupt mask is
+ set so that the function can only be interrupted by a higher priority
+ interrupt. The epilogue will restore the previous values of EPC and Status.
+
+- The prologue and epilogue are modified to save and restore all non-kernel
+ registers as necessary.
+
+- The FPU is disabled in the prologue, as the floating pointer registers are not
+ spilled to the stack.
+
+- The function return sequence is changed to use an exception return instruction.
+
+- The parameter sets the interrupt mask for the function corresponding to the
+ interrupt level specified. If no mask is specified the interrupt mask
+ defaults to "eic".
+
+
+noalias
+-------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","X","", ""
+
+The ``noalias`` attribute indicates that the only memory accesses inside
+function are loads and stores from objects pointed to by its pointer-typed
+arguments, with arbitrary offsets.
+
+
+noduplicate (clang::noduplicate)
+--------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``noduplicate`` attribute can be placed on function declarations to control
+whether function calls to this function can be duplicated or not as a result of
+optimizations. This is required for the implementation of functions with
+certain special requirements, like the OpenCL "barrier" function, that might
+need to be run concurrently by all the threads that are executing in lockstep
+on the hardware. For example this attribute applied on the function
+"nodupfunc" in the code below avoids that:
+
+.. code-block:: c
+
+ void nodupfunc() __attribute__((noduplicate));
+ // Setting it as a C++11 attribute is also valid
+ // void nodupfunc() [[clang::noduplicate]];
+ void foo();
+ void bar();
+
+ nodupfunc();
+ if (a > n) {
+ foo();
+ } else {
+ bar();
+ }
+
+gets possibly modified by some optimizations into code similar to this:
+
+.. code-block:: c
+
+ if (a > n) {
+ nodupfunc();
+ foo();
+ } else {
+ nodupfunc();
+ bar();
+ }
+
+where the call to "nodupfunc" is duplicated and sunk into the two branches
+of the condition.
+
+
+no_sanitize (clang::no_sanitize)
+--------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Use the ``no_sanitize`` attribute on a function declaration to specify
+that a particular instrumentation or set of instrumentations should not be
+applied to that function. The attribute takes a list of string literals,
+which have the same meaning as values accepted by the ``-fno-sanitize=``
+flag. For example, ``__attribute__((no_sanitize("address", "thread")))``
+specifies that AddressSanitizer and ThreadSanitizer should not be applied
+to the function.
+
+See :ref:`Controlling Code Generation <controlling-code-generation>` for a
+full list of supported sanitizer flags.
+
+
+no_sanitize_address (no_address_safety_analysis, gnu::no_address_safety_analysis, gnu::no_sanitize_address)
+-----------------------------------------------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+.. _langext-address_sanitizer:
+
+Use ``__attribute__((no_sanitize_address))`` on a function declaration to
+specify that address safety instrumentation (e.g. AddressSanitizer) should
+not be applied to that function.
+
+
+no_sanitize_thread
+------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+.. _langext-thread_sanitizer:
+
+Use ``__attribute__((no_sanitize_thread))`` on a function declaration to
+specify that checks for data races on plain (non-atomic) memory accesses should
+not be inserted by ThreadSanitizer. The function is still instrumented by the
+tool to avoid false positives and provide meaningful stack traces.
+
+
+no_sanitize_memory
+------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+.. _langext-memory_sanitizer:
+
+Use ``__attribute__((no_sanitize_memory))`` on a function declaration to
+specify that checks for uninitialized memory should not be inserted
+(e.g. by MemorySanitizer). The function may still be instrumented by the tool
+to avoid false positives in other places.
+
+
+no_split_stack (gnu::no_split_stack)
+------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``no_split_stack`` attribute disables the emission of the split stack
+preamble for a particular function. It has no effect if ``-fsplit-stack``
+is not specified.
+
+
+not_tail_called (clang::not_tail_called)
+----------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``.
+
+For example, it prevents tail-call optimization in the following case:
+
+ .. code-block: c
+
+ int __attribute__((not_tail_called)) foo1(int);
+
+ int foo2(int a) {
+ return foo1(a); // No tail-call optimization on direct calls.
+ }
+
+However, it doesn't prevent tail-call optimization in this case:
+
+ .. code-block: c
+
+ int __attribute__((not_tail_called)) foo1(int);
+
+ int foo2(int a) {
+ int (*fn)(int) = &foo1;
+
+ // not_tail_called has no effect on an indirect call even if the call can be
+ // resolved at compile time.
+ return (*fn)(a);
+ }
+
+Marking virtual functions as ``not_tail_called`` is an error:
+
+ .. code-block: c++
+
+ class Base {
+ public:
+ // not_tail_called on a virtual function is an error.
+ [[clang::not_tail_called]] virtual int foo1();
+
+ virtual int foo2();
+
+ // Non-virtual functions can be marked ``not_tail_called``.
+ [[clang::not_tail_called]] int foo3();
+ };
+
+ class Derived1 : public Base {
+ public:
+ int foo1() override;
+
+ // not_tail_called on a virtual function is an error.
+ [[clang::not_tail_called]] int foo2() override;
+ };
+
+
+objc_boxable
+------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Structs and unions marked with the ``objc_boxable`` attribute can be used
+with the Objective-C boxed expression syntax, ``@(...)``.
+
+**Usage**: ``__attribute__((objc_boxable))``. This attribute
+can only be placed on a declaration of a trivially-copyable struct or union:
+
+.. code-block:: objc
+
+ struct __attribute__((objc_boxable)) some_struct {
+ int i;
+ };
+ union __attribute__((objc_boxable)) some_union {
+ int i;
+ float f;
+ };
+ typedef struct __attribute__((objc_boxable)) _some_struct some_struct;
+
+ // ...
+
+ some_struct ss;
+ NSValue *boxed = @(ss);
+
+
+objc_method_family
+------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Many methods in Objective-C have conventional meanings determined by their
+selectors. It is sometimes useful to be able to mark a method as having a
+particular conventional meaning despite not having the right selector, or as
+not having the conventional meaning that its selector would suggest. For these
+use cases, we provide an attribute to specifically describe the "method family"
+that a method belongs to.
+
+**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of
+``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This
+attribute can only be placed at the end of a method declaration:
+
+.. code-block:: objc
+
+ - (NSString *)initMyStringValue __attribute__((objc_method_family(none)));
+
+Users who do not wish to change the conventional meaning of a method, and who
+merely want to document its non-standard retain and release semantics, should
+use the retaining behavior attributes (``ns_returns_retained``,
+``ns_returns_not_retained``, etc).
+
+Query for this feature with ``__has_attribute(objc_method_family)``.
+
+
+objc_requires_super
+-------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Some Objective-C classes allow a subclass to override a particular method in a
+parent class but expect that the overriding method also calls the overridden
+method in the parent class. For these cases, we provide an attribute to
+designate that a method requires a "call to ``super``" in the overriding
+method in the subclass.
+
+**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only
+be placed at the end of a method declaration:
+
+.. code-block:: objc
+
+ - (void)foo __attribute__((objc_requires_super));
+
+This attribute can only be applied the method declarations within a class, and
+not a protocol. Currently this attribute does not enforce any placement of
+where the call occurs in the overriding method (such as in the case of
+``-dealloc`` where the call must appear at the end). It checks only that it
+exists.
+
+Note that on both OS X and iOS that the Foundation framework provides a
+convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this
+attribute:
+
+.. code-block:: objc
+
+ - (void)foo NS_REQUIRES_SUPER;
+
+This macro is conditionally defined depending on the compiler's support for
+this attribute. If the compiler does not support the attribute the macro
+expands to nothing.
+
+Operationally, when a method has this annotation the compiler will warn if the
+implementation of an override in a subclass does not call super. For example:
+
+.. code-block:: objc
+
+ warning: method possibly missing a [super AnnotMeth] call
+ - (void) AnnotMeth{};
+ ^
+
+
+objc_runtime_name
+-----------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+By default, the Objective-C interface or protocol identifier is used
+in the metadata name for that object. The `objc_runtime_name`
+attribute allows annotated interfaces or protocols to use the
+specified string argument in the object's metadata name instead of the
+default name.
+
+**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute
+can only be placed before an @protocol or @interface declaration:
+
+.. code-block:: objc
+
+ __attribute__((objc_runtime_name("MyLocalName")))
+ @interface Message
+ @end
+
+
+optnone (clang::optnone)
+------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``optnone`` attribute suppresses essentially all optimizations
+on a function or method, regardless of the optimization level applied to
+the compilation unit as a whole. This is particularly useful when you
+need to debug a particular function, but it is infeasible to build the
+entire application without optimization. Avoiding optimization on the
+specified function can improve the quality of the debugging information
+for that function.
+
+This attribute is incompatible with the ``always_inline`` and ``minsize``
+attributes.
+
+
+overloadable
+------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang provides support for C++ function overloading in C. Function overloading
+in C is introduced using the ``overloadable`` attribute. For example, one
+might provide several overloaded versions of a ``tgsin`` function that invokes
+the appropriate standard function computing the sine of a value with ``float``,
+``double``, or ``long double`` precision:
+
+.. code-block:: c
+
+ #include <math.h>
+ float __attribute__((overloadable)) tgsin(float x) { return sinf(x); }
+ double __attribute__((overloadable)) tgsin(double x) { return sin(x); }
+ long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); }
+
+Given these declarations, one can call ``tgsin`` with a ``float`` value to
+receive a ``float`` result, with a ``double`` to receive a ``double`` result,
+etc. Function overloading in C follows the rules of C++ function overloading
+to pick the best overload given the call arguments, with a few C-specific
+semantics:
+
+* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a
+ floating-point promotion (per C99) rather than as a floating-point conversion
+ (as in C++).
+
+* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is
+ considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are
+ compatible types.
+
+* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T``
+ and ``U`` are compatible types. This conversion is given "conversion" rank.
+
+The declaration of ``overloadable`` functions is restricted to function
+declarations and definitions. Most importantly, if any function with a given
+name is given the ``overloadable`` attribute, then all function declarations
+and definitions with that name (and in that scope) must have the
+``overloadable`` attribute. This rule even applies to redeclarations of
+functions whose original declaration had the ``overloadable`` attribute, e.g.,
+
+.. code-block:: c
+
+ int f(int) __attribute__((overloadable));
+ float f(float); // error: declaration of "f" must have the "overloadable" attribute
+
+ int g(int) __attribute__((overloadable));
+ int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
+
+Functions marked ``overloadable`` must have prototypes. Therefore, the
+following code is ill-formed:
+
+.. code-block:: c
+
+ int h() __attribute__((overloadable)); // error: h does not have a prototype
+
+However, ``overloadable`` functions are allowed to use a ellipsis even if there
+are no named parameters (as is permitted in C++). This feature is particularly
+useful when combined with the ``unavailable`` attribute:
+
+.. code-block:: c++
+
+ void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error
+
+Functions declared with the ``overloadable`` attribute have their names mangled
+according to the same rules as C++ function names. For example, the three
+``tgsin`` functions in our motivating example get the mangled names
+``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two
+caveats to this use of name mangling:
+
+* Future versions of Clang may change the name mangling of functions overloaded
+ in C, so you should not depend on an specific mangling. To be completely
+ safe, we strongly urge the use of ``static inline`` with ``overloadable``
+ functions.
+
+* The ``overloadable`` attribute has almost no meaning when used in C++,
+ because names will already be mangled and functions are already overloadable.
+ However, when an ``overloadable`` function occurs within an ``extern "C"``
+ linkage specification, it's name *will* be mangled in the same way as it
+ would in C.
+
+Query for this feature with ``__has_extension(attribute_overloadable)``.
+
+
+release_capability (release_shared_capability, clang::release_capability, clang::release_shared_capability)
+-----------------------------------------------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Marks a function as releasing a capability.
+
+
+target (gnu::target)
+--------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute.
+This attribute may be attached to a function definition and instructs
+the backend to use different code generation options than were passed on the
+command line.
+
+The current set of options correspond to the existing "subtarget features" for
+the target with or without a "-mno-" in front corresponding to the absence
+of the feature, as well as ``arch="CPU"`` which will change the default "CPU"
+for the function.
+
+Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2",
+"avx", "xop" and largely correspond to the machine specific options handled by
+the front end.
+
+
+try_acquire_capability (try_acquire_shared_capability, clang::try_acquire_capability, clang::try_acquire_shared_capability)
+---------------------------------------------------------------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+Marks a function that attempts to acquire a capability. This function may fail to
+actually acquire the capability; they accept a Boolean value determining
+whether acquiring the capability means success (true), or failing to acquire
+the capability means success (false).
+
+
+Variable Attributes
+===================
+
+
+init_seg
+--------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","", "X"
+
+The attribute applied by ``pragma init_seg()`` controls the section into
+which global initialization function pointers are emitted. It is only
+available with ``-fms-extensions``. Typically, this function pointer is
+emitted into ``.CRT$XCU`` on Windows. The user can change the order of
+initialization by using a different section name with the same
+``.CRT$XC`` prefix and a suffix that sorts lexicographically before or
+after the standard ``.CRT$XCU`` sections. See the init_seg_
+documentation on MSDN for more information.
+
+.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx
+
+
+pass_object_size
+----------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+.. Note:: The mangling of functions with parameters that are annotated with
+ ``pass_object_size`` is subject to change. You can get around this by
+ using ``__asm__("foo")`` to explicitly name your functions, thus preserving
+ your ABI; also, non-overloadable C functions with ``pass_object_size`` are
+ not mangled.
+
+The ``pass_object_size(Type)`` attribute can be placed on function parameters to
+instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite
+of said function, and implicitly pass the result of this call in as an invisible
+argument of type ``size_t`` directly after the parameter annotated with
+``pass_object_size``. Clang will also replace any calls to
+``__builtin_object_size(param, Type)`` in the function by said implicit
+parameter.
+
+Example usage:
+
+.. code-block:: c
+
+ int bzero1(char *const p __attribute__((pass_object_size(0))))
+ __attribute__((noinline)) {
+ int i = 0;
+ for (/**/; i < (int)__builtin_object_size(p, 0); ++i) {
+ p[i] = 0;
+ }
+ return i;
+ }
+
+ int main() {
+ char chars[100];
+ int n = bzero1(&chars[0]);
+ assert(n == sizeof(chars));
+ return 0;
+ }
+
+If successfully evaluating ``__builtin_object_size(param, Type)`` at the
+callsite is not possible, then the "failed" value is passed in. So, using the
+definition of ``bzero1`` from above, the following code would exit cleanly:
+
+.. code-block:: c
+
+ int main2(int argc, char *argv[]) {
+ int n = bzero1(argv);
+ assert(n == -1);
+ return 0;
+ }
+
+``pass_object_size`` plays a part in overload resolution. If two overload
+candidates are otherwise equally good, then the overload with one or more
+parameters with ``pass_object_size`` is preferred. This implies that the choice
+between two identical overloads both with ``pass_object_size`` on one or more
+parameters will always be ambiguous; for this reason, having two such overloads
+is illegal. For example:
+
+.. code-block:: c++
+
+ #define PS(N) __attribute__((pass_object_size(N)))
+ // OK
+ void Foo(char *a, char *b); // Overload A
+ // OK -- overload A has no parameters with pass_object_size.
+ void Foo(char *a PS(0), char *b PS(0)); // Overload B
+ // Error -- Same signature (sans pass_object_size) as overload B, and both
+ // overloads have one or more parameters with the pass_object_size attribute.
+ void Foo(void *a PS(0), void *b);
+
+ // OK
+ void Bar(void *a PS(0)); // Overload C
+ // OK
+ void Bar(char *c PS(1)); // Overload D
+
+ void main() {
+ char known[10], *unknown;
+ Foo(unknown, unknown); // Calls overload B
+ Foo(known, unknown); // Calls overload B
+ Foo(unknown, known); // Calls overload B
+ Foo(known, known); // Calls overload B
+
+ Bar(known); // Calls overload D
+ Bar(unknown); // Calls overload D
+ }
+
+Currently, ``pass_object_size`` is a bit restricted in terms of its usage:
+
+* Only one use of ``pass_object_size`` is allowed per parameter.
+
+* It is an error to take the address of a function with ``pass_object_size`` on
+ any of its parameters. If you wish to do this, you can create an overload
+ without ``pass_object_size`` on any parameters.
+
+* It is an error to apply the ``pass_object_size`` attribute to parameters that
+ are not pointers. Additionally, any parameter that ``pass_object_size`` is
+ applied to must be marked ``const`` at its function's definition.
+
+
+section (gnu::section, __declspec(allocate))
+--------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","X","", ""
+
+The ``section`` attribute allows you to specify a specific section a
+global variable or function should be in after translation.
+
+
+tls_model (gnu::tls_model)
+--------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``tls_model`` attribute allows you to specify which thread-local storage
+model to use. It accepts the following strings:
+
+* global-dynamic
+* local-dynamic
+* initial-exec
+* local-exec
+
+TLS models are mutually exclusive.
+
+
+thread
+------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","X","", ""
+
+The ``__declspec(thread)`` attribute declares a variable with thread local
+storage. It is available under the ``-fms-extensions`` flag for MSVC
+compatibility. See the documentation for `__declspec(thread)`_ on MSDN.
+
+.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
+
+In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the
+GNU ``__thread`` keyword. The variable must not have a destructor and must have
+a constant initializer, if any. The attribute only applies to variables
+declared with static storage duration, such as globals, class static data
+members, and static locals.
+
+
+Type Attributes
+===============
+
+
+align_value
+-----------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+The align_value attribute can be added to the typedef of a pointer type or the
+declaration of a variable of pointer or reference type. It specifies that the
+pointer will point to, or the reference will bind to, only objects with at
+least the provided alignment. This alignment value must be some positive power
+of 2.
+
+ .. code-block:: c
+
+ typedef double * aligned_double_ptr __attribute__((align_value(64)));
+ void foo(double & x __attribute__((align_value(128)),
+ aligned_double_ptr y) { ... }
+
+If the pointer value does not have the specified alignment at runtime, the
+behavior of the program is undefined.
+
+
+flag_enum
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+This attribute can be added to an enumerator to signal to the compiler that it
+is intended to be used as a flag type. This will cause the compiler to assume
+that the range of the type includes all of the values that you can get by
+manipulating bits of the enumerator when issuing warnings.
+
+
+__single_inhertiance, __multiple_inheritance, __virtual_inheritance
+-------------------------------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+This collection of keywords is enabled under ``-fms-extensions`` and controls
+the pointer-to-member representation used on ``*-*-win32`` targets.
+
+The ``*-*-win32`` targets utilize a pointer-to-member representation which
+varies in size and alignment depending on the definition of the underlying
+class.
+
+However, this is problematic when a forward declaration is only available and
+no definition has been made yet. In such cases, Clang is forced to utilize the
+most general representation that is available to it.
+
+These keywords make it possible to use a pointer-to-member representation other
+than the most general one regardless of whether or not the definition will ever
+be present in the current translation unit.
+
+This family of keywords belong between the ``class-key`` and ``class-name``:
+
+.. code-block:: c++
+
+ struct __single_inheritance S;
+ int S::*i;
+ struct S {};
+
+This keyword can be applied to class templates but only has an effect when used
+on full specializations:
+
+.. code-block:: c++
+
+ template <typename T, typename U> struct __single_inheritance A; // warning: inheritance model ignored on primary template
+ template <typename T> struct __multiple_inheritance A<T, T>; // warning: inheritance model ignored on partial specialization
+ template <> struct __single_inheritance A<int, float>;
+
+Note that choosing an inheritance model less general than strictly necessary is
+an error:
+
+.. code-block:: c++
+
+ struct __multiple_inheritance S; // error: inheritance model does not match definition
+ int S::*i;
+ struct S {};
+
+
+novtable
+--------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","X","", ""
+
+This attribute can be added to a class declaration or definition to signal to
+the compiler that constructors and destructors will not reference the virtual
+function table. It is only supported when using the Microsoft C++ ABI.
+
+
+Statement Attributes
+====================
+
+
+fallthrough (clang::fallthrough)
+--------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","X","","", ""
+
+The ``clang::fallthrough`` attribute is used along with the
+``-Wimplicit-fallthrough`` argument to annotate intentional fall-through
+between switch labels. It can only be applied to a null statement placed at a
+point of execution between any statement and the next switch label. It is
+common to mark these places with a specific comment, but this attribute is
+meant to replace comments with a more strict annotation, which can be checked
+by the compiler. This attribute doesn't change semantics of the code and can
+be used wherever an intended fall-through occurs. It is designed to mimic
+control-flow statements like ``break;``, so it can be placed in most places
+where ``break;`` can, but only if there are no statements on the execution path
+between it and the next switch label.
+
+Here is an example:
+
+.. code-block:: c++
+
+ // compile with -Wimplicit-fallthrough
+ switch (n) {
+ case 22:
+ case 33: // no warning: no statements between case labels
+ f();
+ case 44: // warning: unannotated fall-through
+ g();
+ [[clang::fallthrough]];
+ case 55: // no warning
+ if (x) {
+ h();
+ break;
+ }
+ else {
+ i();
+ [[clang::fallthrough]];
+ }
+ case 66: // no warning
+ p();
+ [[clang::fallthrough]]; // warning: fallthrough annotation does not
+ // directly precede case label
+ q();
+ case 77: // warning: unannotated fall-through
+ r();
+ }
+
+
+#pragma clang loop
+------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","", "X"
+
+The ``#pragma clang loop`` directive allows loop optimization hints to be
+specified for the subsequent loop. The directive allows vectorization,
+interleaving, and unrolling to be enabled or disabled. Vector width as well
+as interleave and unrolling count can be manually specified. See
+`language extensions
+<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
+for details.
+
+
+#pragma unroll, #pragma nounroll
+--------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","", "X"
+
+Loop unrolling optimization hints can be specified with ``#pragma unroll`` and
+``#pragma nounroll``. The pragma is placed immediately before a for, while,
+do-while, or c++11 range-based for loop.
+
+Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
+attempt to fully unroll the loop if the trip count is known at compile time and
+attempt to partially unroll the loop if the trip count is not known at compile
+time:
+
+.. code-block:: c++
+
+ #pragma unroll
+ for (...) {
+ ...
+ }
+
+Specifying the optional parameter, ``#pragma unroll _value_``, directs the
+unroller to unroll the loop ``_value_`` times. The parameter may optionally be
+enclosed in parentheses:
+
+.. code-block:: c++
+
+ #pragma unroll 16
+ for (...) {
+ ...
+ }
+
+ #pragma unroll(16)
+ for (...) {
+ ...
+ }
+
+Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled:
+
+.. code-block:: c++
+
+ #pragma nounroll
+ for (...) {
+ ...
+ }
+
+``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
+``#pragma clang loop unroll(full)`` and
+``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll``
+is equivalent to ``#pragma clang loop unroll(disable)``. See
+`language extensions
+<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
+for further details including limitations of the unroll hints.
+
+
+Type Safety Checking
+====================
+Clang supports additional attributes to enable checking type safety properties
+that can't be enforced by the C type system. Use cases include:
+
+* MPI library implementations, where these attributes enable checking that
+ the buffer type matches the passed ``MPI_Datatype``;
+* for HDF5 library there is a similar use case to MPI;
+* checking types of variadic functions' arguments for functions like
+ ``fcntl()`` and ``ioctl()``.
+
+You can detect support for these attributes with ``__has_attribute()``. For
+example:
+
+.. code-block:: c++
+
+ #if defined(__has_attribute)
+ # if __has_attribute(argument_with_type_tag) && \
+ __has_attribute(pointer_with_type_tag) && \
+ __has_attribute(type_tag_for_datatype)
+ # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx)))
+ /* ... other macros ... */
+ # endif
+ #endif
+
+ #if !defined(ATTR_MPI_PWT)
+ # define ATTR_MPI_PWT(buffer_idx, type_idx)
+ #endif
+
+ int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+ ATTR_MPI_PWT(1,3);
+
+argument_with_type_tag
+----------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx,
+type_tag_idx)))`` on a function declaration to specify that the function
+accepts a type tag that determines the type of some other argument.
+``arg_kind`` is an identifier that should be used when annotating all
+applicable type tags.
+
+This attribute is primarily useful for checking arguments of variadic functions
+(``pointer_with_type_tag`` can be used in most non-variadic cases).
+
+For example:
+
+.. code-block:: c++
+
+ int fcntl(int fd, int cmd, ...)
+ __attribute__(( argument_with_type_tag(fcntl,3,2) ));
+
+
+pointer_with_type_tag
+---------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))``
+on a function declaration to specify that the function accepts a type tag that
+determines the pointee type of some other pointer argument.
+
+For example:
+
+.. code-block:: c++
+
+ int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+ __attribute__(( pointer_with_type_tag(mpi,1,3) ));
+
+
+type_tag_for_datatype
+---------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang supports annotating type tags of two forms.
+
+* **Type tag that is an expression containing a reference to some declared
+ identifier.** Use ``__attribute__((type_tag_for_datatype(kind, type)))`` on a
+ declaration with that identifier:
+
+ .. code-block:: c++
+
+ extern struct mpi_datatype mpi_datatype_int
+ __attribute__(( type_tag_for_datatype(mpi,int) ));
+ #define MPI_INT ((MPI_Datatype) &mpi_datatype_int)
+
+* **Type tag that is an integral literal.** Introduce a ``static const``
+ variable with a corresponding initializer value and attach
+ ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration,
+ for example:
+
+ .. code-block:: c++
+
+ #define MPI_INT ((MPI_Datatype) 42)
+ static const MPI_Datatype mpi_datatype_int
+ __attribute__(( type_tag_for_datatype(mpi,int) )) = 42
+
+The attribute also accepts an optional third argument that determines how the
+expression is compared to the type tag. There are two supported flags:
+
+* ``layout_compatible`` will cause types to be compared according to
+ layout-compatibility rules (C++11 [class.mem] p 17, 18). This is
+ implemented to support annotating types like ``MPI_DOUBLE_INT``.
+
+ For example:
+
+ .. code-block:: c++
+
+ /* In mpi.h */
+ struct internal_mpi_double_int { double d; int i; };
+ extern struct mpi_datatype mpi_datatype_double_int
+ __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int, layout_compatible) ));
+
+ #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int)
+
+ /* In user code */
+ struct my_pair { double a; int b; };
+ struct my_pair *buffer;
+ MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning
+
+ struct my_int_pair { int a; int b; }
+ struct my_int_pair *buffer2;
+ MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element
+ // type 'struct my_int_pair'
+ // doesn't match specified MPI_Datatype
+
+* ``must_be_null`` specifies that the expression should be a null pointer
+ constant, for example:
+
+ .. code-block:: c++
+
+ /* In mpi.h */
+ extern struct mpi_datatype mpi_datatype_null
+ __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) ));
+
+ #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null)
+
+ /* In user code */
+ MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL
+ // was specified but buffer
+ // is not a null pointer
+
+
+AMD GPU Register Attributes
+===========================
+Clang supports attributes for controlling register usage on AMD GPU
+targets. These attributes may be attached to a kernel function
+definition and is an optimization hint to the backend for the maximum
+number of registers to use. This is useful in cases where register
+limited occupancy is known to be an important factor for the
+performance for the kernel.
+
+The semantics are as follows:
+
+- The backend will attempt to limit the number of used registers to
+ the specified value, but the exact number used is not
+ guaranteed. The number used may be rounded up to satisfy the
+ allocation requirements or ABI constraints of the subtarget. For
+ example, on Southern Islands VGPRs may only be allocated in
+ increments of 4, so requesting a limit of 39 VGPRs will really
+ attempt to use up to 40. Requesting more registers than the
+ subtarget supports will truncate to the maximum allowed. The backend
+ may also use fewer registers than requested whenever possible.
+
+- 0 implies the default no limit on register usage.
+
+- Ignored on older VLIW subtargets which did not have separate scalar
+ and vector registers, R600 through Northern Islands.
+
+amdgpu_num_sgpr
+---------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang supports the
+``__attribute__((amdgpu_num_sgpr(<num_registers>)))`` attribute on AMD
+Southern Islands GPUs and later for controlling the number of scalar
+registers. A typical value would be between 8 and 104 in increments of
+8.
+
+Due to common instruction constraints, an additional 2-4 SGPRs are
+typically required for internal use depending on features used. This
+value is a hint for the total number of SGPRs to use, and not the
+number of user SGPRs, so no special consideration needs to be given
+for these.
+
+
+amdgpu_num_vgpr
+---------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Clang supports the
+``__attribute__((amdgpu_num_vgpr(<num_registers>)))`` attribute on AMD
+Southern Islands GPUs and later for controlling the number of vector
+registers. A typical value would be between 4 and 256 in increments
+of 4.
+
+
+Calling Conventions
+===================
+Clang supports several different calling conventions, depending on the target
+platform and architecture. The calling convention used for a function determines
+how parameters are passed, how results are returned to the caller, and other
+low-level details of calling a function.
+
+fastcall (gnu::fastcall, __fastcall, _fastcall)
+-----------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","X", ""
+
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to use ECX and EDX as register parameters and clear parameters off of
+the stack on return. This convention does not support variadic calls or
+unprototyped functions in C, and has no effect on x86_64 targets. This calling
+convention is supported primarily for compatibility with existing code. Users
+seeking register parameters should use the ``regparm`` attribute, which does
+not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN.
+
+.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx
+
+
+ms_abi (gnu::ms_abi)
+--------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+On non-Windows x86_64 targets, this attribute changes the calling convention of
+a function to match the default convention used on Windows x86_64. This
+attribute has no effect on Windows targets or non-x86_64 targets.
+
+
+pcs (gnu::pcs)
+--------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+On ARM targets, this attribute can be used to select calling conventions
+similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and
+"aapcs-vfp".
+
+
+regparm (gnu::regparm)
+----------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+On 32-bit x86 targets, the regparm attribute causes the compiler to pass
+the first three integer parameters in EAX, EDX, and ECX instead of on the
+stack. This attribute has no effect on variadic functions, and all parameters
+are passed via the stack as normal.
+
+
+stdcall (gnu::stdcall, __stdcall, _stdcall)
+-------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","X", ""
+
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to clear parameters off of the stack on return. This convention does
+not support variadic calls or unprototyped functions in C, and has no effect on
+x86_64 targets. This calling convention is used widely by the Windows API and
+COM applications. See the documentation for `__stdcall`_ on MSDN.
+
+.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx
+
+
+thiscall (gnu::thiscall, __thiscall, _thiscall)
+-----------------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","X", ""
+
+On 32-bit x86 targets, this attribute changes the calling convention of a
+function to use ECX for the first parameter (typically the implicit ``this``
+parameter of C++ methods) and clear parameters off of the stack on return. This
+convention does not support variadic calls or unprototyped functions in C, and
+has no effect on x86_64 targets. See the documentation for `__thiscall`_ on
+MSDN.
+
+.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx
+
+
+vectorcall (__vectorcall, _vectorcall)
+--------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","X", ""
+
+On 32-bit x86 *and* x86_64 targets, this attribute changes the calling
+convention of a function to pass vector parameters in SSE registers.
+
+On 32-bit x86 targets, this calling convention is similar to ``__fastcall``.
+The first two integer parameters are passed in ECX and EDX. Subsequent integer
+parameters are passed in memory, and callee clears the stack. On x86_64
+targets, the callee does *not* clear the stack, and integer parameters are
+passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling
+convention.
+
+On both 32-bit x86 and x86_64 targets, vector and floating point arguments are
+passed in XMM0-XMM5. Homogenous vector aggregates of up to four elements are
+passed in sequential SSE registers if enough are available. If AVX is enabled,
+256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that
+cannot be passed in registers for any reason is passed by reference, which
+allows the caller to align the parameter memory.
+
+See the documentation for `__vectorcall`_ on MSDN for more details.
+
+.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx
+
+
+Consumed Annotation Checking
+============================
+Clang supports additional attributes for checking basic resource management
+properties, specifically for unique objects that have a single owning reference.
+The following attributes are currently supported, although **the implementation
+for these annotations is currently in development and are subject to change.**
+
+callable_when
+-------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Use ``__attribute__((callable_when(...)))`` to indicate what states a method
+may be called in. Valid states are unconsumed, consumed, or unknown. Each
+argument to this attribute must be a quoted string. E.g.:
+
+``__attribute__((callable_when("unconsumed", "unknown")))``
+
+
+consumable
+----------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Each ``class`` that uses any of the typestate annotations must first be marked
+using the ``consumable`` attribute. Failure to do so will result in a warning.
+
+This attribute accepts a single parameter that must be one of the following:
+``unknown``, ``consumed``, or ``unconsumed``.
+
+
+param_typestate
+---------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+This attribute specifies expectations about function parameters. Calls to an
+function with annotated parameters will issue a warning if the corresponding
+argument isn't in the expected state. The attribute is also used to set the
+initial state of the parameter when analyzing the function's body.
+
+
+return_typestate
+----------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+The ``return_typestate`` attribute can be applied to functions or parameters.
+When applied to a function the attribute specifies the state of the returned
+value. The function's body is checked to ensure that it always returns a value
+in the specified state. On the caller side, values returned by the annotated
+function are initialized to the given state.
+
+When applied to a function parameter it modifies the state of an argument after
+a call to the function returns. The function's body is checked to ensure that
+the parameter is in the expected state before returning.
+
+
+set_typestate
+-------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Annotate methods that transition an object into a new state with
+``__attribute__((set_typestate(new_state)))``. The new state must be
+unconsumed, consumed, or unknown.
+
+
+test_typestate
+--------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","","","", ""
+
+Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method
+returns true if the object is in the specified state..
+
+
+OpenCL Address Spaces
+=====================
+The address space qualifier may be used to specify the region of memory that is
+used to allocate the object. OpenCL supports the following address spaces:
+__generic(generic), __global(global), __local(local), __private(private),
+__constant(constant).
+
+ .. code-block:: c
+
+ __constant int c = ...;
+
+ __generic int* foo(global int* g) {
+ __local int* l;
+ private int p;
+ ...
+ return l;
+ }
+
+More details can be found in the OpenCL C language Spec v2.0, Section 6.5.
+
+constant (__constant)
+---------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The constant address space attribute signals that an object is located in
+a constant (non-modifiable) memory region. It is available to all work items.
+Any type can be annotated with the constant address space attribute. Objects
+with the constant address space qualifier can be declared in any scope and must
+have an initializer.
+
+
+generic (__generic)
+-------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The generic address space attribute is only available with OpenCL v2.0 and later.
+It can be used with pointer types. Variables in global and local scope and
+function parameters in non-kernel functions can have the generic address space
+type attribute. It is intended to be a placeholder for any other address space
+except for '__constant' in OpenCL code which can be used with multiple address
+spaces.
+
+
+global (__global)
+-----------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The global address space attribute specifies that an object is allocated in
+global memory, which is accessible by all work items. The content stored in this
+memory area persists between kernel executions. Pointer types to the global
+address space are allowed as function parameters or local variables. Starting
+with OpenCL v2.0, the global address space can be used with global (program
+scope) variables and static local variable as well.
+
+
+local (__local)
+---------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The local address space specifies that an object is allocated in the local (work
+group) memory area, which is accessible to all work items in the same work
+group. The content stored in this memory region is not accessible after
+the kernel execution ends. In a kernel function scope, any variable can be in
+the local address space. In other scopes, only pointer types to the local address
+space are allowed. Local address space variables cannot have an initializer.
+
+
+private (__private)
+-------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The private address space specifies that an object is allocated in the private
+(work item) memory. Other work items cannot access the same memory area and its
+content is destroyed after work item execution ends. Local variables can be
+declared in the private address space. Function arguments are always in the
+private address space. Kernel function arguments of a pointer or an array type
+cannot point to the private address space.
+
+
+Nullability Attributes
+======================
+Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``).
+
+The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example:
+
+ .. code-block:: c
+
+ // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior).
+ int fetch(int * _Nonnull ptr) { return *ptr; }
+
+ // 'ptr' may be null.
+ int fetch_or_zero(int * _Nullable ptr) {
+ return ptr ? *ptr : 0;
+ }
+
+ // A nullable pointer to non-null pointers to const characters.
+ const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n);
+
+In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example:
+
+ .. code-block:: objective-c
+
+ @interface NSView : NSResponder
+ - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView;
+ @property (assign, nullable) NSView *superview;
+ @property (readonly, nonnull) NSArray *subviews;
+ @end
+
+nonnull (gnu::nonnull)
+----------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes>`_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example:
+
+ .. code-block:: c
+
+ extern void * my_memcpy (void *dest, const void *src, size_t len)
+ __attribute__((nonnull (1, 2)));
+
+Here, the ``nonnull`` attribute indicates that parameters 1 and 2
+cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null:
+
+ .. code-block:: c
+
+ extern void * my_memcpy (void *dest, const void *src, size_t len)
+ __attribute__((nonnull));
+
+Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example:
+
+ .. code-block:: c
+
+ extern void * my_memcpy (void *dest __attribute__((nonnull)),
+ const void *src __attribute__((nonnull)), size_t len);
+
+Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable.
+
+
+returns_nonnull (gnu::returns_nonnull)
+--------------------------------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "X","X","","", ""
+
+The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer:
+
+ .. code-block:: c
+
+ extern void * malloc (size_t size) __attribute__((returns_nonnull));
+
+The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable
+
+
+_Nonnull
+--------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as:
+
+ .. code-block:: c
+
+ int fetch(int * _Nonnull ptr);
+
+a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null.
+
+
+_Null_unspecified
+-----------------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API.
+
+
+_Nullable
+---------
+.. csv-table:: Supported Syntaxes
+ :header: "GNU", "C++11", "__declspec", "Keyword", "Pragma"
+
+ "","","","X", ""
+
+The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given:
+
+ .. code-block:: c
+
+ int fetch_or_zero(int * _Nullable ptr);
+
+a caller of ``fetch_or_zero`` can provide null.
+
+
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 9bdbcdbc1250..8c3f46c64863 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,6 +1,6 @@
-=====================================
-Clang 3.8 (In-Progress) Release Notes
-=====================================
+=======================
+Clang 3.8 Release Notes
+=======================
.. contents::
:local:
@@ -8,12 +8,6 @@ Clang 3.8 (In-Progress) Release Notes
Written by the `LLVM Team <http://llvm.org/>`_
-.. warning::
-
- These are in-progress notes for the upcoming Clang 3.8 release. You may
- prefer the `Clang 3.7 Release Notes
- <http://llvm.org/releases/3.7.0/tools/clang/docs/ReleaseNotes.html>`_.
-
Introduction
============
@@ -31,11 +25,6 @@ the latest release, please check out the main please see the `Clang Web
Site <http://clang.llvm.org>`_ or the `LLVM Web
Site <http://llvm.org>`_.
-Note that if you are reading this file from a Subversion checkout or the
-main Clang web page, this document applies to the *next* release, not
-the current one. To see the release notes for a specific release, please
-see the `releases page <http://llvm.org/releases/>`_.
-
What's New in Clang 3.8?
========================
@@ -93,8 +82,41 @@ Clang's support for building native Windows programs ...
C Language Changes in Clang
---------------------------
+Better support for ``__builtin_object_size``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Clang 3.8 has expanded support for the ``__builtin_object_size`` intrinsic.
+Specifically, ``__builtin_object_size`` will now fail less often when you're
+trying to get the size of a subobject. Additionally, the ``pass_object_size``
+attribute was added, which allows ``__builtin_object_size`` to successfully
+report the size of function parameters, without requiring that the function be
+inlined.
+
+
+``overloadable`` attribute relaxations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Previously, functions marked ``overloadable`` in C would strictly use C++'s
+type conversion rules, so the following code would not compile:
+
+.. code-block:: c
+
+ void foo(char *bar, char *baz) __attribute__((overloadable));
+ void foo(char *bar) __attribute__((overloadable));
+
+ void callFoo() {
+ int a;
+ foo(&a);
+ }
+
+Now, Clang is able to selectively use C's type conversion rules during overload
+resolution in C, which allows the above example to compile (albeit potentially
+with a warning about an implicit conversion from ``int*`` to ``char*``).
+
+
...
+
C11 Feature Support
^^^^^^^^^^^^^^^^^^^
@@ -127,7 +149,9 @@ These are major API changes that have happened since the 3.7 release of
Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading.
-- ...
+* With this release, the autoconf build system is deprecated. It will be removed
+ in the 3.9 release. Please migrate to using CMake. For more information see:
+ `Building LLVM with CMake <http://llvm.org/docs/CMake.html>`_
AST Matchers
------------
@@ -182,7 +206,26 @@ libclang
Static Analyzer
---------------
-...
+The scan-build and scan-view tools will now be installed with clang. Use these
+tools to run the static analyzer on projects and view the produced results.
+
+Static analysis of C++ lambdas has been greatly improved, including
+interprocedural analysis of lambda applications.
+
+Several new checks were added:
+
+- The analyzer now checks for misuse of ``vfork()``.
+- The analyzer can now detect excessively-padded structs. This check can be
+ enabled by passing the following command to scan-build:
+ ``-enable-checker optin.performance.Padding``.
+- The checks to detect misuse of ``_Nonnull`` type qualifiers as well as checks
+ to detect misuse of Objective-C generics were added.
+- The analyzer now has opt in checks to detect localization errors in Coca
+ applications. The checks warn about uses of non-localized ``NSStrings``
+ passed to UI methods expecting localized strings and on ``NSLocalizedString``
+ macros that are missing the comment argument. These can be enabled by passing
+ the following command to scan-build:
+ ``-enable-checker optin.osx.cocoa.localizability``.
Core Analysis Improvements
==========================
diff --git a/docs/UndefinedBehaviorSanitizer.rst b/docs/UndefinedBehaviorSanitizer.rst
index 37ff16d9a9e9..2a133501dd95 100644
--- a/docs/UndefinedBehaviorSanitizer.rst
+++ b/docs/UndefinedBehaviorSanitizer.rst
@@ -168,6 +168,38 @@ UndefinedBehaviorSanitizer supports ``src`` and ``fun`` entity types in
:doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports
in the specified source files or functions.
+Runtime suppressions
+--------------------
+
+Sometimes you can suppress UBSan error reports for specific files, functions,
+or libraries without recompiling the code. You need to pass a path to
+suppression file in a ``UBSAN_OPTIONS`` environment variable.
+
+.. code-block:: bash
+
+ UBSAN_OPTIONS=suppressions=MyUBSan.supp
+
+You need to specify a :ref:`check <ubsan-checks>` you are suppressing and the
+bug location. For example:
+
+.. code-block:: bash
+
+ signed-integer-overflow:file-with-known-overflow.cpp
+ alignment:function_doing_unaligned_access
+ vptr:shared_object_with_vptr_failures.so
+
+There are several limitations:
+
+* Sometimes your binary must have enough debug info and/or symbol table, so
+ that the runtime could figure out source file or function name to match
+ against the suppression.
+* It is only possible to suppress recoverable checks. For the example above,
+ you can additionally pass
+ ``-fsanitize-recover=signed-integer-overflow,alignment,vptr``, although
+ most of UBSan checks are recoverable by default.
+* Check groups (like ``undefined``) can't be used in suppressions file, only
+ fine-grained checks are supported.
+
Supported Platforms
===================
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 5fe1e371df64..18211e27f5d6 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -2036,6 +2036,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
CL.EXE COMPATIBILITY OPTIONS:
/? Display available options
/arch:<value> Set architecture for code generation
+ /Brepro- Emit an object file which cannot be reproduced over time
+ /Brepro Emit an object file which can be reproduced over time
/C Don't discard comments when preprocessing
/c Compile only
/D <macro[=value]> Define macro
@@ -2079,8 +2081,6 @@ Execute ``clang-cl /?`` to see a list of supported options:
/Oi Enable use of builtin functions
/Os Optimize for size
/Ot Optimize for speed
- /Oy- Disable frame pointer omission
- /Oy Enable frame pointer omission
/O<value> Optimization level
/o <file or directory> Set output file or directory (ends in / or \)
/P Preprocess to file
@@ -2105,7 +2105,7 @@ Execute ``clang-cl /?`` to see a list of supported options:
/W2 Enable -Wall
/W3 Enable -Wall
/W4 Enable -Wall and -Wextra
- /Wall Enable -Wall
+ /Wall Enable -Wall and -Wextra
/WX- Do not treat warnings as errors
/WX Treat warnings as errors
/w Disable all warnings
@@ -2133,8 +2133,10 @@ Execute ``clang-cl /?`` to see a list of supported options:
-fms-compatibility-version=<value>
Dot-separated value representing the Microsoft compiler version
number to report in _MSC_VER (0 = don't define it (default))
- -fmsc-version=<value> Microsoft compiler version number to report in _MSC_VER (0 = don't
- define it (default))
+ -fms-compatibility Enable full Microsoft Visual C++ compatibility
+ -fms-extensions Accept some non-standard constructs supported by the Microsoft compiler
+ -fmsc-version=<value> Microsoft compiler version number to report in _MSC_VER
+ (0 = don't define it (default))
-fno-sanitize-coverage=<value>
Disable specified features of coverage instrumentation for Sanitizers
-fno-sanitize-recover=<value>
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index ffe1ff3b950b..29aa642a9ab8 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2229,7 +2229,8 @@ public:
bool CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
- bool IgnoreBaseAccess);
+ bool IgnoreBaseAccess,
+ bool Diagnose = true);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType);
@@ -5388,7 +5389,8 @@ public:
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name,
- CXXCastPath *BasePath);
+ CXXCastPath *BasePath,
+ bool IgnoreAccess = false);
std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
@@ -7514,14 +7516,15 @@ public:
ObjCMethodDecl *&ClassMethod,
ObjCMethodDecl *&InstanceMethod,
TypedefNameDecl *&TDNDecl,
- bool CfToNs);
-
+ bool CfToNs, bool Diagnose = true);
+
bool CheckObjCBridgeRelatedConversions(SourceLocation Loc,
QualType DestType, QualType SrcType,
- Expr *&SrcExpr);
-
- bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr);
-
+ Expr *&SrcExpr, bool Diagnose = true);
+
+ bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr,
+ bool Diagnose = true);
+
bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
/// \brief Check whether the given new method is a valid override of the
@@ -8613,6 +8616,7 @@ public:
ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
QualType castType, Expr *&op,
CheckedConversionKind CCK,
+ bool Diagnose = true,
bool DiagnoseCFAudited = false,
BinaryOperatorKind Opc = BO_PtrMemD
);
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 0ab1fa788603..2ab5a32917ae 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -473,14 +473,14 @@ class TemplateDiff {
/// ShowColor - Diagnostics support color, so bolding will be used.
bool ShowColor;
- /// FromType - When single type printing is selected, this is the type to be
- /// be printed. When tree printing is selected, this type will show up first
- /// in the tree.
- QualType FromType;
+ /// FromTemplateType - When single type printing is selected, this is the
+ /// type to be be printed. When tree printing is selected, this type will
+ /// show up first in the tree.
+ QualType FromTemplateType;
- /// ToType - The type that FromType is compared to. Only in tree printing
- /// will this type be outputed.
- QualType ToType;
+ /// ToTemplateType - The type that FromType is compared to. Only in tree
+ /// printing will this type be outputed.
+ QualType ToTemplateType;
/// OS - The stream used to construct the output strings.
raw_ostream &OS;
@@ -491,82 +491,70 @@ class TemplateDiff {
/// DiffTree - A tree representation the differences between two types.
class DiffTree {
public:
- /// DiffKind - The difference in a DiffNode and which fields are used.
+ /// DiffKind - The difference in a DiffNode. Fields of
+ /// TemplateArgumentInfo needed by each difference can be found in the
+ /// Set* and Get* functions.
enum DiffKind {
/// Incomplete or invalid node.
Invalid,
- /// Another level of templates, uses TemplateDecl and Qualifiers
+ /// Another level of templates, requires that
Template,
- /// Type difference, uses QualType
+ /// Type difference, all type differences except those falling under
+ /// the Template difference.
Type,
- /// Expression difference, uses Expr
+ /// Expression difference, this is only when both arguments are
+ /// expressions. If one argument is an expression and the other is
+ /// Integer or Declaration, then use that diff type instead.
Expression,
- /// Template argument difference, uses TemplateDecl
+ /// Template argument difference
TemplateTemplate,
- /// Integer difference, uses APSInt and Expr
+ /// Integer difference
Integer,
- /// Declaration difference, uses ValueDecl
- Declaration
+ /// Declaration difference, nullptr arguments are included here
+ Declaration,
+ /// One argument being integer and the other being declaration
+ FromIntegerAndToDeclaration,
+ FromDeclarationAndToInteger
};
+
private:
+ /// TemplateArgumentInfo - All the information needed to pretty print
+ /// a template argument. See the Set* and Get* functions to see which
+ /// fields are used for each DiffKind.
+ struct TemplateArgumentInfo {
+ QualType ArgType;
+ Qualifiers Qual;
+ llvm::APSInt Val;
+ bool IsValidInt = false;
+ Expr *ArgExpr = nullptr;
+ TemplateDecl *TD = nullptr;
+ ValueDecl *VD = nullptr;
+ bool NeedAddressOf = false;
+ bool IsNullPtr = false;
+ bool IsDefault = false;
+ };
+
/// DiffNode - The root node stores the original type. Each child node
/// stores template arguments of their parents. For templated types, the
/// template decl is also stored.
struct DiffNode {
- DiffKind Kind;
+ DiffKind Kind = Invalid;
/// NextNode - The index of the next sibling node or 0.
- unsigned NextNode;
+ unsigned NextNode = 0;
/// ChildNode - The index of the first child node or 0.
- unsigned ChildNode;
+ unsigned ChildNode = 0;
/// ParentNode - The index of the parent node.
- unsigned ParentNode;
-
- /// FromType, ToType - The type arguments.
- QualType FromType, ToType;
-
- /// FromExpr, ToExpr - The expression arguments.
- Expr *FromExpr, *ToExpr;
-
- /// FromNullPtr, ToNullPtr - If the template argument is a nullptr
- bool FromNullPtr, ToNullPtr;
-
- /// FromTD, ToTD - The template decl for template template
- /// arguments or the type arguments that are templates.
- TemplateDecl *FromTD, *ToTD;
-
- /// FromQual, ToQual - Qualifiers for template types.
- Qualifiers FromQual, ToQual;
+ unsigned ParentNode = 0;
- /// FromInt, ToInt - APSInt's for integral arguments.
- llvm::APSInt FromInt, ToInt;
-
- /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
- bool IsValidFromInt, IsValidToInt;
-
- /// FromValueDecl, ToValueDecl - Whether the argument is a decl.
- ValueDecl *FromValueDecl, *ToValueDecl;
-
- /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of
- /// operator before it.
- bool FromAddressOf, ToAddressOf;
-
- /// FromDefault, ToDefault - Whether the argument is a default argument.
- bool FromDefault, ToDefault;
+ TemplateArgumentInfo FromArgInfo, ToArgInfo;
/// Same - Whether the two arguments evaluate to the same value.
- bool Same;
-
- DiffNode(unsigned ParentNode = 0)
- : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
- FromType(), ToType(), FromExpr(nullptr), ToExpr(nullptr),
- FromNullPtr(false), ToNullPtr(false),
- FromTD(nullptr), ToTD(nullptr), IsValidFromInt(false),
- IsValidToInt(false), FromValueDecl(nullptr), ToValueDecl(nullptr),
- FromAddressOf(false), ToAddressOf(false), FromDefault(false),
- ToDefault(false), Same(false) {}
+ bool Same = false;
+
+ DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {}
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -581,54 +569,127 @@ class TemplateDiff {
/// ReadNode - The index of the current node being read.
unsigned ReadNode;
-
+
public:
DiffTree() :
CurrentNode(0), NextFreeNode(1) {
FlatTree.push_back(DiffNode());
}
- // Node writing functions.
- /// SetNode - Sets FromTD and ToTD of the current node.
- void SetNode(TemplateDecl *FromTD, TemplateDecl *ToTD) {
- FlatTree[CurrentNode].FromTD = FromTD;
- FlatTree[CurrentNode].ToTD = ToTD;
+ // Node writing functions, one for each valid DiffKind element.
+ void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
+ Qualifiers FromQual, Qualifiers ToQual,
+ bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Template;
+ FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
+ FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
+ FlatTree[CurrentNode].FromArgInfo.Qual = FromQual;
+ FlatTree[CurrentNode].ToArgInfo.Qual = ToQual;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Type;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromType;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToType;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Expression;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
+ bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = TemplateTemplate;
+ FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
+ FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetIntegerDiff(llvm::APSInt FromInt, llvm::APSInt ToInt,
+ bool IsValidFromInt, bool IsValidToInt,
+ QualType FromIntType, QualType ToIntType,
+ Expr *FromExpr, Expr *ToExpr, bool FromDefault,
+ bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Integer;
+ FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
+ FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
+ FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
+ FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromAddressOf, bool ToAddressOf,
+ bool FromNullPtr, bool ToNullPtr, Expr *FromExpr,
+ Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = Declaration;
+ FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
+ FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
+ FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
+ FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
+ FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetFromDeclarationAndToIntegerDiff(
+ ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr,
+ Expr *FromExpr, llvm::APSInt ToInt, bool IsValidToInt,
+ QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger;
+ FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
+ FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
+ FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
+ FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
+ }
+
+ void SetFromIntegerAndToDeclarationDiff(
+ llvm::APSInt FromInt, bool IsValidFromInt, QualType FromIntType,
+ Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf,
+ bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) {
+ assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
+ FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration;
+ FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
+ FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
+ FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
+ FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
+ FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
+ FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
+ FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
+ FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
+ SetDefault(FromDefault, ToDefault);
}
- /// SetNode - Sets FromType and ToType of the current node.
- void SetNode(QualType FromType, QualType ToType) {
- FlatTree[CurrentNode].FromType = FromType;
- FlatTree[CurrentNode].ToType = ToType;
- }
-
- /// SetNode - Set FromExpr and ToExpr of the current node.
- void SetNode(Expr *FromExpr, Expr *ToExpr) {
- FlatTree[CurrentNode].FromExpr = FromExpr;
- FlatTree[CurrentNode].ToExpr = ToExpr;
- }
-
- /// SetNode - Set FromInt and ToInt of the current node.
- void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt) {
- FlatTree[CurrentNode].FromInt = FromInt;
- FlatTree[CurrentNode].ToInt = ToInt;
- FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt;
- FlatTree[CurrentNode].IsValidToInt = IsValidToInt;
- }
-
- /// SetNode - Set FromQual and ToQual of the current node.
- void SetNode(Qualifiers FromQual, Qualifiers ToQual) {
- FlatTree[CurrentNode].FromQual = FromQual;
- FlatTree[CurrentNode].ToQual = ToQual;
- }
-
- /// SetNode - Set FromValueDecl and ToValueDecl of the current node.
- void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromAddressOf, bool ToAddressOf) {
- FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
- FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
- FlatTree[CurrentNode].FromAddressOf = FromAddressOf;
- FlatTree[CurrentNode].ToAddressOf = ToAddressOf;
+ /// SetDefault - Sets FromDefault and ToDefault flags of the current node.
+ void SetDefault(bool FromDefault, bool ToDefault) {
+ assert((!FromDefault || !ToDefault) && "Both arguments cannot be default.");
+ FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault;
+ FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault;
}
/// SetSame - Sets the same flag of the current node.
@@ -636,18 +697,6 @@ class TemplateDiff {
FlatTree[CurrentNode].Same = Same;
}
- /// SetNullPtr - Sets the NullPtr flags of the current node.
- void SetNullPtr(bool FromNullPtr, bool ToNullPtr) {
- FlatTree[CurrentNode].FromNullPtr = FromNullPtr;
- FlatTree[CurrentNode].ToNullPtr = ToNullPtr;
- }
-
- /// SetDefault - Sets FromDefault and ToDefault flags of the current node.
- void SetDefault(bool FromDefault, bool ToDefault) {
- FlatTree[CurrentNode].FromDefault = FromDefault;
- FlatTree[CurrentNode].ToDefault = ToDefault;
- }
-
/// SetKind - Sets the current node's type.
void SetKind(DiffKind Kind) {
FlatTree[CurrentNode].Kind = Kind;
@@ -655,12 +704,16 @@ class TemplateDiff {
/// Up - Changes the node to the parent of the current node.
void Up() {
+ assert(FlatTree[CurrentNode].Kind != Invalid &&
+ "Cannot exit node before setting node information.");
CurrentNode = FlatTree[CurrentNode].ParentNode;
}
/// AddNode - Adds a child node to the current node, then sets that node
/// node as the current node.
void AddNode() {
+ assert(FlatTree[CurrentNode].Kind == Template &&
+ "Only Template nodes can have children nodes.");
FlatTree.push_back(DiffNode(CurrentNode));
DiffNode &Node = FlatTree[CurrentNode];
if (Node.ChildNode == 0) {
@@ -692,46 +745,103 @@ class TemplateDiff {
ReadNode = FlatTree[ReadNode].ParentNode;
}
- /// GetNode - Gets the FromType and ToType.
- void GetNode(QualType &FromType, QualType &ToType) {
- FromType = FlatTree[ReadNode].FromType;
- ToType = FlatTree[ReadNode].ToType;
+ void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD,
+ Qualifiers &FromQual, Qualifiers &ToQual) {
+ assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind.");
+ FromTD = FlatTree[ReadNode].FromArgInfo.TD;
+ ToTD = FlatTree[ReadNode].ToArgInfo.TD;
+ FromQual = FlatTree[ReadNode].FromArgInfo.Qual;
+ ToQual = FlatTree[ReadNode].ToArgInfo.Qual;
+ }
+
+ void GetTypeDiff(QualType &FromType, QualType &ToType) {
+ assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind");
+ FromType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ ToType = FlatTree[ReadNode].ToArgInfo.ArgType;
+ }
+
+ void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind");
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
+ assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind.");
+ FromTD = FlatTree[ReadNode].FromArgInfo.TD;
+ ToTD = FlatTree[ReadNode].ToArgInfo.TD;
+ }
+
+ void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
+ bool &IsValidFromInt, bool &IsValidToInt,
+ QualType &FromIntType, QualType &ToIntType,
+ Expr *&FromExpr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind.");
+ FromInt = FlatTree[ReadNode].FromArgInfo.Val;
+ ToInt = FlatTree[ReadNode].ToArgInfo.Val;
+ IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
+ IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
+ FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
+ bool &FromAddressOf, bool &ToAddressOf,
+ bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr,
+ Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind.");
+ FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
+ ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
+ FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
+ ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
+ FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
+ ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetFromDeclarationAndToIntegerDiff(
+ ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr,
+ Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt,
+ QualType &ToIntType, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger &&
+ "Unexpected kind.");
+ FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
+ FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
+ FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToInt = FlatTree[ReadNode].ToArgInfo.Val;
+ IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
+ ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
+ }
+
+ void GetFromIntegerAndToDeclarationDiff(
+ llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType,
+ Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf,
+ bool &ToNullPtr, Expr *&ToExpr) {
+ assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration &&
+ "Unexpected kind.");
+ FromInt = FlatTree[ReadNode].FromArgInfo.Val;
+ IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
+ FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
+ FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
+ ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
+ ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
+ ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
+ ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
}
- /// GetNode - Gets the FromExpr and ToExpr.
- void GetNode(Expr *&FromExpr, Expr *&ToExpr) {
- FromExpr = FlatTree[ReadNode].FromExpr;
- ToExpr = FlatTree[ReadNode].ToExpr;
- }
-
- /// GetNode - Gets the FromTD and ToTD.
- void GetNode(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
- FromTD = FlatTree[ReadNode].FromTD;
- ToTD = FlatTree[ReadNode].ToTD;
- }
-
- /// GetNode - Gets the FromInt and ToInt.
- void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
- bool &IsValidFromInt, bool &IsValidToInt) {
- FromInt = FlatTree[ReadNode].FromInt;
- ToInt = FlatTree[ReadNode].ToInt;
- IsValidFromInt = FlatTree[ReadNode].IsValidFromInt;
- IsValidToInt = FlatTree[ReadNode].IsValidToInt;
- }
-
- /// GetNode - Gets the FromQual and ToQual.
- void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) {
- FromQual = FlatTree[ReadNode].FromQual;
- ToQual = FlatTree[ReadNode].ToQual;
+ /// FromDefault - Return true if the from argument is the default.
+ bool FromDefault() {
+ return FlatTree[ReadNode].FromArgInfo.IsDefault;
}
- /// GetNode - Gets the FromValueDecl and ToValueDecl.
- void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
- bool &FromAddressOf, bool &ToAddressOf) {
- FromValueDecl = FlatTree[ReadNode].FromValueDecl;
- ToValueDecl = FlatTree[ReadNode].ToValueDecl;
- FromAddressOf = FlatTree[ReadNode].FromAddressOf;
- ToAddressOf = FlatTree[ReadNode].ToAddressOf;
+ /// ToDefault - Return true if the to argument is the default.
+ bool ToDefault() {
+ return FlatTree[ReadNode].ToArgInfo.IsDefault;
}
/// NodeIsSame - Returns true the arguments are the same.
@@ -764,26 +874,6 @@ class TemplateDiff {
return FlatTree[ReadNode].NextNode != 0;
}
- /// FromNullPtr - Returns true if the from argument is null.
- bool FromNullPtr() {
- return FlatTree[ReadNode].FromNullPtr;
- }
-
- /// ToNullPtr - Returns true if the to argument is null.
- bool ToNullPtr() {
- return FlatTree[ReadNode].ToNullPtr;
- }
-
- /// FromDefault - Return true if the from argument is the default.
- bool FromDefault() {
- return FlatTree[ReadNode].FromDefault;
- }
-
- /// ToDefault - Return true if the to argument is the default.
- bool ToDefault() {
- return FlatTree[ReadNode].ToDefault;
- }
-
/// Empty - Returns true if the tree has no information.
bool Empty() {
return GetKind() == Invalid;
@@ -797,102 +887,128 @@ class TemplateDiff {
DiffTree Tree;
- /// TSTiterator - an iterator that is used to enter a
- /// TemplateSpecializationType and read TemplateArguments inside template
- /// parameter packs in order with the rest of the TemplateArguments.
- struct TSTiterator {
+ /// TSTiterator - a pair of iterators that walks the
+ /// TemplateSpecializationType and the desugared TemplateSpecializationType.
+ /// The deseguared TemplateArgument should provide the canonical argument
+ /// for comparisons.
+ class TSTiterator {
typedef const TemplateArgument& reference;
typedef const TemplateArgument* pointer;
- /// TST - the template specialization whose arguments this iterator
- /// traverse over.
- const TemplateSpecializationType *TST;
+ /// InternalIterator - an iterator that is used to enter a
+ /// TemplateSpecializationType and read TemplateArguments inside template
+ /// parameter packs in order with the rest of the TemplateArguments.
+ struct InternalIterator {
+ /// TST - the template specialization whose arguments this iterator
+ /// traverse over.
+ const TemplateSpecializationType *TST;
- /// DesugarTST - desugared template specialization used to extract
- /// default argument information
- const TemplateSpecializationType *DesugarTST;
+ /// Index - the index of the template argument in TST.
+ unsigned Index;
- /// Index - the index of the template argument in TST.
- unsigned Index;
+ /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA
+ /// points to a TemplateArgument within a parameter pack.
+ TemplateArgument::pack_iterator CurrentTA;
- /// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA
- /// points to a TemplateArgument within a parameter pack.
- TemplateArgument::pack_iterator CurrentTA;
+ /// EndTA - the end iterator of a parameter pack
+ TemplateArgument::pack_iterator EndTA;
- /// EndTA - the end iterator of a parameter pack
- TemplateArgument::pack_iterator EndTA;
+ /// InternalIterator - Constructs an iterator and sets it to the first
+ /// template argument.
+ InternalIterator(const TemplateSpecializationType *TST)
+ : TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) {
+ if (isEnd()) return;
- /// TSTiterator - Constructs an iterator and sets it to the first template
- /// argument.
- TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
- : TST(TST),
- DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
- Index(0), CurrentTA(nullptr), EndTA(nullptr) {
- if (isEnd()) return;
+ // Set to first template argument. If not a parameter pack, done.
+ TemplateArgument TA = TST->getArg(0);
+ if (TA.getKind() != TemplateArgument::Pack) return;
- // Set to first template argument. If not a parameter pack, done.
- TemplateArgument TA = TST->getArg(0);
- if (TA.getKind() != TemplateArgument::Pack) return;
+ // Start looking into the parameter pack.
+ CurrentTA = TA.pack_begin();
+ EndTA = TA.pack_end();
- // Start looking into the parameter pack.
- CurrentTA = TA.pack_begin();
- EndTA = TA.pack_end();
+ // Found a valid template argument.
+ if (CurrentTA != EndTA) return;
- // Found a valid template argument.
- if (CurrentTA != EndTA) return;
+ // Parameter pack is empty, use the increment to get to a valid
+ // template argument.
+ ++(*this);
+ }
- // Parameter pack is empty, use the increment to get to a valid
- // template argument.
- ++(*this);
- }
+ /// isEnd - Returns true if the iterator is one past the end.
+ bool isEnd() const {
+ return Index >= TST->getNumArgs();
+ }
- /// isEnd - Returns true if the iterator is one past the end.
- bool isEnd() const {
- return Index >= TST->getNumArgs();
- }
+ /// &operator++ - Increment the iterator to the next template argument.
+ InternalIterator &operator++() {
+ if (isEnd()) {
+ return *this;
+ }
- /// &operator++ - Increment the iterator to the next template argument.
- TSTiterator &operator++() {
- // After the end, Index should be the default argument position in
- // DesugarTST, if it exists.
- if (isEnd()) {
- ++Index;
+ // If in a parameter pack, advance in the parameter pack.
+ if (CurrentTA != EndTA) {
+ ++CurrentTA;
+ if (CurrentTA != EndTA)
+ return *this;
+ }
+
+ // Loop until a template argument is found, or the end is reached.
+ while (true) {
+ // Advance to the next template argument. Break if reached the end.
+ if (++Index == TST->getNumArgs())
+ break;
+
+ // If the TemplateArgument is not a parameter pack, done.
+ TemplateArgument TA = TST->getArg(Index);
+ if (TA.getKind() != TemplateArgument::Pack)
+ break;
+
+ // Handle parameter packs.
+ CurrentTA = TA.pack_begin();
+ EndTA = TA.pack_end();
+
+ // If the parameter pack is empty, try to advance again.
+ if (CurrentTA != EndTA)
+ break;
+ }
return *this;
}
- // If in a parameter pack, advance in the parameter pack.
- if (CurrentTA != EndTA) {
- ++CurrentTA;
- if (CurrentTA != EndTA)
- return *this;
+ /// operator* - Returns the appropriate TemplateArgument.
+ reference operator*() const {
+ assert(!isEnd() && "Index exceeds number of arguments.");
+ if (CurrentTA == EndTA)
+ return TST->getArg(Index);
+ else
+ return *CurrentTA;
}
- // Loop until a template argument is found, or the end is reached.
- while (true) {
- // Advance to the next template argument. Break if reached the end.
- if (++Index == TST->getNumArgs()) break;
+ /// operator-> - Allow access to the underlying TemplateArgument.
+ pointer operator->() const {
+ return &operator*();
+ }
+ };
- // If the TemplateArgument is not a parameter pack, done.
- TemplateArgument TA = TST->getArg(Index);
- if (TA.getKind() != TemplateArgument::Pack) break;
+ InternalIterator SugaredIterator;
+ InternalIterator DesugaredIterator;
- // Handle parameter packs.
- CurrentTA = TA.pack_begin();
- EndTA = TA.pack_end();
+ public:
+ TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
+ : SugaredIterator(TST),
+ DesugaredIterator(
+ GetTemplateSpecializationType(Context, TST->desugar())) {}
- // If the parameter pack is empty, try to advance again.
- if (CurrentTA != EndTA) break;
- }
+ /// &operator++ - Increment the iterator to the next template argument.
+ TSTiterator &operator++() {
+ ++SugaredIterator;
+ ++DesugaredIterator;
return *this;
}
/// operator* - Returns the appropriate TemplateArgument.
reference operator*() const {
- assert(!isEnd() && "Index exceeds number of arguments.");
- if (CurrentTA == EndTA)
- return TST->getArg(Index);
- else
- return *CurrentTA;
+ return *SugaredIterator;
}
/// operator-> - Allow access to the underlying TemplateArgument.
@@ -900,16 +1016,27 @@ class TemplateDiff {
return &operator*();
}
- /// getDesugar - Returns the deduced template argument from DesguarTST
- reference getDesugar() const {
- return DesugarTST->getArg(Index);
+ /// isEnd - Returns true if no more TemplateArguments are available.
+ bool isEnd() const {
+ return SugaredIterator.isEnd();
+ }
+
+ /// hasDesugaredTA - Returns true if there is another TemplateArgument
+ /// available.
+ bool hasDesugaredTA() const {
+ return !DesugaredIterator.isEnd();
+ }
+
+ /// getDesugaredTA - Returns the desugared TemplateArgument.
+ reference getDesugaredTA() const {
+ return *DesugaredIterator;
}
};
// These functions build up the template diff tree, including functions to
- // retrieve and compare template arguments.
+ // retrieve and compare template arguments.
- static const TemplateSpecializationType * GetTemplateSpecializationType(
+ static const TemplateSpecializationType *GetTemplateSpecializationType(
ASTContext &Context, QualType Ty) {
if (const TemplateSpecializationType *TST =
Ty->getAs<TemplateSpecializationType>())
@@ -935,108 +1062,136 @@ class TemplateDiff {
return Ty->getAs<TemplateSpecializationType>();
}
- /// DiffTypes - Fills a DiffNode with information about a type difference.
- void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter,
- TemplateTypeParmDecl *FromDefaultTypeDecl,
- TemplateTypeParmDecl *ToDefaultTypeDecl) {
- QualType FromType = GetType(FromIter, FromDefaultTypeDecl);
- QualType ToType = GetType(ToIter, ToDefaultTypeDecl);
-
- Tree.SetNode(FromType, ToType);
- Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
- ToIter.isEnd() && !ToType.isNull());
- Tree.SetKind(DiffTree::Type);
+ /// Returns true if the DiffType is Type and false for Template.
+ static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType,
+ QualType ToType,
+ const TemplateSpecializationType *&FromArgTST,
+ const TemplateSpecializationType *&ToArgTST) {
if (FromType.isNull() || ToType.isNull())
- return;
+ return true;
- if (Context.hasSameType(FromType, ToType)) {
- Tree.SetSame(true);
- return;
- }
+ if (Context.hasSameType(FromType, ToType))
+ return true;
- const TemplateSpecializationType *FromArgTST =
- GetTemplateSpecializationType(Context, FromType);
- if (!FromArgTST)
- return;
+ FromArgTST = GetTemplateSpecializationType(Context, FromType);
+ ToArgTST = GetTemplateSpecializationType(Context, ToType);
- const TemplateSpecializationType *ToArgTST =
- GetTemplateSpecializationType(Context, ToType);
- if (!ToArgTST)
- return;
+ if (!FromArgTST || !ToArgTST)
+ return true;
if (!hasSameTemplate(FromArgTST, ToArgTST))
- return;
+ return true;
- Qualifiers FromQual = FromType.getQualifiers(),
- ToQual = ToType.getQualifiers();
- FromQual -= QualType(FromArgTST, 0).getQualifiers();
- ToQual -= QualType(ToArgTST, 0).getQualifiers();
- Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
- ToArgTST->getTemplateName().getAsTemplateDecl());
- Tree.SetNode(FromQual, ToQual);
- Tree.SetKind(DiffTree::Template);
- DiffTemplate(FromArgTST, ToArgTST);
+ return false;
+ }
+
+ /// DiffTypes - Fills a DiffNode with information about a type difference.
+ void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) {
+ QualType FromType = GetType(FromIter);
+ QualType ToType = GetType(ToIter);
+
+ bool FromDefault = FromIter.isEnd() && !FromType.isNull();
+ bool ToDefault = ToIter.isEnd() && !ToType.isNull();
+
+ const TemplateSpecializationType *FromArgTST = nullptr;
+ const TemplateSpecializationType *ToArgTST = nullptr;
+ if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) {
+ Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault);
+ Tree.SetSame(!FromType.isNull() && !ToType.isNull() &&
+ Context.hasSameType(FromType, ToType));
+ } else {
+ assert(FromArgTST && ToArgTST &&
+ "Both template specializations need to be valid.");
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
+ FromQual -= QualType(FromArgTST, 0).getQualifiers();
+ ToQual -= QualType(ToArgTST, 0).getQualifiers();
+ Tree.SetTemplateDiff(FromArgTST->getTemplateName().getAsTemplateDecl(),
+ ToArgTST->getTemplateName().getAsTemplateDecl(),
+ FromQual, ToQual, FromDefault, ToDefault);
+ DiffTemplate(FromArgTST, ToArgTST);
+ }
}
/// DiffTemplateTemplates - Fills a DiffNode with information about a
/// template template difference.
void DiffTemplateTemplates(const TSTiterator &FromIter,
- const TSTiterator &ToIter,
- TemplateTemplateParmDecl *FromDefaultTemplateDecl,
- TemplateTemplateParmDecl *ToDefaultTemplateDecl) {
- TemplateDecl *FromDecl = GetTemplateDecl(FromIter, FromDefaultTemplateDecl);
- TemplateDecl *ToDecl = GetTemplateDecl(ToIter, ToDefaultTemplateDecl);
- Tree.SetNode(FromDecl, ToDecl);
+ const TSTiterator &ToIter) {
+ TemplateDecl *FromDecl = GetTemplateDecl(FromIter);
+ TemplateDecl *ToDecl = GetTemplateDecl(ToIter);
+ Tree.SetTemplateTemplateDiff(FromDecl, ToDecl, FromIter.isEnd() && FromDecl,
+ ToIter.isEnd() && ToDecl);
Tree.SetSame(FromDecl && ToDecl &&
FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl);
- Tree.SetKind(DiffTree::TemplateTemplate);
}
/// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes
- static void InitializeNonTypeDiffVariables(
- ASTContext &Context, const TSTiterator &Iter,
- NonTypeTemplateParmDecl *Default, bool &HasInt, bool &HasValueDecl,
- bool &IsNullPtr, Expr *&E, llvm::APSInt &Value, ValueDecl *&VD) {
- HasInt = !Iter.isEnd() && Iter->getKind() == TemplateArgument::Integral;
-
- HasValueDecl =
- !Iter.isEnd() && Iter->getKind() == TemplateArgument::Declaration;
-
- IsNullPtr = !Iter.isEnd() && Iter->getKind() == TemplateArgument::NullPtr;
-
- if (HasInt)
- Value = Iter->getAsIntegral();
- else if (HasValueDecl)
- VD = Iter->getAsDecl();
- else if (!IsNullPtr)
- E = GetExpr(Iter, Default);
-
- if (E && Default->getType()->isPointerType())
- IsNullPtr = CheckForNullPtr(Context, E);
- }
-
- /// NeedsAddressOf - Helper function for DiffNonTypes. Returns true if the
- /// ValueDecl needs a '&' when printed.
- static bool NeedsAddressOf(ValueDecl *VD, Expr *E,
- NonTypeTemplateParmDecl *Default) {
- if (!VD)
- return false;
-
- if (E) {
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
- if (UO->getOpcode() == UO_AddrOf) {
- return true;
+ static void InitializeNonTypeDiffVariables(ASTContext &Context,
+ const TSTiterator &Iter,
+ NonTypeTemplateParmDecl *Default,
+ llvm::APSInt &Value, bool &HasInt,
+ QualType &IntType, bool &IsNullPtr,
+ Expr *&E, ValueDecl *&VD,
+ bool &NeedAddressOf) {
+ if (!Iter.isEnd()) {
+ switch (Iter->getKind()) {
+ default:
+ llvm_unreachable("unknown ArgumentKind");
+ case TemplateArgument::Integral:
+ Value = Iter->getAsIntegral();
+ HasInt = true;
+ IntType = Iter->getIntegralType();
+ return;
+ case TemplateArgument::Declaration: {
+ VD = Iter->getAsDecl();
+ QualType ArgType = Iter->getParamTypeForDecl();
+ QualType VDType = VD->getType();
+ if (ArgType->isPointerType() &&
+ Context.hasSameType(ArgType->getPointeeType(), VDType))
+ NeedAddressOf = true;
+ return;
}
+ case TemplateArgument::NullPtr:
+ IsNullPtr = true;
+ return;
+ case TemplateArgument::Expression:
+ E = Iter->getAsExpr();
}
- return false;
+ } else if (!Default->isParameterPack()) {
+ E = Default->getDefaultArgument();
}
- if (!Default->getType()->isReferenceType()) {
- return true;
- }
+ if (!Iter.hasDesugaredTA()) return;
- return false;
+ const TemplateArgument& TA = Iter.getDesugaredTA();
+ switch (TA.getKind()) {
+ default:
+ llvm_unreachable("unknown ArgumentKind");
+ case TemplateArgument::Integral:
+ Value = TA.getAsIntegral();
+ HasInt = true;
+ IntType = TA.getIntegralType();
+ return;
+ case TemplateArgument::Declaration: {
+ VD = TA.getAsDecl();
+ QualType ArgType = TA.getParamTypeForDecl();
+ QualType VDType = VD->getType();
+ if (ArgType->isPointerType() &&
+ Context.hasSameType(ArgType->getPointeeType(), VDType))
+ NeedAddressOf = true;
+ return;
+ }
+ case TemplateArgument::NullPtr:
+ IsNullPtr = true;
+ return;
+ case TemplateArgument::Expression:
+ // TODO: Sometimes, the desugared template argument Expr differs from
+ // the sugared template argument Expr. It may be useful in the future
+ // but for now, it is just discarded.
+ if (!E)
+ E = TA.getAsExpr();
+ return;
+ }
}
/// DiffNonTypes - Handles any template parameters not handled by DiffTypes
@@ -1046,85 +1201,68 @@ class TemplateDiff {
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) {
Expr *FromExpr = nullptr, *ToExpr = nullptr;
llvm::APSInt FromInt, ToInt;
+ QualType FromIntType, ToIntType;
ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
- bool HasFromInt = false, HasToInt = false, HasFromValueDecl = false,
- HasToValueDecl = false, FromNullPtr = false, ToNullPtr = false;
- InitializeNonTypeDiffVariables(Context, FromIter, FromDefaultNonTypeDecl,
- HasFromInt, HasFromValueDecl, FromNullPtr,
- FromExpr, FromInt, FromValueDecl);
- InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl,
- HasToInt, HasToValueDecl, ToNullPtr,
- ToExpr, ToInt, ToValueDecl);
-
- assert(((!HasFromInt && !HasToInt) ||
- (!HasFromValueDecl && !HasToValueDecl)) &&
- "Template argument cannot be both integer and declaration");
-
- if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
- Tree.SetNode(FromExpr, ToExpr);
- Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr);
- if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType()) {
- if (FromExpr)
- HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt,
- FromDefaultNonTypeDecl->getType());
- if (ToExpr)
- HasToInt = GetInt(Context, ToIter, ToExpr, ToInt,
- ToDefaultNonTypeDecl->getType());
- }
- if (HasFromInt && HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(FromInt == ToInt);
- Tree.SetKind(DiffTree::Integer);
- } else if (HasFromInt || HasToInt) {
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(false);
- Tree.SetKind(DiffTree::Integer);
- } else {
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr) ||
- (FromNullPtr && ToNullPtr));
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetKind(DiffTree::Expression);
- }
+ bool HasFromInt = false, HasToInt = false, FromNullPtr = false,
+ ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false;
+ InitializeNonTypeDiffVariables(
+ Context, FromIter, FromDefaultNonTypeDecl, FromInt, HasFromInt,
+ FromIntType, FromNullPtr, FromExpr, FromValueDecl, NeedFromAddressOf);
+ InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl, ToInt,
+ HasToInt, ToIntType, ToNullPtr, ToExpr,
+ ToValueDecl, NeedToAddressOf);
+
+ bool FromDefault = FromIter.isEnd() &&
+ (FromExpr || FromValueDecl || HasFromInt || FromNullPtr);
+ bool ToDefault = ToIter.isEnd() &&
+ (ToExpr || ToValueDecl || HasToInt || ToNullPtr);
+
+ bool FromDeclaration = FromValueDecl || FromNullPtr;
+ bool ToDeclaration = ToValueDecl || ToNullPtr;
+
+ if (FromDeclaration && HasToInt) {
+ Tree.SetFromDeclarationAndToIntegerDiff(
+ FromValueDecl, NeedFromAddressOf, FromNullPtr, FromExpr, ToInt,
+ HasToInt, ToIntType, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(false);
+ return;
+
+ }
+
+ if (HasFromInt && ToDeclaration) {
+ Tree.SetFromIntegerAndToDeclarationDiff(
+ FromInt, HasFromInt, FromIntType, FromExpr, ToValueDecl,
+ NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(false);
return;
}
if (HasFromInt || HasToInt) {
- if (!HasFromInt && FromExpr)
- HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt,
- FromDefaultNonTypeDecl->getType());
- if (!HasToInt && ToExpr)
- HasToInt = GetInt(Context, ToIter, ToExpr, ToInt,
- ToDefaultNonTypeDecl->getType());
- Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetIntegerDiff(FromInt, ToInt, HasFromInt, HasToInt, FromIntType,
+ ToIntType, FromExpr, ToExpr, FromDefault, ToDefault);
if (HasFromInt && HasToInt) {
- Tree.SetSame(FromInt == ToInt);
- } else {
- Tree.SetSame(false);
+ Tree.SetSame(Context.hasSameType(FromIntType, ToIntType) &&
+ FromInt == ToInt);
}
- Tree.SetDefault(FromIter.isEnd() && HasFromInt,
- ToIter.isEnd() && HasToInt);
- Tree.SetKind(DiffTree::Integer);
return;
}
- if (!HasFromValueDecl && FromExpr)
- FromValueDecl = GetValueDecl(FromIter, FromExpr);
- if (!HasToValueDecl && ToExpr)
- ToValueDecl = GetValueDecl(ToIter, ToExpr);
-
- bool FromAddressOf =
- NeedsAddressOf(FromValueDecl, FromExpr, FromDefaultNonTypeDecl);
- bool ToAddressOf =
- NeedsAddressOf(ToValueDecl, ToExpr, ToDefaultNonTypeDecl);
-
- Tree.SetNullPtr(FromNullPtr, ToNullPtr);
- Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
- Tree.SetSame(FromValueDecl && ToValueDecl &&
- FromValueDecl->getCanonicalDecl() ==
- ToValueDecl->getCanonicalDecl());
- Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
- ToIter.isEnd() && ToValueDecl);
- Tree.SetKind(DiffTree::Declaration);
+ if (FromDeclaration || ToDeclaration) {
+ Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, NeedFromAddressOf,
+ NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
+ ToExpr, FromDefault, ToDefault);
+ bool BothNull = FromNullPtr && ToNullPtr;
+ bool SameValueDecl =
+ FromValueDecl && ToValueDecl &&
+ NeedFromAddressOf == NeedToAddressOf &&
+ FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl();
+ Tree.SetSame(BothNull || SameValueDecl);
+ return;
+ }
+
+ assert((FromExpr || ToExpr) && "Both template arguments cannot be empty.");
+ Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault);
+ Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
}
/// DiffTemplate - recursively visits template arguments and stores the
@@ -1149,28 +1287,23 @@ class TemplateDiff {
NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex);
NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex);
- TemplateTypeParmDecl *FromDefaultTypeDecl =
- dyn_cast<TemplateTypeParmDecl>(FromParamND);
- TemplateTypeParmDecl *ToDefaultTypeDecl =
- dyn_cast<TemplateTypeParmDecl>(ToParamND);
- if (FromDefaultTypeDecl && ToDefaultTypeDecl)
- DiffTypes(FromIter, ToIter, FromDefaultTypeDecl, ToDefaultTypeDecl);
-
- TemplateTemplateParmDecl *FromDefaultTemplateDecl =
- dyn_cast<TemplateTemplateParmDecl>(FromParamND);
- TemplateTemplateParmDecl *ToDefaultTemplateDecl =
- dyn_cast<TemplateTemplateParmDecl>(ToParamND);
- if (FromDefaultTemplateDecl && ToDefaultTemplateDecl)
- DiffTemplateTemplates(FromIter, ToIter, FromDefaultTemplateDecl,
- ToDefaultTemplateDecl);
-
- NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
- dyn_cast<NonTypeTemplateParmDecl>(FromParamND);
- NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
- dyn_cast<NonTypeTemplateParmDecl>(ToParamND);
- if (FromDefaultNonTypeDecl && ToDefaultNonTypeDecl)
+ assert(FromParamND->getKind() == ToParamND->getKind() &&
+ "Parameter Decl are not the same kind.");
+
+ if (isa<TemplateTypeParmDecl>(FromParamND)) {
+ DiffTypes(FromIter, ToIter);
+ } else if (isa<TemplateTemplateParmDecl>(FromParamND)) {
+ DiffTemplateTemplates(FromIter, ToIter);
+ } else if (isa<NonTypeTemplateParmDecl>(FromParamND)) {
+ NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
+ cast<NonTypeTemplateParmDecl>(FromParamND);
+ NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
+ cast<NonTypeTemplateParmDecl>(ToParamND);
DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl,
ToDefaultNonTypeDecl);
+ } else {
+ llvm_unreachable("Unexpected Decl type.");
+ }
++FromIter;
++ToIter;
@@ -1239,140 +1372,27 @@ class TemplateDiff {
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- static QualType GetType(const TSTiterator &Iter,
- TemplateTypeParmDecl *DefaultTTPD) {
- bool isVariadic = DefaultTTPD->isParameterPack();
-
+ static QualType GetType(const TSTiterator &Iter) {
if (!Iter.isEnd())
return Iter->getAsType();
- if (isVariadic)
- return QualType();
-
- QualType ArgType = DefaultTTPD->getDefaultArgument();
- if (ArgType->isDependentType())
- return Iter.getDesugar().getAsType();
-
- return ArgType;
- }
-
- /// GetExpr - Retrieves the template expression argument, including default
- /// arguments.
- static Expr *GetExpr(const TSTiterator &Iter,
- NonTypeTemplateParmDecl *DefaultNTTPD) {
- Expr *ArgExpr = nullptr;
- bool isVariadic = DefaultNTTPD->isParameterPack();
-
- if (!Iter.isEnd())
- ArgExpr = Iter->getAsExpr();
- else if (!isVariadic)
- ArgExpr = DefaultNTTPD->getDefaultArgument();
-
- if (ArgExpr)
- while (SubstNonTypeTemplateParmExpr *SNTTPE =
- dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))
- ArgExpr = SNTTPE->getReplacement();
-
- return ArgExpr;
- }
-
- /// GetInt - Retrieves the template integer argument, including evaluating
- /// default arguments. If the value comes from an expression, extend the
- /// APSInt to size of IntegerType to match the behavior in
- /// Sema::CheckTemplateArgument
- static bool GetInt(ASTContext &Context, const TSTiterator &Iter,
- Expr *ArgExpr, llvm::APSInt &Int, QualType IntegerType) {
- // Default, value-depenedent expressions require fetching
- // from the desugared TemplateArgument, otherwise expression needs to
- // be evaluatable.
- if (Iter.isEnd() && ArgExpr->isValueDependent()) {
- switch (Iter.getDesugar().getKind()) {
- case TemplateArgument::Integral:
- Int = Iter.getDesugar().getAsIntegral();
- return true;
- case TemplateArgument::Expression:
- ArgExpr = Iter.getDesugar().getAsExpr();
- Int = ArgExpr->EvaluateKnownConstInt(Context);
- Int = Int.extOrTrunc(Context.getTypeSize(IntegerType));
- return true;
- default:
- llvm_unreachable("Unexpected template argument kind");
- }
- } else if (ArgExpr->isEvaluatable(Context)) {
- Int = ArgExpr->EvaluateKnownConstInt(Context);
- Int = Int.extOrTrunc(Context.getTypeSize(IntegerType));
- return true;
- }
-
- return false;
- }
-
- /// GetValueDecl - Retrieves the template Decl argument, including
- /// default expression argument.
- static ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
- // Default, value-depenedent expressions require fetching
- // from the desugared TemplateArgument
- if (Iter.isEnd() && ArgExpr->isValueDependent())
- switch (Iter.getDesugar().getKind()) {
- case TemplateArgument::Declaration:
- return Iter.getDesugar().getAsDecl();
- case TemplateArgument::Expression:
- ArgExpr = Iter.getDesugar().getAsExpr();
- return cast<DeclRefExpr>(ArgExpr)->getDecl();
- default:
- llvm_unreachable("Unexpected template argument kind");
- }
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
- if (!DRE) {
- UnaryOperator *UO = dyn_cast<UnaryOperator>(ArgExpr->IgnoreParens());
- if (!UO)
- return nullptr;
- DRE = cast<DeclRefExpr>(UO->getSubExpr());
- }
-
- return DRE->getDecl();
- }
-
- /// CheckForNullPtr - returns true if the expression can be evaluated as
- /// a null pointer
- static bool CheckForNullPtr(ASTContext &Context, Expr *E) {
- assert(E && "Expected expression");
-
- E = E->IgnoreParenCasts();
- if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
- return true;
-
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
- if (!DRE)
- return false;
-
- VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
- if (!VD || !VD->hasInit())
- return false;
-
- return VD->getInit()->IgnoreParenCasts()->isNullPointerConstant(
- Context, Expr::NPC_ValueDependentIsNull);
+ if (Iter.hasDesugaredTA())
+ return Iter.getDesugaredTA().getAsType();
+ return QualType();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
- TemplateTemplateParmDecl *DefaultTTPD) {
- bool isVariadic = DefaultTTPD->isParameterPack();
-
- TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
- TemplateDecl *DefaultTD = nullptr;
- if (TA.getKind() != TemplateArgument::Null)
- DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
-
+ static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) {
if (!Iter.isEnd())
return Iter->getAsTemplate().getAsTemplateDecl();
- if (!isVariadic)
- return DefaultTD;
-
+ if (Iter.hasDesugaredTA())
+ return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl();
return nullptr;
}
- /// IsEqualExpr - Returns true if the expressions evaluate to the same value.
+ /// IsEqualExpr - Returns true if the expressions are the same in regards to
+ /// template arguments. These expressions are dependent, so profile them
+ /// instead of trying to evaluate them.
static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
if (FromExpr == ToExpr)
return true;
@@ -1380,47 +1400,10 @@ class TemplateDiff {
if (!FromExpr || !ToExpr)
return false;
- DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr->IgnoreParens()),
- *ToDRE = dyn_cast<DeclRefExpr>(ToExpr->IgnoreParens());
-
- if (FromDRE || ToDRE) {
- if (!FromDRE || !ToDRE)
- return false;
- return FromDRE->getDecl() == ToDRE->getDecl();
- }
-
- Expr::EvalResult FromResult, ToResult;
- if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
- !ToExpr->EvaluateAsRValue(ToResult, Context)) {
- llvm::FoldingSetNodeID FromID, ToID;
- FromExpr->Profile(FromID, Context, true);
- ToExpr->Profile(ToID, Context, true);
- return FromID == ToID;
- }
-
- APValue &FromVal = FromResult.Val;
- APValue &ToVal = ToResult.Val;
-
- if (FromVal.getKind() != ToVal.getKind()) return false;
-
- switch (FromVal.getKind()) {
- case APValue::Int:
- return FromVal.getInt() == ToVal.getInt();
- case APValue::LValue: {
- APValue::LValueBase FromBase = FromVal.getLValueBase();
- APValue::LValueBase ToBase = ToVal.getLValueBase();
- if (FromBase.isNull() && ToBase.isNull())
- return true;
- if (FromBase.isNull() || ToBase.isNull())
- return false;
- return FromBase.get<const ValueDecl*>() ==
- ToBase.get<const ValueDecl*>();
- }
- case APValue::MemberPointer:
- return FromVal.getMemberPointerDecl() == ToVal.getMemberPointerDecl();
- default:
- llvm_unreachable("Unknown template argument expression.");
- }
+ llvm::FoldingSetNodeID FromID, ToID;
+ FromExpr->Profile(FromID, Context, true);
+ ToExpr->Profile(ToID, Context, true);
+ return FromID == ToID;
}
// These functions converts the tree representation of the template
@@ -1442,21 +1425,21 @@ class TemplateDiff {
llvm_unreachable("Template diffing failed with bad DiffNode");
case DiffTree::Type: {
QualType FromType, ToType;
- Tree.GetNode(FromType, ToType);
+ Tree.GetTypeDiff(FromType, ToType);
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
- Tree.GetNode(FromExpr, ToExpr);
- PrintExpr(FromExpr, ToExpr, Tree.FromNullPtr(), Tree.ToNullPtr(),
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ Tree.GetExpressionDiff(FromExpr, ToExpr);
+ PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
+ Tree.NodeIsSame());
return;
}
case DiffTree::TemplateTemplate: {
TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
+ Tree.GetTemplateTemplateDiff(FromTD, ToTD);
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
Tree.ToDefault(), Tree.NodeIsSame());
return;
@@ -1465,26 +1448,70 @@ class TemplateDiff {
llvm::APSInt FromInt, ToInt;
Expr *FromExpr, *ToExpr;
bool IsValidFromInt, IsValidToInt;
- Tree.GetNode(FromExpr, ToExpr);
- Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
- PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
- FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
- Tree.NodeIsSame());
+ QualType FromIntType, ToIntType;
+ Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt,
+ FromIntType, ToIntType, FromExpr, ToExpr);
+ PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType,
+ ToIntType, FromExpr, ToExpr, Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Declaration: {
ValueDecl *FromValueDecl, *ToValueDecl;
bool FromAddressOf, ToAddressOf;
- Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ bool FromNullPtr, ToNullPtr;
+ Expr *FromExpr, *ToExpr;
+ Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf,
+ ToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
+ ToExpr);
PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
- Tree.FromNullPtr(), Tree.ToNullPtr(), Tree.FromDefault(),
- Tree.ToDefault(), Tree.NodeIsSame());
+ FromNullPtr, ToNullPtr, FromExpr, ToExpr,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
+ case DiffTree::FromDeclarationAndToInteger: {
+ ValueDecl *FromValueDecl;
+ bool FromAddressOf;
+ bool FromNullPtr;
+ Expr *FromExpr;
+ llvm::APSInt ToInt;
+ bool IsValidToInt;
+ QualType ToIntType;
+ Expr *ToExpr;
+ Tree.GetFromDeclarationAndToIntegerDiff(
+ FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt,
+ IsValidToInt, ToIntType, ToExpr);
+ assert((FromValueDecl || FromNullPtr) && IsValidToInt);
+ PrintValueDeclAndInteger(FromValueDecl, FromAddressOf, FromNullPtr,
+ FromExpr, Tree.FromDefault(), ToInt, ToIntType,
+ ToExpr, Tree.ToDefault());
+ return;
+ }
+ case DiffTree::FromIntegerAndToDeclaration: {
+ llvm::APSInt FromInt;
+ bool IsValidFromInt;
+ QualType FromIntType;
+ Expr *FromExpr;
+ ValueDecl *ToValueDecl;
+ bool ToAddressOf;
+ bool ToNullPtr;
+ Expr *ToExpr;
+ Tree.GetFromIntegerAndToDeclarationDiff(
+ FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl,
+ ToAddressOf, ToNullPtr, ToExpr);
+ assert(IsValidFromInt && (ToValueDecl || ToNullPtr));
+ PrintIntegerAndValueDecl(FromInt, FromIntType, FromExpr,
+ Tree.FromDefault(), ToValueDecl, ToAddressOf,
+ ToNullPtr, ToExpr, Tree.ToDefault());
return;
}
case DiffTree::Template: {
// Node is root of template. Recurse on children.
TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
+ Qualifiers FromQual, ToQual;
+ Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual);
+
+ PrintQualifiers(FromQual, ToQual);
if (!Tree.HasChildren()) {
// If we're dealing with a template specialization with zero
@@ -1493,11 +1520,7 @@ class TemplateDiff {
return;
}
- Qualifiers FromQual, ToQual;
- Tree.GetNode(FromQual, ToQual);
- PrintQualifiers(FromQual, ToQual);
-
- OS << FromTD->getNameAsString() << '<';
+ OS << FromTD->getNameAsString() << '<';
Tree.MoveToChild();
unsigned NumElideArgs = 0;
do {
@@ -1604,40 +1627,36 @@ class TemplateDiff {
/// PrintExpr - Prints out the expr template arguments, highlighting argument
/// differences.
- void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromNullPtr,
- bool ToNullPtr, bool FromDefault, bool ToDefault, bool Same) {
+ void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault,
+ bool ToDefault, bool Same) {
assert((FromExpr || ToExpr) &&
"Only one template argument may be missing.");
if (Same) {
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- PrintExpr(FromExpr, FromNullPtr);
+ PrintExpr(FromExpr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- PrintExpr(ToExpr, ToNullPtr);
+ PrintExpr(ToExpr);
Unbold();
OS << ']';
}
}
/// PrintExpr - Actual formatting and printing of expressions.
- void PrintExpr(const Expr *E, bool NullPtr = false) {
+ void PrintExpr(const Expr *E) {
if (E) {
E->printPretty(OS, nullptr, Policy);
return;
}
- if (NullPtr) {
- OS << "nullptr";
- return;
- }
OS << "(no argument)";
}
@@ -1677,28 +1696,40 @@ class TemplateDiff {
/// PrintAPSInt - Handles printing of integral arguments, highlighting
/// argument differences.
void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr,
- Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) {
+ bool IsValidFromInt, bool IsValidToInt, QualType FromIntType,
+ QualType ToIntType, Expr *FromExpr, Expr *ToExpr,
+ bool FromDefault, bool ToDefault, bool Same) {
assert((IsValidFromInt || IsValidToInt) &&
"Only one integral argument may be missing.");
if (Same) {
- OS << FromInt.toString(10);
- } else if (!PrintTree) {
+ if (FromIntType->isBooleanType()) {
+ OS << ((FromInt == 0) ? "false" : "true");
+ } else {
+ OS << FromInt.toString(10);
+ }
+ return;
+ }
+
+ bool PrintType = IsValidFromInt && IsValidToInt &&
+ !Context.hasSameType(FromIntType, ToIntType);
+
+ if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
- PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
} else {
OS << (FromDefault ? "[(default) " : "[");
- PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
OS << " != " << (ToDefault ? "(default) " : "");
- PrintAPSInt(ToInt, ToExpr, IsValidToInt);
+ PrintAPSInt(ToInt, ToExpr, IsValidToInt, ToIntType, PrintType);
OS << ']';
}
}
/// PrintAPSInt - If valid, print the APSInt. If the expression is
/// gives more information, print it too.
- void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) {
+ void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid, QualType IntType,
+ bool PrintType) {
Bold();
if (Valid) {
if (HasExtraInfo(E)) {
@@ -1707,7 +1738,20 @@ class TemplateDiff {
OS << " aka ";
Bold();
}
- OS << Val.toString(10);
+ if (PrintType) {
+ Unbold();
+ OS << "(";
+ Bold();
+ IntType.print(OS, Context.getPrintingPolicy());
+ Unbold();
+ OS << ") ";
+ Bold();
+ }
+ if (IntType->isBooleanType()) {
+ OS << ((Val == 0) ? "false" : "true");
+ } else {
+ OS << Val.toString(10);
+ }
} else if (E) {
PrintExpr(E);
} else {
@@ -1716,8 +1760,8 @@ class TemplateDiff {
Unbold();
}
- /// HasExtraInfo - Returns true if E is not an integer literal or the
- /// negation of an integer literal
+ /// HasExtraInfo - Returns true if E is not an integer literal, the
+ /// negation of an integer literal, or a boolean literal.
bool HasExtraInfo(Expr *E) {
if (!E) return false;
@@ -1730,10 +1774,13 @@ class TemplateDiff {
if (isa<IntegerLiteral>(UO->getSubExpr()))
return false;
+ if (isa<CXXBoolLiteralExpr>(E))
+ return false;
+
return true;
}
- void PrintValueDecl(ValueDecl *VD, bool AddressOf, bool NullPtr) {
+ void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) {
if (VD) {
if (AddressOf)
OS << "&";
@@ -1742,6 +1789,17 @@ class TemplateDiff {
}
if (NullPtr) {
+ if (E && !isa<CXXNullPtrLiteralExpr>(E)) {
+ PrintExpr(E);
+ if (IsBold) {
+ Unbold();
+ OS << " aka ";
+ Bold();
+ } else {
+ OS << " aka ";
+ }
+ }
+
OS << "nullptr";
return;
}
@@ -1753,30 +1811,72 @@ class TemplateDiff {
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
bool FromAddressOf, bool ToAddressOf, bool FromNullPtr,
- bool ToNullPtr, bool FromDefault, bool ToDefault,
- bool Same) {
+ bool ToNullPtr, Expr *FromExpr, Expr *ToExpr,
+ bool FromDefault, bool ToDefault, bool Same) {
assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) &&
"Only one Decl argument may be NULL");
if (Same) {
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- PrintValueDecl(ToValueDecl, ToAddressOf, ToNullPtr);
+ PrintValueDecl(ToValueDecl, ToAddressOf, ToExpr, ToNullPtr);
+ Unbold();
+ OS << ']';
+ }
+
+ }
+
+ /// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and
+ /// APSInt to print a mixed difference.
+ void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf,
+ bool IsNullPtr, Expr *VDExpr, bool DefaultDecl,
+ llvm::APSInt Val, QualType IntType,
+ Expr *IntExpr, bool DefaultInt) {
+ if (!PrintTree) {
+ OS << (DefaultDecl ? "(default) " : "");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
Unbold();
+ } else {
+ OS << (DefaultDecl ? "[(default) " : "[");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
+ Unbold();
+ OS << " != " << (DefaultInt ? "(default) " : "");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
OS << ']';
}
+ }
+ /// PrintIntegerAndValueDecl - Uses the print functions for APSInt and
+ /// ValueDecl to print a mixed difference.
+ void PrintIntegerAndValueDecl(llvm::APSInt Val, QualType IntType,
+ Expr *IntExpr, bool DefaultInt, ValueDecl *VD,
+ bool NeedAddressOf, bool IsNullPtr,
+ Expr *VDExpr, bool DefaultDecl) {
+ if (!PrintTree) {
+ OS << (DefaultInt ? "(default) " : "");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
+ } else {
+ OS << (DefaultInt ? "[(default) " : "[");
+ PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
+ OS << " != " << (DefaultDecl ? "(default) " : "");
+ Bold();
+ PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
+ Unbold();
+ OS << ']';
+ }
}
// Prints the appropriate placeholder for elided template arguments.
@@ -1866,21 +1966,21 @@ public:
PrintTree(PrintTree),
ShowColor(ShowColor),
// When printing a single type, the FromType is the one printed.
- FromType(PrintFromType ? FromType : ToType),
- ToType(PrintFromType ? ToType : FromType),
+ FromTemplateType(PrintFromType ? FromType : ToType),
+ ToTemplateType(PrintFromType ? ToType : FromType),
OS(OS),
IsBold(false) {
}
/// DiffTemplate - Start the template type diffing.
void DiffTemplate() {
- Qualifiers FromQual = FromType.getQualifiers(),
- ToQual = ToType.getQualifiers();
+ Qualifiers FromQual = FromTemplateType.getQualifiers(),
+ ToQual = ToTemplateType.getQualifiers();
const TemplateSpecializationType *FromOrigTST =
- GetTemplateSpecializationType(Context, FromType);
+ GetTemplateSpecializationType(Context, FromTemplateType);
const TemplateSpecializationType *ToOrigTST =
- GetTemplateSpecializationType(Context, ToType);
+ GetTemplateSpecializationType(Context, ToTemplateType);
// Only checking templates.
if (!FromOrigTST || !ToOrigTST)
@@ -1893,13 +1993,12 @@ public:
FromQual -= QualType(FromOrigTST, 0).getQualifiers();
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
- Tree.SetNode(FromType, ToType);
- Tree.SetNode(FromQual, ToQual);
- Tree.SetKind(DiffTree::Template);
// Same base template, but different arguments.
- Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
- ToOrigTST->getTemplateName().getAsTemplateDecl());
+ Tree.SetTemplateDiff(FromOrigTST->getTemplateName().getAsTemplateDecl(),
+ ToOrigTST->getTemplateName().getAsTemplateDecl(),
+ FromQual, ToQual, false /*FromDefault*/,
+ false /*ToDefault*/);
DiffTemplate(FromOrigTST, ToOrigTST);
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1bc6c51b9b85..4f0b12489569 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -6151,6 +6151,12 @@ public:
Builder.defineMacro("__s390x__");
Builder.defineMacro("__zarch__");
Builder.defineMacro("__LONG_DOUBLE_128__");
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+
if (HasTransactionalExecution)
Builder.defineMacro("__HTM__");
if (Opts.ZVector)
diff --git a/lib/CodeGen/Address.h b/lib/CodeGen/Address.h
index 9d145fa26b5f..334308081ff3 100644
--- a/lib/CodeGen/Address.h
+++ b/lib/CodeGen/Address.h
@@ -104,23 +104,15 @@ public:
};
}
-}
-namespace llvm {
- // Present a minimal LLVM-like casting interface.
- template <class U> inline U cast(clang::CodeGen::Address addr) {
- return U::castImpl(addr);
- }
- template <class U> inline bool isa(clang::CodeGen::Address addr) {
- return U::isaImpl(addr);
- }
+// Present a minimal LLVM-like casting interface.
+template <class U> inline U cast(CodeGen::Address addr) {
+ return U::castImpl(addr);
+}
+template <class U> inline bool isa(CodeGen::Address addr) {
+ return U::isaImpl(addr);
}
-namespace clang {
- // Make our custom isa and cast available in namespace clang, to mirror
- // what we do for LLVM's versions in Basic/LLVM.h.
- using llvm::isa;
- using llvm::cast;
}
#endif
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 015a7396ffbe..5cfacacbe01a 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -483,7 +483,7 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
if (ThreadID != nullptr)
return ThreadID;
}
- if (auto OMPRegionInfo =
+ if (auto *OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
if (OMPRegionInfo->getThreadIDVariable()) {
// Check if this an outlined function with thread id passed as argument.
@@ -1356,7 +1356,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
// return the address of that temp.
Address CGOpenMPRuntime::emitThreadIDAddress(CodeGenFunction &CGF,
SourceLocation Loc) {
- if (auto OMPRegionInfo =
+ if (auto *OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo))
if (OMPRegionInfo->getThreadIDVariable())
return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress();
@@ -1717,15 +1717,10 @@ void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
}
// Build call __kmpc_cancel_barrier(loc, thread_id) or __kmpc_barrier(loc,
// thread_id);
- auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo);
- // Do not emit barrier call in the single directive emitted in some rare cases
- // for sections directives.
- if (OMPRegionInfo && OMPRegionInfo->getDirectiveKind() == OMPD_single)
- return;
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
getThreadID(CGF, Loc)};
- if (OMPRegionInfo) {
+ if (auto *OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) {
auto *Result = CGF.EmitRuntimeCall(
createRuntimeFunction(OMPRTL__kmpc_cancel_barrier), Args);
@@ -3649,8 +3644,6 @@ void CGOpenMPRuntime::emitCancellationPointCall(
// global_tid, kmp_int32 cncl_kind);
if (auto *OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (OMPRegionInfo->getDirectiveKind() == OMPD_single)
- return;
if (OMPRegionInfo->hasCancel()) {
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
@@ -3687,8 +3680,6 @@ void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
// kmp_int32 cncl_kind);
if (auto *OMPRegionInfo =
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (OMPRegionInfo->getDirectiveKind() == OMPD_single)
- return;
auto &&ThenGen = [this, Loc, CancelRegion,
OMPRegionInfo](CodeGenFunction &CGF) {
llvm::Value *Args[] = {
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 68555128ea01..59821a8d0330 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1657,50 +1657,51 @@ OpenMPDirectiveKind
CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
auto *Stmt = cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
auto *CS = dyn_cast<CompoundStmt>(Stmt);
- if (CS && CS->size() > 1) {
- bool HasLastprivates = false;
- auto &&CodeGen = [&S, CS, &HasLastprivates](CodeGenFunction &CGF) {
- auto &C = CGF.CGM.getContext();
- auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
- // Emit helper vars inits.
- LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
- CGF.Builder.getInt32(0));
- auto *GlobalUBVal = CGF.Builder.getInt32(CS->size() - 1);
- LValue UB =
- createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
- LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
- CGF.Builder.getInt32(1));
- LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
- CGF.Builder.getInt32(0));
- // Loop counter.
- LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
- OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
- CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
- OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
- CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
- // Generate condition for loop.
- BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
- OK_Ordinary, S.getLocStart(),
- /*fpContractable=*/false);
- // Increment for loop counter.
- UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue,
- OK_Ordinary, S.getLocStart());
- auto BodyGen = [CS, &S, &IV](CodeGenFunction &CGF) {
- // Iterate through all sections and emit a switch construct:
- // switch (IV) {
- // case 0:
- // <SectionStmt[0]>;
- // break;
- // ...
- // case <NumSection> - 1:
- // <SectionStmt[<NumSection> - 1]>;
- // break;
- // }
- // .omp.sections.exit:
- auto *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
- auto *SwitchStmt = CGF.Builder.CreateSwitch(
- CGF.EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB,
- CS->size());
+ bool HasLastprivates = false;
+ auto &&CodeGen = [&S, Stmt, CS, &HasLastprivates](CodeGenFunction &CGF) {
+ auto &C = CGF.CGM.getContext();
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ // Emit helper vars inits.
+ LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.",
+ CGF.Builder.getInt32(0));
+ auto *GlobalUBVal = CS != nullptr ? CGF.Builder.getInt32(CS->size() - 1)
+ : CGF.Builder.getInt32(0);
+ LValue UB =
+ createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal);
+ LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.",
+ CGF.Builder.getInt32(1));
+ LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.",
+ CGF.Builder.getInt32(0));
+ // Loop counter.
+ LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv.");
+ OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV);
+ OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
+ // Generate condition for loop.
+ BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
+ OK_Ordinary, S.getLocStart(),
+ /*fpContractable=*/false);
+ // Increment for loop counter.
+ UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
+ S.getLocStart());
+ auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) {
+ // Iterate through all sections and emit a switch construct:
+ // switch (IV) {
+ // case 0:
+ // <SectionStmt[0]>;
+ // break;
+ // ...
+ // case <NumSection> - 1:
+ // <SectionStmt[<NumSection> - 1]>;
+ // break;
+ // }
+ // .omp.sections.exit:
+ auto *ExitBB = CGF.createBasicBlock(".omp.sections.exit");
+ auto *SwitchStmt = CGF.Builder.CreateSwitch(
+ CGF.EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB,
+ CS == nullptr ? 1 : CS->size());
+ if (CS) {
unsigned CaseNumber = 0;
for (auto *SubStmt : CS->children()) {
auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
@@ -1710,99 +1711,72 @@ CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
CGF.EmitBranch(ExitBB);
++CaseNumber;
}
- CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
- };
-
- CodeGenFunction::OMPPrivateScope LoopScope(CGF);
- if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // initialization of firstprivate variables.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
+ } else {
+ auto CaseBB = CGF.createBasicBlock(".omp.sections.case");
+ CGF.EmitBlock(CaseBB);
+ SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB);
+ CGF.EmitStmt(Stmt);
+ CGF.EmitBranch(ExitBB);
}
- CGF.EmitOMPPrivateClause(S, LoopScope);
- HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
- CGF.EmitOMPReductionClauseInit(S, LoopScope);
- (void)LoopScope.Privatize();
-
- // Emit static non-chunked loop.
- CGF.CGM.getOpenMPRuntime().emitForStaticInit(
- CGF, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32,
- /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
- LB.getAddress(), UB.getAddress(), ST.getAddress());
- // UB = min(UB, GlobalUB);
- auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart());
- auto *MinUBGlobalUB = CGF.Builder.CreateSelect(
- CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
- CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
- // IV = LB;
- CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV);
- // while (idx <= UB) { BODY; ++idx; }
- CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
- [](CodeGenFunction &) {});
- // Tell the runtime we are done.
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocStart());
- CGF.EmitOMPReductionClauseFinal(S);
-
- // Emit final copy of the lastprivate variables if IsLastIter != 0.
- if (HasLastprivates)
- CGF.EmitOMPLastprivateClauseFinal(
- S, CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getLocStart())));
+ CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
};
- bool HasCancel = false;
- if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
- HasCancel = OSD->hasCancel();
- else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
- HasCancel = OPSD->hasCancel();
- CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
- HasCancel);
- // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
- // clause. Otherwise the barrier will be generated by the codegen for the
- // directive.
- if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
+ CodeGenFunction::OMPPrivateScope LoopScope(CGF);
+ if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables.
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
- OMPD_unknown);
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(
+ CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false,
+ /*ForceSimpleCall=*/true);
}
- return OMPD_sections;
- }
- // If only one section is found - no need to generate loop, emit as a single
- // region.
- bool HasFirstprivates;
- // No need to generate reductions for sections with single section region, we
- // can use original shared variables for all operations.
- bool HasReductions = S.hasClausesOfKind<OMPReductionClause>();
- // No need to generate lastprivates for sections with single section region,
- // we can use original shared variable for all calculations with barrier at
- // the end of the sections.
- bool HasLastprivates = S.hasClausesOfKind<OMPLastprivateClause>();
- auto &&CodeGen = [Stmt, &S, &HasFirstprivates](CodeGenFunction &CGF) {
- CodeGenFunction::OMPPrivateScope SingleScope(CGF);
- HasFirstprivates = CGF.EmitOMPFirstprivateClause(S, SingleScope);
- CGF.EmitOMPPrivateClause(S, SingleScope);
- (void)SingleScope.Privatize();
+ CGF.EmitOMPPrivateClause(S, LoopScope);
+ HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope);
+ CGF.EmitOMPReductionClauseInit(S, LoopScope);
+ (void)LoopScope.Privatize();
+
+ // Emit static non-chunked loop.
+ CGF.CGM.getOpenMPRuntime().emitForStaticInit(
+ CGF, S.getLocStart(), OMPC_SCHEDULE_static, /*IVSize=*/32,
+ /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), LB.getAddress(),
+ UB.getAddress(), ST.getAddress());
+ // UB = min(UB, GlobalUB);
+ auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart());
+ auto *MinUBGlobalUB = CGF.Builder.CreateSelect(
+ CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal);
+ CGF.EmitStoreOfScalar(MinUBGlobalUB, UB);
+ // IV = LB;
+ CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV);
+ // while (idx <= UB) { BODY; ++idx; }
+ CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen,
+ [](CodeGenFunction &) {});
+ // Tell the runtime we are done.
+ CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocStart());
+ CGF.EmitOMPReductionClauseFinal(S);
- CGF.EmitStmt(Stmt);
+ // Emit final copy of the lastprivate variables if IsLastIter != 0.
+ if (HasLastprivates)
+ CGF.EmitOMPLastprivateClauseFinal(
+ S, CGF.Builder.CreateIsNotNull(
+ CGF.EmitLoadOfScalar(IL, S.getLocStart())));
};
- CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(),
- llvm::None, llvm::None, llvm::None,
- llvm::None);
- // Emit barrier for firstprivates, lastprivates or reductions only if
- // 'sections' directive has 'nowait' clause. Otherwise the barrier will be
- // generated by the codegen for the directive.
- if ((HasFirstprivates || HasLastprivates || HasReductions) &&
- S.getSingleClause<OMPNowaitClause>()) {
+
+ bool HasCancel = false;
+ if (auto *OSD = dyn_cast<OMPSectionsDirective>(&S))
+ HasCancel = OSD->hasCancel();
+ else if (auto *OPSD = dyn_cast<OMPParallelSectionsDirective>(&S))
+ HasCancel = OPSD->hasCancel();
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen,
+ HasCancel);
+ // Emit barrier for lastprivates only if 'sections' directive has 'nowait'
+ // clause. Otherwise the barrier will be generated by the codegen for the
+ // directive.
+ if (HasLastprivates && S.getSingleClause<OMPNowaitClause>()) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables.
- CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_unknown,
- /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
+ OMPD_unknown);
}
- return OMPD_single;
+ return OMPD_sections;
}
void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) {
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index beede2e05804..b669353a036c 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -3233,6 +3233,8 @@ ToolChain::CXXStdlibType NetBSD::GetCXXStdlibType(const ArgList &Args) const {
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return ToolChain::CST_Libcxx;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 5a2dbd388fc1..b7ac24fe674e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -8317,6 +8317,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
useLibgcc = false;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 11f232934e5a..82d81a85fa90 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1742,13 +1742,18 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
/// otherwise. Loc is the location where this routine should point to
/// if there is an error, and Range is the source range to highlight
/// if there is an error.
+///
+/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the
+/// diagnostic for the respective type of error will be suppressed, but the
+/// check for ill-formed code will still be performed.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name,
- CXXCastPath *BasePath) {
+ CXXCastPath *BasePath,
+ bool IgnoreAccess) {
// First, determine whether the path from Derived to Base is
// ambiguous. This is slightly more expensive than checking whether
// the Derived to Base conversion exists, because here we need to
@@ -1761,7 +1766,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (InaccessibleBaseID) {
+ if (!IgnoreAccess) {
// Check that the base class can be accessed.
switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
InaccessibleBaseID)) {
@@ -1810,12 +1815,10 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
CXXCastPath *BasePath,
bool IgnoreAccess) {
- return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? 0
- : diag::err_upcast_to_inaccessible_base,
- diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName(),
- BasePath);
+ return CheckDerivedToBaseConversion(
+ Derived, Base, diag::err_upcast_to_inaccessible_base,
+ diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName(),
+ BasePath, IgnoreAccess);
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3e89af625d1a..ebf79812d8dc 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3748,6 +3748,128 @@ bool Sema::CheckVecStepExpr(Expr *E) {
return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep);
}
+static void captureVariablyModifiedType(ASTContext &Context, QualType T,
+ CapturingScopeInfo *CSI) {
+ assert(T->isVariablyModifiedType());
+ assert(CSI != nullptr);
+
+ // We're going to walk down into the type and look for VLA expressions.
+ do {
+ const Type *Ty = T.getTypePtr();
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ T = QualType();
+ break;
+ // These types are never variably-modified.
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Record:
+ case Type::Enum:
+ case Type::Elaborated:
+ case Type::TemplateSpecialization:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ case Type::Pipe:
+ llvm_unreachable("type class is never variably-modified!");
+ case Type::Adjusted:
+ T = cast<AdjustedType>(Ty)->getOriginalType();
+ break;
+ case Type::Decayed:
+ T = cast<DecayedType>(Ty)->getPointeeType();
+ break;
+ case Type::Pointer:
+ T = cast<PointerType>(Ty)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ T = cast<BlockPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ T = cast<ReferenceType>(Ty)->getPointeeType();
+ break;
+ case Type::MemberPointer:
+ T = cast<MemberPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // Losing element qualification here is fine.
+ T = cast<ArrayType>(Ty)->getElementType();
+ break;
+ case Type::VariableArray: {
+ // Losing element qualification here is fine.
+ const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
+
+ // Unknown size indication requires no size computation.
+ // Otherwise, evaluate and record it.
+ if (auto Size = VAT->getSizeExpr()) {
+ if (!CSI->isVLATypeCaptured(VAT)) {
+ RecordDecl *CapRecord = nullptr;
+ if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ CapRecord = LSI->Lambda;
+ } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
+ CapRecord = CRSI->TheRecordDecl;
+ }
+ if (CapRecord) {
+ auto ExprLoc = Size->getExprLoc();
+ auto SizeType = Context.getSizeType();
+ // Build the non-static data member.
+ auto Field =
+ FieldDecl::Create(Context, CapRecord, ExprLoc, ExprLoc,
+ /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
+ /*BW*/ nullptr, /*Mutable*/ false,
+ /*InitStyle*/ ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Field->setCapturedVLAType(VAT);
+ CapRecord->addDecl(Field);
+
+ CSI->addVLATypeCapture(ExprLoc, SizeType);
+ }
+ }
+ }
+ T = VAT->getElementType();
+ break;
+ }
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ T = cast<FunctionType>(Ty)->getReturnType();
+ break;
+ case Type::Paren:
+ case Type::TypeOf:
+ case Type::UnaryTransform:
+ case Type::Attributed:
+ case Type::SubstTemplateTypeParm:
+ case Type::PackExpansion:
+ // Keep walking after single level desugaring.
+ T = T.getSingleStepDesugaredType(Context);
+ break;
+ case Type::Typedef:
+ T = cast<TypedefType>(Ty)->desugar();
+ break;
+ case Type::Decltype:
+ T = cast<DecltypeType>(Ty)->desugar();
+ break;
+ case Type::Auto:
+ T = cast<AutoType>(Ty)->getDeducedType();
+ break;
+ case Type::TypeOfExpr:
+ T = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
+ break;
+ case Type::Atomic:
+ T = cast<AtomicType>(Ty)->getValueType();
+ break;
+ }
+ } while (!T.isNull() && T->isVariablyModifiedType());
+}
+
/// \brief Build a sizeof or alignof expression given a type operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
@@ -3763,6 +3885,20 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind))
return ExprError();
+ if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) {
+ if (auto *TT = T->getAs<TypedefType>()) {
+ if (auto *CSI = dyn_cast<CapturingScopeInfo>(FunctionScopes.back())) {
+ DeclContext *DC = nullptr;
+ if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI))
+ DC = LSI->CallOperator;
+ else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI))
+ DC = CRSI->TheCapturedDecl;
+ if (DC && TT->getDecl()->getDeclContext() != DC)
+ captureVariablyModifiedType(Context, T, CSI);
+ }
+ }
+ }
+
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
return new (Context) UnaryExprOrTypeTraitExpr(
ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
@@ -7354,11 +7490,14 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
LHSType->isBlockPointerType()) &&
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- CastKind Kind;
- CXXCastPath Path;
- CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
- if (ConvertRHS)
- RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
+ if (Diagnose || ConvertRHS) {
+ CastKind Kind;
+ CXXCastPath Path;
+ CheckPointerConversion(RHS.get(), LHSType, Kind, Path,
+ /*IgnoreBaseAccess=*/false, Diagnose);
+ if (ConvertRHS)
+ RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
+ }
return Compatible;
}
@@ -7376,8 +7515,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
}
Expr *PRE = RHS.get()->IgnoreParenCasts();
- if (ObjCProtocolExpr *OPE = dyn_cast<ObjCProtocolExpr>(PRE)) {
- ObjCProtocolDecl *PDecl = OPE->getProtocol();
+ if (Diagnose && isa<ObjCProtocolExpr>(PRE)) {
+ ObjCProtocolDecl *PDecl = cast<ObjCProtocolExpr>(PRE)->getProtocol();
if (PDecl && !PDecl->hasDefinition()) {
Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName();
Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl;
@@ -7399,11 +7538,11 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
- DiagnoseCFAudited);
+ Diagnose, DiagnoseCFAudited);
if (getLangOpts().ObjC1 &&
- (CheckObjCBridgeRelatedConversions(E->getLocStart(),
- LHSType, E->getType(), E) ||
- ConversionToObjCStringLiteralCheck(LHSType, E))) {
+ (CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType,
+ E->getType(), E, Diagnose) ||
+ ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) {
RHS = E;
return Compatible;
}
@@ -8961,8 +9100,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
else {
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, false,
- Opc);
+ CheckObjCARCConversion(SourceRange(), LHSType, E,
+ CCK_ImplicitConversion, /*Diagnose=*/true,
+ /*DiagnoseCFAudited=*/false, Opc);
RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
@@ -11830,8 +11970,8 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return new (Context) GNUNullExpr(Ty, TokenLoc);
}
-bool
-Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) {
+bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
+ bool Diagnose) {
if (!getLangOpts().ObjC1)
return false;
@@ -11857,8 +11997,9 @@ Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) {
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
if (!SL || !SL->isAscii())
return false;
- Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
- << FixItHint::CreateInsertion(SL->getLocStart(), "@");
+ if (Diagnose)
+ Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
+ << FixItHint::CreateInsertion(SL->getLocStart(), "@");
Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get();
return true;
}
@@ -13139,120 +13280,7 @@ bool Sema::tryCaptureVariable(
QualType QTy = Var->getType();
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
QTy = PVD->getOriginalType();
- do {
- const Type *Ty = QTy.getTypePtr();
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base)
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- QTy = QualType();
- break;
- // These types are never variably-modified.
- case Type::Builtin:
- case Type::Complex:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Record:
- case Type::Enum:
- case Type::Elaborated:
- case Type::TemplateSpecialization:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::ObjCObjectPointer:
- case Type::Pipe:
- llvm_unreachable("type class is never variably-modified!");
- case Type::Adjusted:
- QTy = cast<AdjustedType>(Ty)->getOriginalType();
- break;
- case Type::Decayed:
- QTy = cast<DecayedType>(Ty)->getPointeeType();
- break;
- case Type::Pointer:
- QTy = cast<PointerType>(Ty)->getPointeeType();
- break;
- case Type::BlockPointer:
- QTy = cast<BlockPointerType>(Ty)->getPointeeType();
- break;
- case Type::LValueReference:
- case Type::RValueReference:
- QTy = cast<ReferenceType>(Ty)->getPointeeType();
- break;
- case Type::MemberPointer:
- QTy = cast<MemberPointerType>(Ty)->getPointeeType();
- break;
- case Type::ConstantArray:
- case Type::IncompleteArray:
- // Losing element qualification here is fine.
- QTy = cast<ArrayType>(Ty)->getElementType();
- break;
- case Type::VariableArray: {
- // Losing element qualification here is fine.
- const VariableArrayType *VAT = cast<VariableArrayType>(Ty);
-
- // Unknown size indication requires no size computation.
- // Otherwise, evaluate and record it.
- if (auto Size = VAT->getSizeExpr()) {
- if (!CSI->isVLATypeCaptured(VAT)) {
- RecordDecl *CapRecord = nullptr;
- if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
- CapRecord = LSI->Lambda;
- } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- CapRecord = CRSI->TheRecordDecl;
- }
- if (CapRecord) {
- auto ExprLoc = Size->getExprLoc();
- auto SizeType = Context.getSizeType();
- // Build the non-static data member.
- auto Field = FieldDecl::Create(
- Context, CapRecord, ExprLoc, ExprLoc,
- /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
- /*BW*/ nullptr, /*Mutable*/ false,
- /*InitStyle*/ ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- Field->setCapturedVLAType(VAT);
- CapRecord->addDecl(Field);
-
- CSI->addVLATypeCapture(ExprLoc, SizeType);
- }
- }
- }
- QTy = VAT->getElementType();
- break;
- }
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- QTy = cast<FunctionType>(Ty)->getReturnType();
- break;
- case Type::Paren:
- case Type::TypeOf:
- case Type::UnaryTransform:
- case Type::Attributed:
- case Type::SubstTemplateTypeParm:
- case Type::PackExpansion:
- // Keep walking after single level desugaring.
- QTy = QTy.getSingleStepDesugaredType(getASTContext());
- break;
- case Type::Typedef:
- QTy = cast<TypedefType>(Ty)->desugar();
- break;
- case Type::Decltype:
- QTy = cast<DecltypeType>(Ty)->desugar();
- break;
- case Type::Auto:
- QTy = cast<AutoType>(Ty)->getDeducedType();
- break;
- case Type::TypeOfExpr:
- QTy = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
- break;
- case Type::Atomic:
- QTy = cast<AtomicType>(Ty)->getValueType();
- break;
- }
- } while (!QTy.isNull() && QTy->isVariablyModifiedType());
+ captureVariablyModifiedType(Context, QTy, CSI);
}
if (getLangOpts().OpenMP) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 1d86ca35412e..c1fb906a5b19 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -3816,7 +3816,7 @@ bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
ObjCMethodDecl *&ClassMethod,
ObjCMethodDecl *&InstanceMethod,
TypedefNameDecl *&TDNDecl,
- bool CfToNs) {
+ bool CfToNs, bool Diagnose) {
QualType T = CfToNs ? SrcType : DestType;
ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl);
if (!ObjCBAttr)
@@ -3832,20 +3832,24 @@ bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
LookupResult R(*this, DeclarationName(RCId), SourceLocation(),
Sema::LookupOrdinaryName);
if (!LookupName(R, TUScope)) {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
Target = R.getFoundDecl();
if (Target && isa<ObjCInterfaceDecl>(Target))
RelatedClass = cast<ObjCInterfaceDecl>(Target);
else {
- Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
- << SrcType << DestType;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- if (Target)
- Diag(Target->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ Diag(Target->getLocStart(), diag::note_declared_at);
+ }
return false;
}
@@ -3854,9 +3858,11 @@ bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
Selector Sel = Context.Selectors.getUnarySelector(CMId);
ClassMethod = RelatedClass->lookupMethod(Sel, false);
if (!ClassMethod) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << false;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << false;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
}
@@ -3866,9 +3872,11 @@ bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
Selector Sel = Context.Selectors.getNullarySelector(IMId);
InstanceMethod = RelatedClass->lookupMethod(Sel, true);
if (!InstanceMethod) {
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << Sel << true;
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << true;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
return false;
}
}
@@ -3878,7 +3886,7 @@ bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
bool
Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
QualType DestType, QualType SrcType,
- Expr *&SrcExpr) {
+ Expr *&SrcExpr, bool Diagnose) {
ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType);
ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType);
bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable);
@@ -3891,27 +3899,29 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
ObjCMethodDecl *InstanceMethod = nullptr;
TypedefNameDecl *TDNDecl = nullptr;
if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass,
- ClassMethod, InstanceMethod, TDNDecl, CfToNs))
+ ClassMethod, InstanceMethod, TDNDecl,
+ CfToNs, Diagnose))
return false;
if (CfToNs) {
// Implicit conversion from CF to ObjC object is needed.
if (ClassMethod) {
- std::string ExpressionString = "[";
- ExpressionString += RelatedClass->getNameAsString();
- ExpressionString += " ";
- ExpressionString += ClassMethod->getSelector().getAsString();
- SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd());
- // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << ClassMethod->getSelector() << false
- << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString)
- << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
- Diag(RelatedClass->getLocStart(), diag::note_declared_at);
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Diagnose) {
+ std::string ExpressionString = "[";
+ ExpressionString += RelatedClass->getNameAsString();
+ ExpressionString += " ";
+ ExpressionString += ClassMethod->getSelector().getAsString();
+ SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd());
+ // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << ClassMethod->getSelector() << false
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString)
+ << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
- QualType receiverType =
- Context.getObjCInterfaceType(RelatedClass);
+ QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
// Argument.
Expr *args[] = { SrcExpr };
ExprResult msg = BuildClassMessageImplicit(receiverType, false,
@@ -3925,30 +3935,34 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
else {
// Implicit conversion from ObjC type to CF object is needed.
if (InstanceMethod) {
- std::string ExpressionString;
- SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd());
- if (InstanceMethod->isPropertyAccessor())
- if (const ObjCPropertyDecl *PDecl = InstanceMethod->findPropertyDecl()) {
- // fixit: ObjectExpr.propertyname when it is aproperty accessor.
- ExpressionString = ".";
- ExpressionString += PDecl->getNameAsString();
+ if (Diagnose) {
+ std::string ExpressionString;
+ SourceLocation SrcExprEndLoc =
+ getLocForEndOfToken(SrcExpr->getLocEnd());
+ if (InstanceMethod->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl =
+ InstanceMethod->findPropertyDecl()) {
+ // fixit: ObjectExpr.propertyname when it is aproperty accessor.
+ ExpressionString = ".";
+ ExpressionString += PDecl->getNameAsString();
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ }
+ if (ExpressionString.empty()) {
+ // Provide a fixit: [ObjectExpr InstanceMethod]
+ ExpressionString = " ";
+ ExpressionString += InstanceMethod->getSelector().getAsString();
+ ExpressionString += "]";
+
Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[")
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
}
- if (ExpressionString.empty()) {
- // Provide a fixit: [ObjectExpr InstanceMethod]
- ExpressionString = " ";
- ExpressionString += InstanceMethod->getSelector().getAsString();
- ExpressionString += "]";
-
- Diag(Loc, diag::err_objc_bridged_related_known_method)
- << SrcType << DestType << InstanceMethod->getSelector() << true
- << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[")
- << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
}
- Diag(RelatedClass->getLocStart(), diag::note_declared_at);
- Diag(TDNDecl->getLocStart(), diag::note_declared_at);
ExprResult msg =
BuildInstanceMessageImplicit(SrcExpr, SrcType,
@@ -3965,6 +3979,7 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
Sema::ARCConversionResult
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *&castExpr, CheckedConversionKind CCK,
+ bool Diagnose,
bool DiagnoseCFAudited,
BinaryOperatorKind Opc) {
QualType castExprType = castExpr->getType();
@@ -3980,9 +3995,9 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
if (exprACTC == castACTC) {
// check for viablity and report error if casting an rvalue to a
// life-time qualifier.
- if ((castACTC == ACTC_retainable) &&
+ if (Diagnose && castACTC == ACTC_retainable &&
(CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
- (castType != castExprType)) {
+ castType != castExprType) {
const Type *DT = castType.getTypePtr();
QualType QDT = castType;
// We desugar some types but not others. We ignore those
@@ -4051,19 +4066,20 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
// to 'NSString *'. Let caller issue a normal mismatched diagnostic with
// suitable fix-it.
if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
- ConversionToObjCStringLiteralCheck(castType, castExpr))
+ ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose))
return ACR_okay;
// Do not issue "bridge cast" diagnostic when implicit casting
// a retainable object to a CF type parameter belonging to an audited
// CF API function. Let caller issue a normal type mismatched diagnostic
// instead.
- if (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
- castACTC != ACTC_coreFoundation)
+ if (Diagnose &&
+ (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
+ castACTC != ACTC_coreFoundation))
if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
(Opc == BO_NE || Opc == BO_EQ)))
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, castExpr, exprACTC, CCK);
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr,
+ castExpr, exprACTC, CCK);
return ACR_okay;
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 663da0c0e804..d6a0ff7dc3d1 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2687,15 +2687,16 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
CXXCastPath& BasePath,
- bool IgnoreBaseAccess) {
+ bool IgnoreBaseAccess,
+ bool Diagnose) {
QualType FromType = From->getType();
bool IsCStyleOrFunctionalCast = IgnoreBaseAccess;
Kind = CK_BitCast;
- if (!IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
+ if (Diagnose && !IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() &&
From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) ==
- Expr::NPCK_ZeroExpression) {
+ Expr::NPCK_ZeroExpression) {
if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy))
DiagRuntimeBehavior(From->getExprLoc(), From,
PDiag(diag::warn_impcast_bool_to_null_pointer)
@@ -2713,18 +2714,24 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) {
// We must have a derived-to-base conversion. Check an
// ambiguous or inaccessible conversion.
- if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
- From->getExprLoc(),
- From->getSourceRange(), &BasePath,
- IgnoreBaseAccess))
+ unsigned InaccessibleID = 0;
+ unsigned AmbigiousID = 0;
+ if (Diagnose) {
+ InaccessibleID = diag::err_upcast_to_inaccessible_base;
+ AmbigiousID = diag::err_ambiguous_derived_to_base_conv;
+ }
+ if (CheckDerivedToBaseConversion(
+ FromPointeeType, ToPointeeType, InaccessibleID, AmbigiousID,
+ From->getExprLoc(), From->getSourceRange(), DeclarationName(),
+ &BasePath, IgnoreBaseAccess))
return true;
// The conversion was successful.
Kind = CK_DerivedToBase;
}
- if (!IsCStyleOrFunctionalCast && FromPointeeType->isFunctionType() &&
- ToPointeeType->isVoidType()) {
+ if (Diagnose && !IsCStyleOrFunctionalCast &&
+ FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) {
assert(getLangOpts().MSVCCompat &&
"this should only be possible with MSVCCompat!");
Diag(From->getExprLoc(), diag::ext_ms_impcast_fn_obj)
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index 2ea0561f9e92..4df44f4c5f7f 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -10,10 +10,23 @@ void *use = &used;
// CHECK: @cvar = global
extern "C" auto cvar = []{};
+// CHECK-LABEL: define i32 @_Z9ARBSizeOfi(i32
+int ARBSizeOf(int n) {
+ typedef double (T)[8][n];
+ using TT = double [8][n];
+ return [&]() -> int {
+ typedef double(T1)[8][n];
+ using TT1 = double[8][n];
+ return sizeof(T) + sizeof(T1) + sizeof(TT) + sizeof(TT1);
+ }();
+}
+
+// CHECK-LABEL: define internal i32 @"_ZZ9ARBSizeOfiENK3$_0clEv"
+
int a() { return []{ return 1; }(); }
// CHECK-LABEL: define i32 @_Z1av
-// CHECK: call i32 @"_ZZ1avENK3$_0clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_0clEv"
+// CHECK: call i32 @"_ZZ1avENK3$_1clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1avENK3$_1clEv"
// CHECK: ret i32 1
int b(int x) { return [x]{return x;}(); }
@@ -21,8 +34,8 @@ int b(int x) { return [x]{return x;}(); }
// CHECK: store i32
// CHECK: load i32, i32*
// CHECK: store i32
-// CHECK: call i32 @"_ZZ1biENK3$_1clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_1clEv"
+// CHECK: call i32 @"_ZZ1biENK3$_2clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1biENK3$_2clEv"
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -30,8 +43,8 @@ int c(int x) { return [&x]{return x;}(); }
// CHECK-LABEL: define i32 @_Z1ci
// CHECK: store i32
// CHECK: store i32*
-// CHECK: call i32 @"_ZZ1ciENK3$_2clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_2clEv"
+// CHECK: call i32 @"_ZZ1ciENK3$_3clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1ciENK3$_3clEv"
// CHECK: load i32*, i32**
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -43,8 +56,8 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// CHECK: call void @_ZN1DC1Ev
// CHECK: icmp ult i64 %{{.*}}, 10
// CHECK: call void @_ZN1DC1ERKS_
-// CHECK: call i32 @"_ZZ1diENK3$_3clEv"
-// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_3clEv"
+// CHECK: call i32 @"_ZZ1diENK3$_4clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1diENK3$_4clEv"
// CHECK: load i32, i32*
// CHECK: load i32, i32*
// CHECK: ret i32
@@ -54,18 +67,18 @@ int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); }
// CHECK-LABEL: define i32 @_Z1e1ES_b
// CHECK: call void @_ZN1EC1ERKS_
// CHECK: invoke void @_ZN1EC1ERKS_
-// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv"
-// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
-// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
+// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_5clEv"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_5D1Ev"
-// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
+// CHECK-LABEL: define internal i32 @"_ZZ1e1ES_bENK3$_5clEv"
// CHECK: trunc i8
// CHECK: load i32, i32*
// CHECK: ret i32
void f() {
// CHECK-LABEL: define void @_Z1fv()
- // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv"
+ // CHECK: @"_ZZ1fvENK3$_6cvPFiiiEEv"
// CHECK-NEXT: store i32 (i32, i32)*
// CHECK-NEXT: ret void
int (*fp)(int, int) = [](int x, int y){ return x + y; };
@@ -74,7 +87,7 @@ void f() {
static int k;
int g() {
int &r = k;
- // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_6clEv"(
+ // CHECK-LABEL: define internal i32 @"_ZZ1gvENK3$_7clEv"(
// CHECK-NOT: }
// CHECK: load i32, i32* @_ZL1k,
return [] { return r; } ();
@@ -91,7 +104,7 @@ void staticarrayref(){
}();
}
-// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_8clEv"
+// CHECK-LABEL: define internal i32* @"_ZZ11PR22071_funvENK3$_9clEv"
// CHECK: ret i32* @PR22071_var
int PR22071_var;
int *PR22071_fun() {
@@ -99,19 +112,19 @@ int *PR22071_fun() {
return [&] { return &y; }();
}
-// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
+// CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_5D2Ev"
-// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
+// CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_68__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
// CHECK-NEXT: load i32, i32*
// CHECK-NEXT: load i32, i32*
-// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii"
+// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii"
// CHECK-NEXT: ret i32
-// CHECK-LABEL: define internal void @"_ZZ1hvEN3$_98__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
+// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_108__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
// CHECK-NOT: =
-// CHECK: call void @"_ZZ1hvENK3$_9clEv"(%struct.A* sret %agg.result,
+// CHECK: call void @"_ZZ1hvENK4$_10clEv"(%struct.A* sret %agg.result,
// CHECK-NEXT: ret void
struct A { ~A(); };
void h() {
diff --git a/test/CodeGenOpenCL/pipe_types.cl b/test/CodeGenOpenCL/pipe_types.cl
index 547071cf85a3..9d8d5274a3ba 100644
--- a/test/CodeGenOpenCL/pipe_types.cl
+++ b/test/CodeGenOpenCL/pipe_types.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
// CHECK: %opencl.pipe_t = type opaque
typedef unsigned char __attribute__((ext_vector_type(3))) uchar3;
diff --git a/test/Driver/netbsd.c b/test/Driver/netbsd.c
index ffaab36390c0..351fbdf9ee9c 100644
--- a/test/Driver/netbsd.c
+++ b/test/Driver/netbsd.c
@@ -86,12 +86,18 @@
// RUN: %clang -no-canonical-prefixes -target arm--netbsd6.0.0-eabi -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-ARM-6 %s
-// RUN: %clang -no-canonical-prefixes -target sparc--netbsd -static \
+// RUN: %clang -no-canonical-prefixes -target sparc--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-SPARC %s
-// RUN: %clang -no-canonical-prefixes -target sparc64--netbsd -static \
+// RUN: | FileCheck -check-prefix=S-SPARC-7 %s
+// RUN: %clang -no-canonical-prefixes -target sparc--netbsd6.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
-// RUN: | FileCheck -check-prefix=S-SPARC64 %s
+// RUN: | FileCheck -check-prefix=S-SPARC-6 %s
+// RUN: %clang -no-canonical-prefixes -target sparc64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC64-7 %s
+// RUN: %clang -no-canonical-prefixes -target sparc64--netbsd6.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC64-6 %s
// RUN: %clang -no-canonical-prefixes -target powerpc--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-POWERPC %s
@@ -302,22 +308,37 @@
// S-ARM-6: "-lgcc_eh" "-lc" "-lgcc"
// S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-// S-SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
-// S-SPARC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-SPARC: "-m" "elf32_sparc"
-// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
-// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
-// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-SPARC: "-lgcc_eh" "-lc" "-lgcc"
-// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
-
-// S-SPARC64: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd"
-// S-SPARC64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
-// S-SPARC64: "-m" "elf64_sparc"
-// S-SPARC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
-// S-SPARC64: "-lgcc_eh" "-lc" "-lgcc"
-// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-SPARC-6: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd6.0.0"
+// S-SPARC-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC-6: "-m" "elf32_sparc"
+// S-SPARC-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-SPARC-6: "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-SPARC-7: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd7.0.0"
+// S-SPARC-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC-7: "-m" "elf32_sparc"
+// S-SPARC-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-SPARC64-6: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd6.0.0"
+// S-SPARC64-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC64-6: "-m" "elf64_sparc"
+// S-SPARC64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-SPARC64-6: "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-SPARC64-7: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd7.0.0"
+// S-SPARC64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC64-7: "-m" "elf64_sparc"
+// S-SPARC64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// S-POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
// S-POWERPC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
diff --git a/test/Driver/netbsd.cpp b/test/Driver/netbsd.cpp
index e386a212de2c..856b6ccc669d 100644
--- a/test/Driver/netbsd.cpp
+++ b/test/Driver/netbsd.cpp
@@ -22,9 +22,21 @@
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd6.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=SPARC-6 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=SPARC-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC64 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd6.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=SPARC64-6 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=SPARC64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target powerpc--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=POWERPC %s
@@ -56,9 +68,21 @@
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd6.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC-6 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC64 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd6.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC64-6 %s
+// RUN: %clangxx -no-canonical-prefixes -target sparc64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-SPARC64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target powerpc--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-POWERPC %s
@@ -116,17 +140,47 @@
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
-// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// SPARC: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// SPARC: "-lm" "-lc"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// SPARC-7: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd7.0.0"
+// SPARC-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// SPARC-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// SPARC-7: "-lm" "-lc"
+// SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// SPARC-6: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd6.0.0"
+// SPARC-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// SPARC-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// SPARC-6: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// SPARC64: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd"
// SPARC64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// SPARC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// SPARC64: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// SPARC64: "-lm" "-lc"
// SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// SPARC64-7: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd7.0.0"
+// SPARC64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// SPARC64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// SPARC64-7: "-lm" "-lc"
+// SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// SPARC64-6: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd6.0.0"
+// SPARC64-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// SPARC64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// SPARC64-6: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
// POWERPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
@@ -191,17 +245,47 @@
// S-SPARC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
-// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-SPARC: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-SPARC: "-lm" "-lc"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-SPARC-7: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd7.0.0"
+// S-SPARC-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-SPARC-7: "-lm" "-lc"
+// S-SPARC-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-SPARC-6: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd6.0.0"
+// S-SPARC-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// S-SPARC-6: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-SPARC64: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd"
// S-SPARC64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-SPARC64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
-// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
-// S-SPARC64: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-SPARC64: "-lm" "-lc"
// S-SPARC64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-SPARC64-7: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd7.0.0"
+// S-SPARC64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc++"
+// S-SPARC64-7: "-lm" "-lc"
+// S-SPARC64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-SPARC64-6: clang{{.*}}" "-cc1" "-triple" "sparc64--netbsd6.0.0"
+// S-SPARC64-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-SPARC64-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// S-SPARC64-6: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-SPARC64-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-POWERPC: clang{{.*}}" "-cc1" "-triple" "powerpc--netbsd"
// S-POWERPC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-POWERPC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
diff --git a/test/Misc/diag-template-diffing-color.cpp b/test/Misc/diag-template-diffing-color.cpp
index e73fc2c3973a..bf203153d8d4 100644
--- a/test/Misc/diag-template-diffing-color.cpp
+++ b/test/Misc/diag-template-diffing-color.cpp
@@ -1,5 +1,5 @@
-// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics %s 2>&1 | FileCheck %s
-// RUN: not %clang_cc1 -fsyntax-only -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 -fcolor-diagnostics -fdiagnostics-show-template-tree %s 2>&1 | FileCheck %s -check-prefix=TREE
// REQUIRES: ansi-escape-sequences
template<typename> struct foo {};
void func(foo<int>);
@@ -82,5 +82,23 @@ namespace default_args {
// CHECK: no viable conversion from 'A<[2 * ...], (default) [[CYAN]]2[[RESET]][[BOLD]]>' to 'A<[2 * ...], [[CYAN]]0[[RESET]][[BOLD]]>'
A<0, 2, 0> N2 = M;
}
+}
+
+namespace MixedDeclarationIntegerArgument {
+ template<typename T, T n = 5> class A{};
+ int x;
+ int y[5];
+ A<int> a1 = A<int&, x>();
+ // CHECK: no viable conversion from 'A<[[CYAN]]int &[[RESET]][[BOLD]], [[CYAN]]x[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int[[RESET]][[BOLD]], (default) [[CYAN]]5[[RESET]][[BOLD]]>'
+ // TREE: no viable conversion
+ // TREE: A<
+ // TREE: {{\[}}[[CYAN]]int &[[RESET]][[BOLD]] != [[CYAN]]int[[RESET]][[BOLD]]],
+ // TREE: {{\[}}[[CYAN]]x[[RESET]][[BOLD]] != (default) [[CYAN]]5[[RESET]][[BOLD]]]>
+ A<int**, nullptr> a2 = A<int, 3 + 1>();
+ // CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<[[CYAN]]int[[RESET]][[BOLD]], [[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]]>' to 'A<[[CYAN]]int **[[RESET]][[BOLD]], [[CYAN]]nullptr[[RESET]][[BOLD]]>'
+ // TREE: no viable conversion
+ // TREE: A<
+ // TREE: {{\[}}[[CYAN]]int[[RESET]][[BOLD]] != [[CYAN]]int **[[RESET]][[BOLD]]],
+ // TREE: {{\[}}[[CYAN]]3 + 1[[RESET]][[BOLD]] aka [[CYAN]]4[[RESET]][[BOLD]] != [[CYAN]]nullptr[[RESET]][[BOLD]]]>
}
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 044f07ba06ba..70d5e7c87091 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -925,7 +925,7 @@ namespace DependentDefault {
// CHECK-ELIDE-NOTREE: no known conversion from 'A<char, [...]>' to 'A<int, [...]>'
a3 = a1;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
- // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (default) 40>' to 'A<[...], 10>'
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (default) Trait<T>::V aka 40>' to 'A<[...], 10>'
a2 = a3;
// CHECK-ELIDE-NOTREE: no viable overloaded '='
// CHECK-ELIDE-NOTREE: no known conversion from 'A<int, 10>' to 'A<char, 40>'
@@ -1118,7 +1118,7 @@ int global, global2;
constexpr int * ptr = nullptr;
Wrapper<S<ptr>> W = MakeWrapper<S<&global>>();
// Don't print an extra '&' for 'ptr'
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global>>' to 'Wrapper<S<ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global>>' to 'Wrapper<S<ptr aka nullptr>>'
// Handle parens correctly
Wrapper<S<(&global2)>> W2 = MakeWrapper<S<&global>>();
@@ -1148,7 +1148,7 @@ S<&global, nullptr> s2 = S<&global, ptr>();
S<&global, nullptr> s3 = S<&global, &global>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], nullptr>'
S<&global, ptr> s4 = S<&global, &global>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], ptr>
+// CHECK-ELIDE-NOTREE: no viable conversion from 'S<[...], &global>' to 'S<[...], ptr aka nullptr>
Wrapper<S<&global, nullptr>> W1 = MakeWrapper<S<&global, ptr>>();
Wrapper<S<&global, static_cast<int*>(0)>> W2 = MakeWrapper<S<&global, ptr>>();
@@ -1156,7 +1156,7 @@ Wrapper<S<&global, static_cast<int*>(0)>> W2 = MakeWrapper<S<&global, ptr>>();
Wrapper<S<&global, nullptr>> W3 = MakeWrapper<S<&global, &global>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], nullptr>>'
Wrapper<S<&global, ptr>> W4 = MakeWrapper<S<&global, &global>>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr aka nullptr>>'
Wrapper<S<&global2, ptr>> W5 = MakeWrapper<S<&global, nullptr>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global, [...]>>' to 'Wrapper<S<&global2, [...]>>'
@@ -1180,7 +1180,7 @@ Wrapper<S<&global2, nullptr>> W12 =
Wrapper<S<&global, &global>> W13 = MakeWrapper<S<&global, ptr>>();
// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], nullptr>>' to 'Wrapper<S<[...], &global>>'
Wrapper<S<&global, ptr>> W14 = MakeWrapper<S<&global, &global>>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr aka nullptr>>'
}
namespace TemplateTemplateDefault {
@@ -1271,7 +1271,160 @@ void test() {
foo<BoolT<true>>(X);
}
// CHECK-ELIDE-NOTREE: no matching function for call to 'foo'
-// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT<true>] not viable: no known conversion from 'BoolT<0>' to 'BoolT<1>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT<true>] not viable: no known conversion from 'BoolT<false>' to 'BoolT<true>' for 1st argument
+}
+
+namespace DifferentIntegralTypes {
+template<typename T, T n>
+class A{};
+void foo() {
+ A<int, 1> a1 = A<long long, 1>();
+ A<unsigned int, 1> a2 = A<int, 5>();
+ A<bool, true> a3 = A<signed char, true>();
+}
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<long long, (long long) 1>' to 'A<int, (int) 1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, (int) 5>' to 'A<unsigned int, (unsigned int) 1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<signed char, (signed char) 1>' to 'A<bool, (bool) true>'
+}
+
+namespace MixedDeclarationIntegerArgument {
+template<typename T, T n> class A{};
+int x;
+int y[5];
+
+A<int, 5> a1 = A<int&, x>();
+A<int, 5 - 1> a2 = A<int*, &x>();
+A<int, 5 + 1> a3 = A<int*, y>();
+A<int, 0> a4 = A<int**, nullptr>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int &, x>' to 'A<int, 5>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, &x>' to 'A<int, 5 - 1 aka 4>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int *, y>' to 'A<int, 5 + 1 aka 6>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int **, nullptr>' to 'A<int, 0>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [x != 5]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int * != int],
+// CHECK-ELIDE-TREE: [&x != 5 - 1 aka 4]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int * != int],
+// CHECK-ELIDE-TREE: [y != 5 + 1 aka 6]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int ** != int],
+// CHECK-ELIDE-TREE: [nullptr != 0]>
+
+A<int&, x> a5 = A<int, 3>();
+A<int*, &x> a6 = A<int, 3 - 1>();
+A<int*, y> a7 = A<int, 3 + 1>();
+A<int**, nullptr> a8 = A<int, 3>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int &, x>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 - 1 aka 2>' to 'A<int *, &x>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3 + 1 aka 4>' to 'A<int *, y>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<int, 3>' to 'A<int **, nullptr>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [3 != x]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int *],
+// CHECK-ELIDE-TREE: [3 - 1 aka 2 != &x]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int *],
+// CHECK-ELIDE-TREE: [3 + 1 aka 4 != y]>
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: A<
+// CHECK-ELIDE-TREE: [int != int **],
+// CHECK-ELIDE-TREE: [3 != nullptr]>
+
+template<class T, T n = x> class B{} ;
+B<int, 5> b1 = B<int&>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int &, (default) x>' to 'B<int, 5>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: B<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [(default) x != 5]>
+
+B<int &> b2 = B<int, 2>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int, 2>' to 'B<int &, (default) x>'
+// CHECK-ELIDE-TREE: B<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [2 != (default) x]>
+
+template<class T, T n = 11> class C {};
+C<int> c1 = C<int&, x>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int &, x>' to 'C<int, (default) 11>'
+// CHECK-ELIDE-TREE: error: no viable conversion
+// CHECK-ELIDE-TREE: C<
+// CHECK-ELIDE-TREE: [int & != int],
+// CHECK-ELIDE-TREE: [x != (default) 11]>
+
+C<int &, x> c2 = C<int>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C<int, (default) 11>' to 'C<int &, x>'
+// CHECK-ELIDE-TREE: C<
+// CHECK-ELIDE-TREE: [int != int &],
+// CHECK-ELIDE-TREE: [(default) 11 != x]>
+}
+
+namespace default_args {
+ template <int x, int y = 1+1, int z = 2>
+ class A {};
+
+ void foo(A<0> &M) {
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[...], (default) 1 + 1 aka 2, (default) 2>' to 'A<[...], 0, 0>'
+ A<0, 0, 0> N = M;
+
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'A<[2 * ...], (default) 2>' to 'A<[2 * ...], 0>'
+ A<0, 2, 0> N2 = M;
+ }
+}
+
+namespace DefaultNonTypeArgWithDependentType {
+// We used to crash diffing integer template arguments when the argument type
+// is dependent and default arguments were used.
+template <typename SizeType = int, SizeType = 0> struct A {};
+template <typename R = A<>> R bar();
+A<> &foo() { return bar(); }
+// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<[2 * ...]>' cannot bind to a temporary of type 'A<[2 * ...]>'
+// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<int, 0>' cannot bind to a temporary of type 'A<int, 0>'
+}
+
+namespace PR24587 {
+template <typename T, T v>
+struct integral_constant {};
+
+auto false_ = integral_constant<bool, false> {};
+
+template <typename T>
+void f(T, decltype(false_));
+
+void run() {
+ f(1, integral_constant<bool, true>{});
+}
+// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
+// CHECK-ELIDE-NOTREE: note: candidate function [with T = int] not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
+}
+
+namespace ZeroArgs {
+template <int N = 0> class A {};
+template <class T = A<>> class B {};
+A<1> a1 = A<>();
+A<> a2 = A<1>();
+B<> b1 = B<int>();
+B<int> b2 = B<>();
+B<> b3 = B<const A<>>();
+B<const A<>> b4 = B<>();
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<(default) 0>' to 'A<1>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A<1>' to 'A<(default) 0>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<int>' to 'B<(default) ZeroArgs::A<0>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<(default) ZeroArgs::A<0>>' to 'B<int>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<const A<[...]>>' to 'B<A<[...]>>'
+// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<A<[...]>>' to 'B<const A<[...]>>'
}
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
diff --git a/test/OpenMP/cancel_codegen.cpp b/test/OpenMP/cancel_codegen.cpp
index e2dd3673caff..8234193e8f95 100644
--- a/test/OpenMP/cancel_codegen.cpp
+++ b/test/OpenMP/cancel_codegen.cpp
@@ -19,9 +19,10 @@ int main (int argc, char **argv) {
{
#pragma omp cancel sections
}
-// CHECK: call i32 @__kmpc_single(
-// CHECK-NOT: @__kmpc_cancel
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call i32 @__kmpc_cancel(
+// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t*
+// CHECK: call void @__kmpc_for_static_fini(
// CHECK: call void @__kmpc_barrier(%ident_t*
#pragma omp sections
{
@@ -125,9 +126,10 @@ for (int i = 0; i < argc; ++i) {
// CHECK: ret i32 0
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
-// CHECK: call i32 @__kmpc_single(
-// CHECK-NOT: @__kmpc_cancel
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call i32 @__kmpc_cancel(
+// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t*
+// CHECK: call void @__kmpc_for_static_fini(
// CHECK: ret void
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
diff --git a/test/OpenMP/cancellation_point_codegen.cpp b/test/OpenMP/cancellation_point_codegen.cpp
index 795f69ed24fa..91e6c6994916 100644
--- a/test/OpenMP/cancellation_point_codegen.cpp
+++ b/test/OpenMP/cancellation_point_codegen.cpp
@@ -22,9 +22,16 @@ int main (int argc, char **argv) {
#pragma omp cancel sections
}
}
-// CHECK: call i32 @__kmpc_single(
-// CHECK-NOT: @__kmpc_cancellationpoint
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3)
+// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0
+// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]]
+// CHECK: [[EXIT]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t*
+// CHECK: br label
+// CHECK: [[CONTINUE]]
+// CHECK: br label
+// CHECK: call void @__kmpc_for_static_fini(
// CHECK: call void @__kmpc_barrier(%ident_t*
#pragma omp sections
{
@@ -126,9 +133,16 @@ for (int i = 0; i < argc; ++i) {
// CHECK: ret i32 0
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
-// CHECK: call i32 @__kmpc_single(
-// CHECK-NOT: @__kmpc_cancellationpoint
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancellationpoint(%ident_t* {{[^,]+}}, i32 [[GTID:%.+]], i32 3)
+// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0
+// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]]
+// CHECK: [[EXIT]]
+// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t*
+// CHECK: br label
+// CHECK: [[CONTINUE]]
+// CHECK: br label
+// CHECK: call void @__kmpc_for_static_fini(
// CHECK: ret void
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}})
diff --git a/test/OpenMP/parallel_sections_codegen.cpp b/test/OpenMP/parallel_sections_codegen.cpp
index b8c1e39d8f9e..bc7e1982dcb3 100644
--- a/test/OpenMP/parallel_sections_codegen.cpp
+++ b/test/OpenMP/parallel_sections_codegen.cpp
@@ -78,15 +78,10 @@ int main() {
// CHECK-LABEL: tmain
// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK-NOT: __kmpc_global_thread_num
-// CHECK: [[RES:%.+]] = call i32 @__kmpc_single(
-// CHECK-NEXT: [[BOOLRES:%.+]] = icmp ne i32 [[RES]], 0
-// CHECK-NEXT: br i1 [[BOOLRES]], label %[[THEN:.+]], label %[[END:.+]]
-// CHECK: [[THEN]]
-// CHECK-NEXT: invoke void @{{.*}}foo{{.*}}()
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: invoke void @{{.*}}foo{{.*}}()
// CHECK-NEXT: unwind label %[[TERM_LPAD:.+]]
-// CHECK: call void @__kmpc_end_single(
-// CHECK-NEXT: br label %[[END]]
-// CHECK: [[END]]
+// CHECK: call void @__kmpc_for_static_fini(
// CHECK-NEXT: ret
// CHECK: [[TERM_LPAD]]
// CHECK: call void @__clang_call_terminate(i8*
diff --git a/test/OpenMP/sections_codegen.cpp b/test/OpenMP/sections_codegen.cpp
index 44fdefeee733..291f05927d86 100644
--- a/test/OpenMP/sections_codegen.cpp
+++ b/test/OpenMP/sections_codegen.cpp
@@ -6,7 +6,6 @@
#ifndef HEADER
#define HEADER
// CHECK: [[IMPLICIT_BARRIER_SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
-// CHECK: [[IMPLICIT_BARRIER_SINGLE_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-LABEL: foo
void foo() {};
// CHECK-LABEL: bar
@@ -86,17 +85,12 @@ int main() {
// CHECK-LABEL: tmain
// CHECK: call void {{.*}} @__kmpc_fork_call(
// CHECK-NOT: __kmpc_global_thread_num
-// CHECK: [[RES:%.+]] = call i32 @__kmpc_single(
-// CHECK-NEXT: [[BOOLRES:%.+]] = icmp ne i32 [[RES]], 0
-// CHECK-NEXT: br i1 [[BOOLRES]], label %[[THEN:.+]], label %[[END:.+]]
-// CHECK: [[THEN]]
-// CHECK-NEXT: invoke void @{{.*}}foo{{.*}}()
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: invoke void @{{.*}}foo{{.*}}()
// CHECK-NEXT: unwind label %[[TERM_LPAD:.+]]
-// CHECK: call void @__kmpc_end_single(
-// CHECK-NEXT: br label %[[END]]
-// CHECK: [[END]]
-// CHECK-NEXT: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SINGLE_LOC]],
-// CHECK: ret
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SECTIONS_LOC]],
+// CHECK: ret
// CHECK: [[TERM_LPAD]]
// CHECK: call void @__clang_call_terminate(i8*
// CHECK-NEXT: unreachable
diff --git a/test/OpenMP/sections_firstprivate_codegen.cpp b/test/OpenMP/sections_firstprivate_codegen.cpp
index f673597f660b..0e9273f52ca7 100644
--- a/test/OpenMP/sections_firstprivate_codegen.cpp
+++ b/test/OpenMP/sections_firstprivate_codegen.cpp
@@ -202,14 +202,18 @@ int main() {
// CHECK: define {{.*}}i{{[0-9]+}} @main()
// CHECK: alloca i{{[0-9]+}},
-// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: [[SIVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
-// CHECK: call i32 @__kmpc_single(
// firstprivate t_var(t_var)
// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR]],
// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_PRIV]],
@@ -235,15 +239,16 @@ int main() {
// CHECK: call {{.*}} [[ST_TY_DESTR]]([[ST_TY]]* [[ST_TY_TEMP]])
// firstprivate isvar
-// CHEC: [[SIVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIVAR]],
-// CHEC: store i{{[0-9]+}} [[SIVAR_VAL]], i{{[0-9]+}}* [[SIVAR_PRIV]],
+// CHECK: [[SIVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIVAR]],
+// CHECK: store i{{[0-9]+}} [[SIVAR_VAL]], i{{[0-9]+}}* [[SIVAR_PRIV]],
+
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
// ~(firstprivate var), ~(firstprivate s_arr)
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
-// CHECK: call void @__kmpc_end_single(
-
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
diff --git a/test/OpenMP/sections_lastprivate_codegen.cpp b/test/OpenMP/sections_lastprivate_codegen.cpp
index a1ff007fd61d..6ee9f63b4bdd 100644
--- a/test/OpenMP/sections_lastprivate_codegen.cpp
+++ b/test/OpenMP/sections_lastprivate_codegen.cpp
@@ -23,7 +23,6 @@ volatile int g = 1212;
// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]*, i{{[0-9]+}}* }
// CHECK: [[S_INT_TY:%.+]] = type { i32 }
-// CHECK-DAG: [[SINGLE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-DAG: [[SECTIONS_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
// CHECK-DAG: [[X:@.+]] = global double 0.0
template <typename T>
@@ -234,27 +233,29 @@ int main() {
// CHECK: ret
// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}},
-// CHECK-NOT: alloca i{{[0-9]+}},
-// CHECK-NOT: alloca [2 x i{{[0-9]+}}],
-// CHECK-NOT: alloca [2 x [[S_FLOAT_TY]]],
-// CHECK-NOT: alloca [[S_FLOAT_TY]],
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca [2 x i{{[0-9]+}}],
+// CHECK: alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: alloca [[S_FLOAT_TY]],
+// CHECK: alloca i{{[0-9]+}},
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call i32 @__kmpc_single(
-
-// CHECK-DAG: getelementptr inbounds [2 x i32], [2 x i32]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK-DAG: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: call void @__kmpc_for_static_init_4(
// <Skip loop body>
+// CHECK: call void @__kmpc_for_static_fini(
-// CHECK-NOT: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
-// CHECK-NOT: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
-
-// CHECK: call void @__kmpc_end_single(
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK-DAG: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SINGLE_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: call void @__kmpc_barrier(
// CHECK: ret void
//
diff --git a/test/OpenMP/sections_private_codegen.cpp b/test/OpenMP/sections_private_codegen.cpp
index cd2218832bcf..b81265516935 100644
--- a/test/OpenMP/sections_private_codegen.cpp
+++ b/test/OpenMP/sections_private_codegen.cpp
@@ -157,6 +157,11 @@ int main() {
// CHECK: ret
//
// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
+// CHECK: alloca i{{[0-9]+}},
// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
@@ -165,7 +170,6 @@ int main() {
// CHECK: [[SIVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
// CHECK-NOT: alloca [[S_FLOAT_TY]],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
-// CHECK: call i32 @__kmpc_single(
// CHECK-NOT: [[T_VAR_PRIV]]
// CHECK-NOT: [[VEC_PRIV]]
// CHECK-NOT: [[SIVAR_PRIV]]
@@ -175,9 +179,13 @@ int main() {
// CHECK-NOT: [[T_VAR_PRIV]]
// CHECK-NOT: [[VEC_PRIV]]
// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_barrier(
// CHECK: ret void
// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
diff --git a/test/OpenMP/sections_reduction_codegen.cpp b/test/OpenMP/sections_reduction_codegen.cpp
index f67977c39580..b52d2ee3ec37 100644
--- a/test/OpenMP/sections_reduction_codegen.cpp
+++ b/test/OpenMP/sections_reduction_codegen.cpp
@@ -23,7 +23,6 @@ struct S {
// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
// CHECK-DAG: [[ATOMIC_REDUCE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
-// CHECK-DAG: [[SINGLE_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
@@ -195,23 +194,23 @@ int main() {
// CHECK: ret
//
// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}},
-// CHECK-NOT: alloca float,
-// CHECK-NOT: alloca [[S_FLOAT_TY]],
-// CHECK-NOT: alloca [[S_FLOAT_TY]],
-// CHECK-NOT: alloca float,
+// CHECK: alloca float,
+// CHECK: alloca [[S_FLOAT_TY]],
+// CHECK: alloca [[S_FLOAT_TY]],
+// CHECK: alloca float,
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[GTID_REF]]
-// CHECK: call i32 @__kmpc_single(
// CHECK-NOT: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
// CHECK-NOT: call {{.*}} [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
-// CHECK: call void @__kmpc_end_single(
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
-// CHECK: call void @__kmpc_barrier(%{{.+}}* [[SINGLE_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK: call void @__kmpc_barrier(
// CHECK: ret void
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 66a96e431fc9..ea98e7fb0fe5 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -1787,6 +1787,10 @@
// RUN: -target s390x-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_SYSTEMZ_Z10
//
+// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK_SYSTEMZ_Z10: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
// CHECK_SYSTEMZ_Z10: #define __LONG_DOUBLE_128__ 1
// CHECK_SYSTEMZ_Z10: #define __s390__ 1
// CHECK_SYSTEMZ_Z10: #define __s390x__ 1
@@ -1796,6 +1800,10 @@
// RUN: -target s390x-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_SYSTEMZ_ZEC12
//
+// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK_SYSTEMZ_ZEC12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
// CHECK_SYSTEMZ_ZEC12: #define __HTM__ 1
// CHECK_SYSTEMZ_ZEC12: #define __LONG_DOUBLE_128__ 1
// CHECK_SYSTEMZ_ZEC12: #define __s390__ 1
diff --git a/test/SemaObjC/ovl-check.m b/test/SemaObjC/ovl-check.m
new file mode 100644
index 000000000000..7fc8a6404911
--- /dev/null
+++ b/test/SemaObjC/ovl-check.m
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify %s -fobjc-arc
+//
+// These tests exist as a means to help ensure that diagnostics aren't printed
+// in overload resolution in ObjC.
+
+struct Type1 { int a; };
+@interface Iface1 @end
+
+@interface NeverCalled
+- (void) test:(struct Type1 *)arg;
+@end
+
+@interface TakesIface1
+- (void) test:(Iface1 *)arg;
+@end
+
+// PR26085, rdar://problem/24111333
+void testTakesIface1(id x, Iface1 *arg) {
+ // This should resolve silently to `TakesIface1`.
+ [x test:arg];
+}
+
+@class NSString;
+@interface NeverCalledv2
+- (void) testStr:(NSString *)arg;
+@end
+
+@interface TakesVanillaConstChar
+- (void) testStr:(const void *)a;
+@end
+
+// Not called out explicitly by PR26085, but related.
+void testTakesNSString(id x) {
+ // Overload resolution should not emit a diagnostic about needing to add an
+ // '@' before "someStringLiteral".
+ [x testStr:"someStringLiteral"];
+}
+
+typedef const void *CFTypeRef;
+id CreateSomething();
+
+@interface NeverCalledv3
+- (void) testCFTypeRef:(struct Type1 *)arg;
+@end
+
+@interface TakesCFTypeRef
+- (void) testCFTypeRef:(CFTypeRef)arg;
+@end
+
+// Not called out explicitly by PR26085, but related.
+void testTakesCFTypeRef(id x) {
+ // Overload resolution should occur silently, select the CFTypeRef overload,
+ // and produce a single complaint. (with notes)
+ [x testCFTypeRef:CreateSomething()]; // expected-error{{implicit conversion of Objective-C pointer type 'id' to C pointer type 'CFTypeRef'}} expected-note{{use __bridge}} expected-note{{use __bridge_retained}}
+}