From d4aec3a22f5b4c987be1c3815fdadbac72c6de5b Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Feb 13 2016 14:58:13 +0000 Subject: Vendor import of clang release_38 branch r260756: https://llvm.org/svn/llvm-project/cfe/branches/release_38@260756 --- diff --git a/docs/AttributeReference.rst b/docs/AttributeReference.rst index a763dde..4a3649d 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([,]))`` 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 +`_, +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 +`_ 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 ` 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 + 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 struct __single_inheritance A; // warning: inheritance model ignored on primary template + template struct __multiple_inheritance A; // warning: inheritance model ignored on partial specialization + template <> struct __single_inheritance A; + +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 +`_ +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 +`_ +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()))`` 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()))`` 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 `_) 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 9bdbcdb..8c3f46c 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 `_ -.. warning:: - - These are in-progress notes for the upcoming Clang 3.8 release. You may - prefer the `Clang 3.7 Release Notes - `_. - Introduction ============ @@ -31,11 +25,6 @@ the latest release, please check out the main please see the `Clang Web Site `_ or the `LLVM Web Site `_. -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 `_. - 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 `_ 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 37ff16d..2a13350 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 ` 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 5fe1e37..18211e2 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: 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 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 Optimization level /o 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= Dot-separated value representing the Microsoft compiler version number to report in _MSC_VER (0 = don't define it (default)) - -fmsc-version= 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= Microsoft compiler version number to report in _MSC_VER + (0 = don't define it (default)) -fno-sanitize-coverage= Disable specified features of coverage instrumentation for Sanitizers -fno-sanitize-recover= diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ffe1ff3..29aa642 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 0ab1fa7..2ab5a32 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()) @@ -935,108 +1062,136 @@ class TemplateDiff { return Ty->getAs(); } - /// 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(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(FromParamND); - TemplateTypeParmDecl *ToDefaultTypeDecl = - dyn_cast(ToParamND); - if (FromDefaultTypeDecl && ToDefaultTypeDecl) - DiffTypes(FromIter, ToIter, FromDefaultTypeDecl, ToDefaultTypeDecl); - - TemplateTemplateParmDecl *FromDefaultTemplateDecl = - dyn_cast(FromParamND); - TemplateTemplateParmDecl *ToDefaultTemplateDecl = - dyn_cast(ToParamND); - if (FromDefaultTemplateDecl && ToDefaultTemplateDecl) - DiffTemplateTemplates(FromIter, ToIter, FromDefaultTemplateDecl, - ToDefaultTemplateDecl); - - NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = - dyn_cast(FromParamND); - NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = - dyn_cast(ToParamND); - if (FromDefaultNonTypeDecl && ToDefaultNonTypeDecl) + assert(FromParamND->getKind() == ToParamND->getKind() && + "Parameter Decl are not the same kind."); + + if (isa(FromParamND)) { + DiffTypes(FromIter, ToIter); + } else if (isa(FromParamND)) { + DiffTemplateTemplates(FromIter, ToIter); + } else if (isa(FromParamND)) { + NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = + cast(FromParamND); + NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = + cast(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(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(ArgExpr)->getDecl(); - default: - llvm_unreachable("Unexpected template argument kind"); - } - DeclRefExpr *DRE = dyn_cast(ArgExpr); - if (!DRE) { - UnaryOperator *UO = dyn_cast(ArgExpr->IgnoreParens()); - if (!UO) - return nullptr; - DRE = cast(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(E); - if (!DRE) - return false; - - VarDecl *VD = dyn_cast(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(FromExpr->IgnoreParens()), - *ToDRE = dyn_cast(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() == - ToBase.get(); - } - 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(UO->getSubExpr())) return false; + if (isa(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(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 1bc6c51..4f0b124 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 9d145fa..3343080 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 inline U cast(clang::CodeGen::Address addr) { - return U::castImpl(addr); - } - template inline bool isa(clang::CodeGen::Address addr) { - return U::isaImpl(addr); - } +// Present a minimal LLVM-like casting interface. +template inline U cast(CodeGen::Address addr) { + return U::castImpl(addr); +} +template 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 015a739..5cfacac 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(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(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(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(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(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(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 6855512..59821a8 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -1657,50 +1657,51 @@ OpenMPDirectiveKind CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { auto *Stmt = cast(S.getAssociatedStmt())->getCapturedStmt(); auto *CS = dyn_cast(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: - // ; - // break; - // ... - // case - 1: - // - 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: + // ; + // break; + // ... + // case - 1: + // - 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(&S)) - HasCancel = OSD->hasCancel(); - else if (auto *OPSD = dyn_cast(&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()) { + 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(); - // 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(); - 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()) { + + bool HasCancel = false; + if (auto *OSD = dyn_cast(&S)) + HasCancel = OSD->hasCancel(); + else if (auto *OPSD = dyn_cast(&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()) { // 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 beede2e..b669353 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 5a2dbd3..b7ac24f 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 11f2329..82d81a8 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 3e89af6..ebf7981 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(Ty)->getOriginalType(); + break; + case Type::Decayed: + T = cast(Ty)->getPointeeType(); + break; + case Type::Pointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast(Ty)->getPointeeType(); + break; + case Type::MemberPointer: + T = cast(Ty)->getPointeeType(); + break; + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + T = cast(Ty)->getElementType(); + break; + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *VAT = cast(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(CSI)) { + CapRecord = LSI->Lambda; + } else if (auto CRSI = dyn_cast(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(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(Ty)->desugar(); + break; + case Type::Decltype: + T = cast(Ty)->desugar(); + break; + case Type::Auto: + T = cast(Ty)->getDeducedType(); + break; + case Type::TypeOfExpr: + T = cast(Ty)->getUnderlyingExpr()->getType(); + break; + case Type::Atomic: + T = cast(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()) { + if (auto *CSI = dyn_cast(FunctionScopes.back())) { + DeclContext *DC = nullptr; + if (auto LSI = dyn_cast(CSI)) + DC = LSI->CallOperator; + else if (auto CRSI = dyn_cast(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(PRE)) { - ObjCProtocolDecl *PDecl = OPE->getProtocol(); + if (Diagnose && isa(PRE)) { + ObjCProtocolDecl *PDecl = cast(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(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(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(Ty)->getOriginalType(); - break; - case Type::Decayed: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::Pointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::BlockPointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::LValueReference: - case Type::RValueReference: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::MemberPointer: - QTy = cast(Ty)->getPointeeType(); - break; - case Type::ConstantArray: - case Type::IncompleteArray: - // Losing element qualification here is fine. - QTy = cast(Ty)->getElementType(); - break; - case Type::VariableArray: { - // Losing element qualification here is fine. - const VariableArrayType *VAT = cast(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(CSI)) { - CapRecord = LSI->Lambda; - } else if (auto CRSI = dyn_cast(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(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(Ty)->desugar(); - break; - case Type::Decltype: - QTy = cast(Ty)->desugar(); - break; - case Type::Auto: - QTy = cast(Ty)->getDeducedType(); - break; - case Type::TypeOfExpr: - QTy = cast(Ty)->getUnderlyingExpr()->getType(); - break; - case Type::Atomic: - QTy = cast(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 1d86ca3..c1fb906 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(Target)) RelatedClass = cast(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 663da0c..d6a0ff7 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 2ea0561..4df44f4 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 547071c..9d8d527 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 ffaab36..351fbdf 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 e386a21..856b6cc 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 e73fc2c..bf20315 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 struct foo {}; void func(foo); @@ -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 class A{}; + int x; + int y[5]; + A a1 = A(); + // 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 a2 = A(); + // 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 044f07b..70d5e7c 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' to 'A' 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::V aka 40>' to 'A<[...], 10>' a2 = a3; // CHECK-ELIDE-NOTREE: no viable overloaded '=' // CHECK-ELIDE-NOTREE: no known conversion from 'A' to 'A' @@ -1118,7 +1118,7 @@ int global, global2; constexpr int * ptr = nullptr; Wrapper> W = MakeWrapper>(); // Don't print an extra '&' for 'ptr' -// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' // Handle parens correctly Wrapper> W2 = MakeWrapper>(); @@ -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> W1 = MakeWrapper>(); Wrapper(0)>> W2 = MakeWrapper>(); @@ -1156,7 +1156,7 @@ Wrapper(0)>> W2 = MakeWrapper>(); Wrapper> W3 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W4 = MakeWrapper>(); -// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W5 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' @@ -1180,7 +1180,7 @@ Wrapper> W12 = Wrapper> W13 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W14 = MakeWrapper>(); -// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' } namespace TemplateTemplateDefault { @@ -1271,7 +1271,160 @@ void test() { foo>(X); } // CHECK-ELIDE-NOTREE: no matching function for call to 'foo' -// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT] not viable: no known conversion from 'BoolT<0>' to 'BoolT<1>' for 1st argument +// CHECK-ELIDE-NOTREE: candidate function [with T = BoolArgumentBitExtended::BoolT] not viable: no known conversion from 'BoolT' to 'BoolT' for 1st argument +} + +namespace DifferentIntegralTypes { +template +class A{}; +void foo() { + A a1 = A(); + A a2 = A(); + A a3 = A(); +} +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +} + +namespace MixedDeclarationIntegerArgument { +template class A{}; +int x; +int y[5]; + +A a1 = A(); +A a2 = A(); +A a3 = A(); +A a4 = A(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// 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 a5 = A(); +A a6 = A(); +A a7 = A(); +A a8 = A(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'A' to 'A' +// 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 B{} ; +B b1 = B(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B' to 'B' +// CHECK-ELIDE-TREE: error: no viable conversion +// CHECK-ELIDE-TREE: B< +// CHECK-ELIDE-TREE: [int & != int], +// CHECK-ELIDE-TREE: [(default) x != 5]> + +B b2 = B(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B' to 'B' +// CHECK-ELIDE-TREE: B< +// CHECK-ELIDE-TREE: [int != int &], +// CHECK-ELIDE-TREE: [2 != (default) x]> + +template class C {}; +C c1 = C(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C' to 'C' +// CHECK-ELIDE-TREE: error: no viable conversion +// CHECK-ELIDE-TREE: C< +// CHECK-ELIDE-TREE: [int & != int], +// CHECK-ELIDE-TREE: [x != (default) 11]> + +C c2 = C(); +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'C' to 'C' +// CHECK-ELIDE-TREE: C< +// CHECK-ELIDE-TREE: [int != int &], +// CHECK-ELIDE-TREE: [(default) 11 != x]> +} + +namespace default_args { + template + 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 struct A {}; +template > 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' cannot bind to a temporary of type 'A' +} + +namespace PR24587 { +template +struct integral_constant {}; + +auto false_ = integral_constant {}; + +template +void f(T, decltype(false_)); + +void run() { + f(1, integral_constant{}); +} +// 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 class A {}; +template > class B {}; +A<1> a1 = A<>(); +A<> a2 = A<1>(); +B<> b1 = B(); +B b2 = B<>(); +B<> b3 = B>(); +B> 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' to 'B<(default) ZeroArgs::A<0>>' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B<(default) ZeroArgs::A<0>>' to 'B' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B>' to 'B>' +// CHECK-ELIDE-NOTREE: error: no viable conversion from 'B>' to 'B>' } // CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated. diff --git a/test/OpenMP/cancel_codegen.cpp b/test/OpenMP/cancel_codegen.cpp index e2dd367..8234193 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 795f69e..91e6c69 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 b8c1e39..bc7e198 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 44fdefe..291f059 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 f673597..0e9273f 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 a1ff007..6ee9f63 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 @@ -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( // +// 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 cd22188..b812655 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 f67977c..b52d2ee 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 66a96e4..ea98e7f 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 0000000..7fc8a64 --- /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}} +}