diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst index 7549159a39ab..3404b669e248 100644 --- a/docs/AddressSanitizer.rst +++ b/docs/AddressSanitizer.rst @@ -1,294 +1,300 @@ ================ AddressSanitizer ================ .. contents:: :local: Introduction ============ AddressSanitizer is a fast memory error detector. It consists of a compiler instrumentation module and a run-time library. The tool can detect the following types of bugs: * Out-of-bounds accesses to heap, stack and globals * Use-after-free * Use-after-return (runtime flag `ASAN_OPTIONS=detect_stack_use_after_return=1`) * Use-after-scope (clang flag `-fsanitize-address-use-after-scope`) * Double-free, invalid free * Memory leaks (experimental) Typical slowdown introduced by AddressSanitizer is **2x**. How to build ============ Build LLVM/Clang with `CMake `_. Usage ===== Simply compile and link your program with ``-fsanitize=address`` flag. The AddressSanitizer run-time library should be linked to the final executable, so make sure to use ``clang`` (not ``ld``) for the final link step. When linking shared libraries, the AddressSanitizer run-time is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it with AddressSanitizer). To get a reasonable performance add ``-O1`` or higher. To get nicer stack traces in error messages add ``-fno-omit-frame-pointer``. To get perfect stack traces you may need to disable inlining (just use ``-O1``) and tail call elimination (``-fno-optimize-sibling-calls``). .. code-block:: console % cat example_UseAfterFree.cc int main(int argc, char **argv) { int *array = new int[100]; delete [] array; return array[argc]; // BOOM } # Compile and link % clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc or: .. code-block:: console # Compile % clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc # Link % clang++ -g -fsanitize=address example_UseAfterFree.o If a bug is detected, the program will print an error message to stderr and exit with a non-zero exit code. AddressSanitizer exits on the first detected error. This is by design: * This approach allows AddressSanitizer to produce faster and smaller generated code (both by ~5%). * Fixing bugs becomes unavoidable. AddressSanitizer does not produce false alarms. Once a memory corruption occurs, the program is in an inconsistent state, which could lead to confusing results and potentially misleading subsequent reports. If your process is sandboxed and you are running on OS X 10.10 or earlier, you will need to set ``DYLD_INSERT_LIBRARIES`` environment variable and point it to the ASan library that is packaged with the compiler used to build the executable. (You can find the library by searching for dynamic libraries with ``asan`` in their name.) If the environment variable is not set, the process will try to re-exec. Also keep in mind that when moving the executable to another machine, the ASan library will also need to be copied over. Symbolizing the Reports ========================= To make AddressSanitizer symbolize its output you need to set the ``ASAN_SYMBOLIZER_PATH`` environment variable to point to the ``llvm-symbolizer`` binary (or make sure ``llvm-symbolizer`` is in your ``$PATH``): .. code-block:: console % ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer ./a.out ==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8 READ of size 4 at 0x7f7ddab8c084 thread T0 #0 0x403c8c in main example_UseAfterFree.cc:4 #1 0x7f7ddabcac4d in __libc_start_main ??:0 0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210) freed by thread T0 here: #0 0x404704 in operator delete[](void*) ??:0 #1 0x403c53 in main example_UseAfterFree.cc:4 #2 0x7f7ddabcac4d in __libc_start_main ??:0 previously allocated by thread T0 here: #0 0x404544 in operator new[](unsigned long) ??:0 #1 0x403c43 in main example_UseAfterFree.cc:2 #2 0x7f7ddabcac4d in __libc_start_main ??:0 ==9442== ABORTING If that does not work for you (e.g. your process is sandboxed), you can use a separate script to symbolize the result offline (online symbolization can be force disabled by setting ``ASAN_OPTIONS=symbolize=0``): .. code-block:: console % ASAN_OPTIONS=symbolize=0 ./a.out 2> log % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt ==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8 READ of size 4 at 0x7f7ddab8c084 thread T0 #0 0x403c8c in main example_UseAfterFree.cc:4 #1 0x7f7ddabcac4d in __libc_start_main ??:0 ... Note that on OS X you may need to run ``dsymutil`` on your binary to have the file\:line info in the AddressSanitizer reports. Additional Checks ================= Initialization order checking ----------------------------- AddressSanitizer can optionally detect dynamic initialization order problems, when initialization of globals defined in one translation unit uses globals defined in another translation unit. To enable this check at runtime, you should set environment variable ``ASAN_OPTIONS=check_initialization_order=1``. Note that this option is not supported on OS X. Memory leak detection --------------------- For more information on leak detector in AddressSanitizer, see :doc:`LeakSanitizer`. The leak detection is turned on by default on Linux, and can be enabled using ``ASAN_OPTIONS=detect_leaks=1`` on OS X; however, it is not yet supported on other platforms. +Writable/Executable paging detection +------------------------------------ + +The W^X detection is disabled by default and can be enabled using +``ASAN_OPTIONS=detect_write_exec=1``. + Issue Suppression ================= AddressSanitizer is not expected to produce false positives. If you see one, look again; most likely it is a true positive! Suppressing Reports in External Libraries ----------------------------------------- Runtime interposition allows AddressSanitizer to find bugs in code that is not being recompiled. If you run into an issue in external libraries, we recommend immediately reporting it to the library maintainer so that it gets addressed. However, you can use the following suppression mechanism to unblock yourself and continue on with the testing. This suppression mechanism should only be used for suppressing issues in external code; it does not work on code recompiled with AddressSanitizer. To suppress errors in external libraries, set the ``ASAN_OPTIONS`` environment variable to point to a suppression file. You can either specify the full path to the file or the path of the file relative to the location of your executable. .. code-block:: bash ASAN_OPTIONS=suppressions=MyASan.supp Use the following format to specify the names of the functions or libraries you want to suppress. You can see these in the error report. Remember that the narrower the scope of the suppression, the more bugs you will be able to catch. .. code-block:: bash interceptor_via_fun:NameOfCFunctionToSuppress interceptor_via_fun:-[ClassName objCMethodToSuppress:] interceptor_via_lib:NameOfTheLibraryToSuppress Conditional Compilation with ``__has_feature(address_sanitizer)`` ----------------------------------------------------------------- In some cases one may need to execute different code depending on whether AddressSanitizer is enabled. :ref:`\_\_has\_feature ` can be used for this purpose. .. code-block:: c #if defined(__has_feature) # if __has_feature(address_sanitizer) // code that builds only under AddressSanitizer # endif #endif Disabling Instrumentation with ``__attribute__((no_sanitize("address")))`` -------------------------------------------------------------------------- Some code should not be instrumented by AddressSanitizer. One may use the attribute ``__attribute__((no_sanitize("address")))`` (which has deprecated synonyms `no_sanitize_address` and `no_address_safety_analysis`) to disable instrumentation of a particular function. This attribute may not be supported by other compilers, so we suggest to use it together with ``__has_feature(address_sanitizer)``. The same attribute used on a global variable prevents AddressSanitizer from adding redzones around it and detecting out of bounds accesses. Suppressing Errors in Recompiled Code (Blacklist) ------------------------------------------------- AddressSanitizer supports ``src`` and ``fun`` entity types in :doc:`SanitizerSpecialCaseList`, that can be used to suppress error reports in the specified source files or functions. Additionally, AddressSanitizer introduces ``global`` and ``type`` entity types that can be used to suppress error reports for out-of-bound access to globals with certain names and types (you may only specify class or struct types). You may use an ``init`` category to suppress reports about initialization-order problems happening in certain source files or with certain global variables. .. code-block:: bash # Suppress error reports for code in a file or in a function: src:bad_file.cpp # Ignore all functions with names containing MyFooBar: fun:*MyFooBar* # Disable out-of-bound checks for global: global:bad_array # Disable out-of-bound checks for global instances of a given class ... type:Namespace::BadClassName # ... or a given struct. Use wildcard to deal with anonymous namespace. type:Namespace2::*::BadStructName # Disable initialization-order checks for globals: global:bad_init_global=init type:*BadInitClassSubstring*=init src:bad/init/files/*=init Suppressing memory leaks ------------------------ Memory leak reports produced by :doc:`LeakSanitizer` (if it is run as a part of AddressSanitizer) can be suppressed by a separate file passed as .. code-block:: bash LSAN_OPTIONS=suppressions=MyLSan.supp which contains lines of the form `leak:`. Memory leak will be suppressed if pattern matches any function name, source file name, or library name in the symbolized stack trace of the leak report. See `full documentation `_ for more details. Limitations =========== * AddressSanitizer uses more real memory than a native run. Exact overhead depends on the allocations sizes. The smaller the allocations you make the bigger the overhead is. * AddressSanitizer uses more stack memory. We have seen up to 3x increase. * On 64-bit platforms AddressSanitizer maps (but not reserves) 16+ Terabytes of virtual address space. This means that tools like ``ulimit`` may not work as usually expected. * Static linking is not supported. Supported Platforms =================== AddressSanitizer is supported on: * Linux i386/x86\_64 (tested on Ubuntu 12.04) * OS X 10.7 - 10.11 (i386/x86\_64) * iOS Simulator * Android ARM * NetBSD i386/x86\_64 * FreeBSD i386/x86\_64 (tested on FreeBSD 11-current) Ports to various other platforms are in progress. Current Status ============== AddressSanitizer is fully functional on supported platforms starting from LLVM 3.1. The test suite is integrated into CMake build and can be run with ``make check-asan`` command. More Information ================ ``_ diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst index 4e033fa1941d..e979186be1ac 100644 --- a/docs/MemorySanitizer.rst +++ b/docs/MemorySanitizer.rst @@ -1,218 +1,225 @@ ================ MemorySanitizer ================ .. contents:: :local: Introduction ============ MemorySanitizer is a detector of uninitialized reads. It consists of a compiler instrumentation module and a run-time library. Typical slowdown introduced by MemorySanitizer is **3x**. How to build ============ Build LLVM/Clang with `CMake `_. Usage ===== Simply compile and link your program with ``-fsanitize=memory`` flag. The MemorySanitizer run-time library should be linked to the final executable, so make sure to use ``clang`` (not ``ld``) for the final link step. When linking shared libraries, the MemorySanitizer run-time is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it with MemorySanitizer). To get a reasonable performance add ``-O1`` or higher. To get meaningful stack traces in error messages add ``-fno-omit-frame-pointer``. To get perfect stack traces you may need to disable inlining (just use ``-O1``) and tail call elimination (``-fno-optimize-sibling-calls``). .. code-block:: console % cat umr.cc #include int main(int argc, char** argv) { int* a = new int[10]; a[5] = 0; if (a[argc]) printf("xx\n"); return 0; } % clang -fsanitize=memory -fno-omit-frame-pointer -g -O2 umr.cc If a bug is detected, the program will print an error message to stderr and exit with a non-zero exit code. .. code-block:: console % ./a.out WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x7f45944b418a in main umr.cc:6 #1 0x7f45938b676c in __libc_start_main libc-start.c:226 By default, MemorySanitizer exits on the first detected error. If you find the error report hard to understand, try enabling :ref:`origin tracking `. ``__has_feature(memory_sanitizer)`` ------------------------------------ In some cases one may need to execute different code depending on whether MemorySanitizer is enabled. :ref:`\_\_has\_feature ` can be used for this purpose. .. code-block:: c #if defined(__has_feature) # if __has_feature(memory_sanitizer) // code that builds only under MemorySanitizer # endif #endif ``__attribute__((no_sanitize("memory")))`` ----------------------------------------------- Some code should not be checked by MemorySanitizer. One may use the function attribute ``no_sanitize("memory")`` to disable uninitialized checks in a particular function. MemorySanitizer may still instrument such functions to avoid false positives. This attribute may not be supported by other compilers, so we suggest to use it together with ``__has_feature(memory_sanitizer)``. Blacklist --------- MemorySanitizer supports ``src`` and ``fun`` entity types in :doc:`SanitizerSpecialCaseList`, that can be used to relax MemorySanitizer checks for certain source files and functions. All "Use of uninitialized value" warnings will be suppressed and all values loaded from memory will be considered fully initialized. Report symbolization ==================== MemorySanitizer uses an external symbolizer to print files and line numbers in reports. Make sure that ``llvm-symbolizer`` binary is in ``PATH``, or set environment variable ``MSAN_SYMBOLIZER_PATH`` to point to it. .. _msan-origins: Origin Tracking =============== MemorySanitizer can track origins of uninitialized values, similar to Valgrind's --track-origins option. This feature is enabled by ``-fsanitize-memory-track-origins=2`` (or simply ``-fsanitize-memory-track-origins``) Clang option. With the code from the example above, .. code-block:: console % cat umr2.cc #include int main(int argc, char** argv) { int* a = new int[10]; a[5] = 0; volatile int b = a[argc]; if (b) printf("xx\n"); return 0; } % clang -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O2 umr2.cc % ./a.out WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x7f7893912f0b in main umr2.cc:7 #1 0x7f789249b76c in __libc_start_main libc-start.c:226 Uninitialized value was stored to memory at #0 0x7f78938b5c25 in __msan_chain_origin msan.cc:484 #1 0x7f7893912ecd in main umr2.cc:6 Uninitialized value was created by a heap allocation #0 0x7f7893901cbd in operator new[](unsigned long) msan_new_delete.cc:44 #1 0x7f7893912e06 in main umr2.cc:4 By default, MemorySanitizer collects both allocation points and all intermediate stores the uninitialized value went through. Origin tracking has proved to be very useful for debugging MemorySanitizer reports. It slows down program execution by a factor of 1.5x-2x on top of the usual MemorySanitizer slowdown and increases memory overhead. Clang option ``-fsanitize-memory-track-origins=1`` enables a slightly faster mode when MemorySanitizer collects only allocation points but not intermediate stores. Use-after-destruction detection =============================== You can enable experimental use-after-destruction detection in MemorySanitizer. After invocation of the destructor, the object will be considered no longer readable, and using underlying memory will lead to error reports in runtime. This feature is still experimental, in order to enable it at runtime you need to: #. Pass addition Clang option ``-fsanitize-memory-use-after-dtor`` during compilation. #. Set environment variable `MSAN_OPTIONS=poison_in_dtor=1` before running the program. +Writable/Executable paging detection +==================================== + +You can eable writable-executable page detection in MemorySanitizer by +setting the environment variable `MSAN_OPTIONS=detect_write_exec=1` before +running the program. + Handling external code ====================== MemorySanitizer requires that all program code is instrumented. This also includes any libraries that the program depends on, even libc. Failing to achieve this may result in false reports. For the same reason you may need to replace all inline assembly code that writes to memory with a pure C/C++ code. Full MemorySanitizer instrumentation is very difficult to achieve. To make it easier, MemorySanitizer runtime library includes 70+ interceptors for the most common libc functions. They make it possible to run MemorySanitizer-instrumented programs linked with uninstrumented libc. For example, the authors were able to bootstrap MemorySanitizer-instrumented Clang compiler by linking it with self-built instrumented libc++ (as a replacement for libstdc++). Supported Platforms =================== MemorySanitizer is supported on the following OS: * Linux * NetBSD * FreeBSD Limitations =========== * MemorySanitizer uses 2x more real memory than a native run, 3x with origin tracking. * MemorySanitizer maps (but not reserves) 64 Terabytes of virtual address space. This means that tools like ``ulimit`` may not work as usually expected. * Static linking is not supported. * Older versions of MSan (LLVM 3.7 and older) didn't work with non-position-independent executables, and could fail on some Linux kernel versions with disabled ASLR. Refer to documentation for older versions for more details. Current Status ============== MemorySanitizer is known to work on large real-world programs (like Clang/LLVM itself) that can be recompiled from source, including all dependent libraries. More Information ================ ``_ diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 01702023c540..5f446d85dc8c 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -1,354 +1,355 @@ ======================================= Clang 7.0.0 (In-Progress) Release Notes ======================================= .. contents:: :local: :depth: 2 Written by the `LLVM Team `_ .. warning:: These are in-progress notes for the upcoming Clang 7 release. Release notes for previous releases can be found on `the Download Page `_. Introduction ============ This document contains the release notes for the Clang C/C++/Objective-C frontend, part of the LLVM Compiler Infrastructure, release 7.0.0. Here we describe the status of Clang in some detail, including major improvements from the previous release and new feature work. For the general LLVM release notes, see `the LLVM documentation `_. All LLVM releases may be downloaded from the `LLVM releases web site `_. For more information about Clang or LLVM, including information about the latest release, 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 7.0.0? ========================== Some of the major new features and improvements to Clang are listed here. Generic improvements to Clang as a whole or to its underlying infrastructure are described first, followed by language-specific sections with improvements to Clang's support for those languages. Major New Features ------------------ - A new Implicit Conversion Sanitizer (``-fsanitize=implicit-conversion``) group was added. Please refer to the :ref:`release-notes-ubsan` section of the release notes for the details. - Preliminary/experimental support for DWARF v5 debugging information. If you compile with ``-gdwarf-5 -O0`` you should get fully conforming DWARF v5 information, including the new .debug_names accelerator table. Type units and split DWARF are known not to conform, and higher optimization levels will likely get a mix of v4 and v5 formats. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``-Wc++98-compat-extra-semi`` is a new flag, which was previously inseparable from ``-Wc++98-compat-pedantic``. The latter still controls the new flag. - ``-Wextra-semi`` now also controls ``-Wc++98-compat-extra-semi``. Please do note that if you pass ``-Wno-c++98-compat-pedantic``, it implies ``-Wno-c++98-compat-extra-semi``, so if you want that diagnostic, you need to explicitly re-enable it (e.g. by appending ``-Wextra-semi``). - ``-Wself-assign`` and ``-Wself-assign-field`` were extended to diagnose self-assignment operations using overloaded operators (i.e. classes). If you are doing such an assignment intentionally, e.g. in a unit test for a data structure, the first warning can be disabled by passing ``-Wno-self-assign-overloaded``, also the warning can be suppressed by adding ``*&`` to the right-hand side or casting it to the appropriate reference type. Non-comprehensive list of changes in this release ------------------------------------------------- - Clang binary and libraries have been renamed from 7.0 to 7. For example, the ``clang`` binary will be called ``clang-7`` instead of ``clang-7.0``. - Clang implements a collection of recent fixes to the C++ standard's definition of "standard-layout". In particular, a class is only considered to be standard-layout if all base classes and the first data member (or bit-field) can be laid out at offset zero. - Clang's handling of the GCC ``packed`` class attribute in C++ has been fixed to apply only to non-static data members and not to base classes. This fixes an ABI difference between Clang and GCC, but creates an ABI difference between Clang 7 and earlier versions. The old behavior can be restored by setting ``-fclang-abi-compat`` to ``6`` or earlier. - Clang implements the proposed resolution of LWG issue 2358, along with the `corresponding change to the Itanium C++ ABI `_, which make classes containing only unnamed non-zero-length bit-fields be considered non-empty. This is an ABI break compared to prior Clang releases, but makes Clang generate code that is ABI-compatible with other compilers. The old behavior can be restored by setting ``-fclang-abi-compat`` to ``6`` or lower. - An existing tool named ``diagtool`` has been added to the release. As the name suggests, it helps with dealing with diagnostics in ``clang``, such as finding out the warning hierarchy, and which of them are enabled by default or for a particular compiler invocation. - By default, Clang emits an address-significance table into every ELF object file when using the integrated assembler. Address-significance tables allow linkers to implement `safe ICF `_ without the false positives that can result from other implementation techniques such as relocation scanning. The ``-faddrsig`` and ``-fno-addrsig`` flags can be used to control whether to emit the address-significance table. - ... New Compiler Flags ------------------ - ``-fstrict-float-cast-overflow`` and ``-fno-strict-float-cast-overflow``. When a floating-point value is not representable in a destination integer type, the code has undefined behavior according to the language standard. By default, Clang will not guarantee any particular result in that case. With the 'no-strict' option, Clang attempts to match the overflowing behavior of the target's native float-to-int conversion instructions. - ``-fforce-emit-vtables`` and ``-fno-force-emit-vtables``. In order to improve devirtualization, forces emitting of vtables even in modules where it isn't necessary. It causes more inline virtual functions to be emitted. - ... Deprecated Compiler Flags ------------------------- The following options are deprecated and ignored. They will be removed in future versions of Clang. - ... Modified Compiler Flags ----------------------- - Before Clang 7, we prepended the `#` character to the `--autocomplete` argument to enable cc1 flags. For example, when the `-cc1` or `-Xclang` flag is in the :program:`clang` invocation, the shell executed `clang --autocomplete=#-`. Clang 7 now requires the whole invocation including all flags to be passed to the `--autocomplete` like this: `clang --autocomplete=-cc1,-xc++,-fsyn`. New Pragmas in Clang -------------------- Clang now supports the ... Attribute Changes in Clang -------------------------- - Clang now supports function multiversioning with attribute 'target' on ELF based x86/x86-64 environments by using indirect functions. This implementation has a few minor limitations over the GCC implementation for the sake of AST sanity, however it is otherwise compatible with existing code using this feature for GCC. Consult the documentation for the target attribute for more information. - ... Windows Support --------------- - clang-cl's support for precompiled headers has been much improved: - When using a pch file, clang-cl now no longer redundantly emits inline methods that are already stored in the obj that was built together with the pch file (matching cl.exe). This speeds up builds using pch files by around 30%. - The /Ycfoo.h and /Yufoo.h flags can now be used without /FIfoo.h when foo.h is instead included by an explicit `#include` directive. This means Visual Studio's default stdafx.h setup now uses precompiled headers with clang-cl. - ... C Language Changes in Clang --------------------------- - ... ... C11 Feature Support ^^^^^^^^^^^^^^^^^^^ ... C++ Language Changes in Clang ----------------------------- - ... C++1z Feature Support ^^^^^^^^^^^^^^^^^^^^^ ... Objective-C Language Changes in Clang ------------------------------------- ... OpenCL C Language Changes in Clang ---------------------------------- ... OpenMP Support in Clang ---------------------------------- - Clang gained basic support for OpenMP 4.5 offloading for NVPTX target. To compile your program for NVPTX target use the following options: `-fopenmp -fopenmp-targets=nvptx64-nvidia-cuda` for 64 bit platforms or `-fopenmp -fopenmp-targets=nvptx-nvidia-cuda` for 32 bit platform. - Passing options to the OpenMP device offloading toolchain can be done using the `-Xopenmp-target= -opt=val` flag. In this way the `-opt=val` option will be forwarded to the respective OpenMP device offloading toolchain described by the triple. For example passing the compute capability to the OpenMP NVPTX offloading toolchain can be done as follows: `-Xopenmp-target=nvptx64-nvidia-cuda -march=sm_60`. For the case when only one target offload toolchain is specified under the `-fopenmp-targets=` option, then the triple can be skipped: `-Xopenmp-target -march=sm_60`. - Other bugfixes. CUDA Support in Clang --------------------- - Clang will now try to locate the CUDA installation next to :program:`ptxas` in the `PATH` environment variable. This behavior can be turned off by passing the new flag `--cuda-path-ignore-env`. - Clang now supports generating object files with relocatable device code. This feature needs to be enabled with `-fcuda-rdc` and my result in performance penalties compared to whole program compilation. Please note that NVIDIA's :program:`nvcc` must be used for linking. Internal API Changes -------------------- These are major API changes that have happened since the 6.0.0 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. - ... AST Matchers ------------ - ... clang-format ------------ - Clang-format will now support detecting and formatting code snippets in raw string literals. This is configured through the `RawStringFormats` style option. - ... libclang -------- ... Static Analyzer --------------- -- ... +- The new `MmapWriteExec` checker had been introduced to detect attempts to map pages +both writable and executable. ... .. _release-notes-ubsan: Undefined Behavior Sanitizer (UBSan) ------------------------------------ * A new Implicit Conversion Sanitizer (``-fsanitize=implicit-conversion``) group was added. Currently, only one type of issues is caught - implicit integer truncation (``-fsanitize=implicit-integer-truncation``), also known as integer demotion. While there is a ``-Wconversion`` diagnostic group that catches this kind of issues, it is both noisy, and does not catch **all** the cases. .. code-block:: c++ unsigned char store = 0; bool consume(unsigned int val); void test(unsigned long val) { if (consume(val)) // the value may have been silently truncated. store = store + 768; // before addition, 'store' was promoted to int. (void)consume((unsigned int)val); // OK, the truncation is explicit. } Just like other ``-fsanitize=integer`` checks, these issues are **not** undefined behaviour. But they are not *always* intentional, and are somewhat hard to track down. This group is **not** enabled by ``-fsanitize=undefined``, but the ``-fsanitize=implicit-integer-truncation`` check is enabled by ``-fsanitize=integer``. Core Analysis Improvements ========================== - ... New Issues Found ================ - ... Python Binding Changes ---------------------- The following methods have been added: - ... Significant Known Problems ========================== Additional Information ====================== A wide variety of additional information is available on the `Clang web page `_. The web page contains versions of the API documentation which are up-to-date with the Subversion version of the source code. You can access versions of these documents specific to this release by going into the "``clang/docs/``" directory in the Clang tree. If you have any questions or comments about Clang, please feel free to contact us via the `mailing list `_. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 8269b5b229a2..906b98bfbafe 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -1,2666 +1,2690 @@ //===--- CGBlocks.cpp - Emit LLVM Code for declarations ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code to emit blocks. // //===----------------------------------------------------------------------===// #include "CGBlocks.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/DeclObjC.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/SmallSet.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" #include #include using namespace clang; using namespace CodeGen; CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name) : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false), LocalAddress(Address::invalid()), StructureType(nullptr), Block(block), DominatingIP(nullptr) { // Skip asm prefix, if any. 'name' is usually taken directly from // the mangled name of the enclosing function. if (!name.empty() && name[0] == '\01') name = name.substr(1); } // Anchor the vtable to this translation unit. BlockByrefHelpers::~BlockByrefHelpers() {} /// Build the given block as a global block. static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, const CGBlockInfo &blockInfo, llvm::Constant *blockFn); /// Build the helper function to copy a block. static llvm::Constant *buildCopyHelper(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo); } /// Build the helper function to dispose of a block. static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo); } /// buildBlockDescriptor - Build the block descriptor meta-data for a block. /// buildBlockDescriptor is accessed from 5th field of the Block_literal /// meta-data and contains stationary information about the block literal. /// Its definition will have 4 (or optionally 6) words. /// \code /// struct Block_descriptor { /// unsigned long reserved; /// unsigned long size; // size of Block_literal metadata in bytes. /// void *copy_func_helper_decl; // optional copy helper. /// void *destroy_func_decl; // optioanl destructor helper. /// void *block_method_encoding_address; // @encode for block literal signature. /// void *block_layout_info; // encoding of captured block variables. /// }; /// \endcode static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { ASTContext &C = CGM.getContext(); llvm::IntegerType *ulong = cast(CGM.getTypes().ConvertType(C.UnsignedLongTy)); llvm::PointerType *i8p = nullptr; if (CGM.getLangOpts().OpenCL) i8p = llvm::Type::getInt8PtrTy( CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant)); else i8p = CGM.VoidPtrTy; ConstantInitBuilder builder(CGM); auto elements = builder.beginStruct(); // reserved elements.addInt(ulong, 0); // Size // FIXME: What is the right way to say this doesn't fit? We should give // a user diagnostic in that case. Better fix would be to change the // API to size_t. elements.addInt(ulong, blockInfo.BlockSize.getQuantity()); // Optional copy/dispose helpers. if (blockInfo.needsCopyDisposeHelpers()) { // copy_func_helper_decl elements.add(buildCopyHelper(CGM, blockInfo)); // destroy_func_decl elements.add(buildDisposeHelper(CGM, blockInfo)); } // Signature. Mandatory ObjC-style method descriptor @encode sequence. std::string typeAtEncoding = CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr()); elements.add(llvm::ConstantExpr::getBitCast( CGM.GetAddrOfConstantCString(typeAtEncoding).getPointer(), i8p)); // GC layout. if (C.getLangOpts().ObjC1) { if (CGM.getLangOpts().getGC() != LangOptions::NonGC) elements.add(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); else elements.add(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo)); } else elements.addNullPointer(i8p); unsigned AddrSpace = 0; if (C.getLangOpts().OpenCL) AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant); llvm::GlobalVariable *global = elements.finishAndCreateGlobal("__block_descriptor_tmp", CGM.getPointerAlign(), /*constant*/ true, llvm::GlobalValue::InternalLinkage, AddrSpace); return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } /* Purely notional variadic template describing the layout of a block. template struct Block_literal { /// Initialized to one of: /// extern void *_NSConcreteStackBlock[]; /// extern void *_NSConcreteGlobalBlock[]; /// /// In theory, we could start one off malloc'ed by setting /// BLOCK_NEEDS_FREE, giving it a refcount of 1, and using /// this isa: /// extern void *_NSConcreteMallocBlock[]; struct objc_class *isa; /// These are the flags (with corresponding bit number) that the /// compiler is actually supposed to know about. /// 23. BLOCK_IS_NOESCAPE - indicates that the block is non-escaping /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block /// descriptor provides copy and dispose helper functions /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured /// object with a nontrivial destructor or copy constructor /// 28. BLOCK_IS_GLOBAL - indicates that the block is allocated /// as global memory /// 29. BLOCK_USE_STRET - indicates that the block function /// uses stret, which objc_msgSend needs to know about /// 30. BLOCK_HAS_SIGNATURE - indicates that the block has an /// @encoded signature string /// And we're not supposed to manipulate these: /// 24. BLOCK_NEEDS_FREE - indicates that the block has been moved /// to malloc'ed memory /// 27. BLOCK_IS_GC - indicates that the block has been moved to /// to GC-allocated memory /// Additionally, the bottom 16 bits are a reference count which /// should be zero on the stack. int flags; /// Reserved; should be zero-initialized. int reserved; /// Function pointer generated from block literal. _ResultType (*invoke)(Block_literal *, _ParamTypes...); /// Block description metadata generated from block literal. struct Block_descriptor *block_descriptor; /// Captured values follow. _CapturesTypes captures...; }; */ namespace { /// A chunk of data that we actually have to capture in the block. struct BlockLayoutChunk { CharUnits Alignment; CharUnits Size; Qualifiers::ObjCLifetime Lifetime; const BlockDecl::Capture *Capture; // null for 'this' llvm::Type *Type; QualType FieldType; BlockLayoutChunk(CharUnits align, CharUnits size, Qualifiers::ObjCLifetime lifetime, const BlockDecl::Capture *capture, llvm::Type *type, QualType fieldType) : Alignment(align), Size(size), Lifetime(lifetime), Capture(capture), Type(type), FieldType(fieldType) {} /// Tell the block info that this chunk has the given field index. void setIndex(CGBlockInfo &info, unsigned index, CharUnits offset) { if (!Capture) { info.CXXThisIndex = index; info.CXXThisOffset = offset; } else { auto C = CGBlockInfo::Capture::makeIndex(index, offset, FieldType); info.Captures.insert({Capture->getVariable(), C}); } } }; /// Order by 1) all __strong together 2) next, all byfref together 3) next, /// all __weak together. Preserve descending alignment in all situations. bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) { if (left.Alignment != right.Alignment) return left.Alignment > right.Alignment; auto getPrefOrder = [](const BlockLayoutChunk &chunk) { if (chunk.Capture && chunk.Capture->isByRef()) return 1; if (chunk.Lifetime == Qualifiers::OCL_Strong) return 0; if (chunk.Lifetime == Qualifiers::OCL_Weak) return 2; return 3; }; return getPrefOrder(left) < getPrefOrder(right); } } // end anonymous namespace /// Determines if the given type is safe for constant capture in C++. static bool isSafeForCXXConstantCapture(QualType type) { const RecordType *recordType = type->getBaseElementTypeUnsafe()->getAs(); // Only records can be unsafe. if (!recordType) return true; const auto *record = cast(recordType->getDecl()); // Maintain semantics for classes with non-trivial dtors or copy ctors. if (!record->hasTrivialDestructor()) return false; if (record->hasNonTrivialCopyConstructor()) return false; // Otherwise, we just have to make sure there aren't any mutable // fields that might have changed since initialization. return !record->hasMutableFields(); } /// It is illegal to modify a const object after initialization. /// Therefore, if a const object has a constant initializer, we don't /// actually need to keep storage for it in the block; we'll just /// rematerialize it at the start of the block function. This is /// acceptable because we make no promises about address stability of /// captured variables. static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM, CodeGenFunction *CGF, const VarDecl *var) { // Return if this is a function parameter. We shouldn't try to // rematerialize default arguments of function parameters. if (isa(var)) return nullptr; QualType type = var->getType(); // We can only do this if the variable is const. if (!type.isConstQualified()) return nullptr; // Furthermore, in C++ we have to worry about mutable fields: // C++ [dcl.type.cv]p4: // Except that any class member declared mutable can be // modified, any attempt to modify a const object during its // lifetime results in undefined behavior. if (CGM.getLangOpts().CPlusPlus && !isSafeForCXXConstantCapture(type)) return nullptr; // If the variable doesn't have any initializer (shouldn't this be // invalid?), it's not clear what we should do. Maybe capture as // zero? const Expr *init = var->getInit(); if (!init) return nullptr; return ConstantEmitter(CGM, CGF).tryEmitAbstractForInitializer(*var); } /// Get the low bit of a nonzero character count. This is the /// alignment of the nth byte if the 0th byte is universally aligned. static CharUnits getLowBit(CharUnits v) { return CharUnits::fromQuantity(v.getQuantity() & (~v.getQuantity() + 1)); } static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, SmallVectorImpl &elementTypes) { assert(elementTypes.empty()); if (CGM.getLangOpts().OpenCL) { // The header is basically 'struct { int; int; // custom_fields; }'. Assert that struct is packed. elementTypes.push_back(CGM.IntTy); /* total size */ elementTypes.push_back(CGM.IntTy); /* align */ unsigned Offset = 2 * CGM.getIntSize().getQuantity(); unsigned BlockAlign = CGM.getIntAlign().getQuantity(); if (auto *Helper = CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ { // TargetOpenCLBlockHelp needs to make sure the struct is packed. // If necessary, add padding fields to the custom fields. unsigned Align = CGM.getDataLayout().getABITypeAlignment(I); if (BlockAlign < Align) BlockAlign = Align; assert(Offset % Align == 0); Offset += CGM.getDataLayout().getTypeAllocSize(I); elementTypes.push_back(I); } } info.BlockAlign = CharUnits::fromQuantity(BlockAlign); info.BlockSize = CharUnits::fromQuantity(Offset); } else { // The header is basically 'struct { void *; int; int; void *; void *; }'. // Assert that the struct is packed. assert(CGM.getIntSize() <= CGM.getPointerSize()); assert(CGM.getIntAlign() <= CGM.getPointerAlign()); assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign())); info.BlockAlign = CGM.getPointerAlign(); info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize(); elementTypes.push_back(CGM.VoidPtrTy); elementTypes.push_back(CGM.IntTy); elementTypes.push_back(CGM.IntTy); elementTypes.push_back(CGM.VoidPtrTy); elementTypes.push_back(CGM.getBlockDescriptorType()); } } static QualType getCaptureFieldType(const CodeGenFunction &CGF, const BlockDecl::Capture &CI) { const VarDecl *VD = CI.getVariable(); // If the variable is captured by an enclosing block or lambda expression, // use the type of the capture field. if (CGF.BlockInfo && CI.isNested()) return CGF.BlockInfo->getCapture(VD).fieldType(); if (auto *FD = CGF.LambdaCaptureFields.lookup(VD)) return FD->getType(); return VD->getType(); } /// Compute the layout of the given block. Attempts to lay the block /// out with minimal space requirements. static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, CGBlockInfo &info) { ASTContext &C = CGM.getContext(); const BlockDecl *block = info.getBlockDecl(); SmallVector elementTypes; initializeForBlockHeader(CGM, info, elementTypes); bool hasNonConstantCustomFields = false; if (auto *OpenCLHelper = CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) hasNonConstantCustomFields = !OpenCLHelper->areAllCustomFieldValuesConstant(info); if (!block->hasCaptures() && !hasNonConstantCustomFields) { info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); info.CanBeGlobal = true; return; } else if (C.getLangOpts().ObjC1 && CGM.getLangOpts().getGC() == LangOptions::NonGC) info.HasCapturedVariableLayout = true; // Collect the layout chunks. SmallVector layout; layout.reserve(block->capturesCXXThis() + (block->capture_end() - block->capture_begin())); CharUnits maxFieldAlign; // First, 'this'. if (block->capturesCXXThis()) { assert(CGF && CGF->CurFuncDecl && isa(CGF->CurFuncDecl) && "Can't capture 'this' outside a method"); QualType thisType = cast(CGF->CurFuncDecl)->getThisType(C); // Theoretically, this could be in a different address space, so // don't assume standard pointer size/align. llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); std::pair tinfo = CGM.getContext().getTypeInfoInChars(thisType); maxFieldAlign = std::max(maxFieldAlign, tinfo.second); layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, Qualifiers::OCL_None, nullptr, llvmType, thisType)); } // Next, all the block captures. for (const auto &CI : block->captures()) { const VarDecl *variable = CI.getVariable(); if (CI.isByRef()) { // We have to copy/dispose of the __block reference. info.NeedsCopyDispose = true; // Just use void* instead of a pointer to the byref type. CharUnits align = CGM.getPointerAlign(); maxFieldAlign = std::max(maxFieldAlign, align); layout.push_back(BlockLayoutChunk(align, CGM.getPointerSize(), Qualifiers::OCL_None, &CI, CGM.VoidPtrTy, variable->getType())); continue; } // Otherwise, build a layout chunk with the size and alignment of // the declaration. if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) { info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant); continue; } // If we have a lifetime qualifier, honor it for capture purposes. // That includes *not* copying it if it's __unsafe_unretained. Qualifiers::ObjCLifetime lifetime = variable->getType().getObjCLifetime(); if (lifetime) { switch (lifetime) { case Qualifiers::OCL_None: llvm_unreachable("impossible"); case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: info.NeedsCopyDispose = true; } // Block pointers require copy/dispose. So do Objective-C pointers. } else if (variable->getType()->isObjCRetainableType()) { // But honor the inert __unsafe_unretained qualifier, which doesn't // actually make it into the type system. if (variable->getType()->isObjCInertUnsafeUnretainedType()) { lifetime = Qualifiers::OCL_ExplicitNone; } else { info.NeedsCopyDispose = true; // used for mrr below. lifetime = Qualifiers::OCL_Strong; } // So do types that require non-trivial copy construction. } else if (CI.hasCopyExpr()) { info.NeedsCopyDispose = true; info.HasCXXObject = true; // So do C structs that require non-trivial copy construction or // destruction. } else if (variable->getType().isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct || variable->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) { info.NeedsCopyDispose = true; // And so do types with destructors. } else if (CGM.getLangOpts().CPlusPlus) { if (const CXXRecordDecl *record = variable->getType()->getAsCXXRecordDecl()) { if (!record->hasTrivialDestructor()) { info.HasCXXObject = true; info.NeedsCopyDispose = true; } } } QualType VT = getCaptureFieldType(*CGF, CI); CharUnits size = C.getTypeSizeInChars(VT); CharUnits align = C.getDeclAlign(variable); maxFieldAlign = std::max(maxFieldAlign, align); llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(VT); layout.push_back( BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT)); } // If that was everything, we're done here. if (layout.empty()) { info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); info.CanBeGlobal = true; return; } // Sort the layout by alignment. We have to use a stable sort here // to get reproducible results. There should probably be an // llvm::array_pod_stable_sort. std::stable_sort(layout.begin(), layout.end()); // Needed for blocks layout info. info.BlockHeaderForcedGapOffset = info.BlockSize; info.BlockHeaderForcedGapSize = CharUnits::Zero(); CharUnits &blockSize = info.BlockSize; info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign); // Assuming that the first byte in the header is maximally aligned, // get the alignment of the first byte following the header. CharUnits endAlign = getLowBit(blockSize); // If the end of the header isn't satisfactorily aligned for the // maximum thing, look for things that are okay with the header-end // alignment, and keep appending them until we get something that's // aligned right. This algorithm is only guaranteed optimal if // that condition is satisfied at some point; otherwise we can get // things like: // header // next byte has alignment 4 // something_with_size_5; // next byte has alignment 1 // something_with_alignment_8; // which has 7 bytes of padding, as opposed to the naive solution // which might have less (?). if (endAlign < maxFieldAlign) { SmallVectorImpl::iterator li = layout.begin() + 1, le = layout.end(); // Look for something that the header end is already // satisfactorily aligned for. for (; li != le && endAlign < li->Alignment; ++li) ; // If we found something that's naturally aligned for the end of // the header, keep adding things... if (li != le) { SmallVectorImpl::iterator first = li; for (; li != le; ++li) { assert(endAlign >= li->Alignment); li->setIndex(info, elementTypes.size(), blockSize); elementTypes.push_back(li->Type); blockSize += li->Size; endAlign = getLowBit(blockSize); // ...until we get to the alignment of the maximum field. if (endAlign >= maxFieldAlign) { break; } } // Don't re-append everything we just appended. layout.erase(first, li); } } assert(endAlign == getLowBit(blockSize)); // At this point, we just have to add padding if the end align still // isn't aligned right. if (endAlign < maxFieldAlign) { CharUnits newBlockSize = blockSize.alignTo(maxFieldAlign); CharUnits padding = newBlockSize - blockSize; // If we haven't yet added any fields, remember that there was an // initial gap; this need to go into the block layout bit map. if (blockSize == info.BlockHeaderForcedGapOffset) { info.BlockHeaderForcedGapSize = padding; } elementTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty, padding.getQuantity())); blockSize = newBlockSize; endAlign = getLowBit(blockSize); // might be > maxFieldAlign } assert(endAlign >= maxFieldAlign); assert(endAlign == getLowBit(blockSize)); // Slam everything else on now. This works because they have // strictly decreasing alignment and we expect that size is always a // multiple of alignment. for (SmallVectorImpl::iterator li = layout.begin(), le = layout.end(); li != le; ++li) { if (endAlign < li->Alignment) { // size may not be multiple of alignment. This can only happen with // an over-aligned variable. We will be adding a padding field to // make the size be multiple of alignment. CharUnits padding = li->Alignment - endAlign; elementTypes.push_back(llvm::ArrayType::get(CGM.Int8Ty, padding.getQuantity())); blockSize += padding; endAlign = getLowBit(blockSize); } assert(endAlign >= li->Alignment); li->setIndex(info, elementTypes.size(), blockSize); elementTypes.push_back(li->Type); blockSize += li->Size; endAlign = getLowBit(blockSize); } info.StructureType = llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); } /// Enter the scope of a block. This should be run at the entrance to /// a full-expression so that the block's cleanups are pushed at the /// right place in the stack. static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { assert(CGF.HaveInsertPoint()); // Allocate the block info and place it at the head of the list. CGBlockInfo &blockInfo = *new CGBlockInfo(block, CGF.CurFn->getName()); blockInfo.NextBlockInfo = CGF.FirstBlockInfo; CGF.FirstBlockInfo = &blockInfo; // Compute information about the layout, etc., of this block, // pushing cleanups as necessary. computeBlockInfo(CGF.CGM, &CGF, blockInfo); // Nothing else to do if it can be global. if (blockInfo.CanBeGlobal) return; // Make the allocation for the block. blockInfo.LocalAddress = CGF.CreateTempAlloca(blockInfo.StructureType, blockInfo.BlockAlign, "block"); // If there are cleanups to emit, enter them (but inactive). if (!blockInfo.NeedsCopyDispose) return; // Walk through the captures (in order) and find the ones not // captured by constant. for (const auto &CI : block->captures()) { // Ignore __block captures; there's nothing special in the // on-stack block that we need to do for them. if (CI.isByRef()) continue; // Ignore variables that are constant-captured. const VarDecl *variable = CI.getVariable(); CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) continue; // Ignore objects that aren't destructed. QualType VT = getCaptureFieldType(CGF, CI); QualType::DestructionKind dtorKind = VT.isDestructedType(); if (dtorKind == QualType::DK_none) continue; CodeGenFunction::Destroyer *destroyer; // Block captures count as local values and have imprecise semantics. // They also can't be arrays, so need to worry about that. // // For const-qualified captures, emit clang.arc.use to ensure the captured // object doesn't get released while we are still depending on its validity // within the block. if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong && CGF.CGM.getCodeGenOpts().OptimizationLevel != 0) { assert(CGF.CGM.getLangOpts().ObjCAutoRefCount && "expected ObjC ARC to be enabled"); destroyer = CodeGenFunction::emitARCIntrinsicUse; } else if (dtorKind == QualType::DK_objc_strong_lifetime) { destroyer = CodeGenFunction::destroyARCStrongImprecise; } else { destroyer = CGF.getDestroyer(dtorKind); } // GEP down to the address. Address addr = CGF.Builder.CreateStructGEP(blockInfo.LocalAddress, capture.getIndex(), capture.getOffset()); // We can use that GEP as the dominating IP. if (!blockInfo.DominatingIP) blockInfo.DominatingIP = cast(addr.getPointer()); CleanupKind cleanupKind = InactiveNormalCleanup; bool useArrayEHCleanup = CGF.needsEHCleanup(dtorKind); if (useArrayEHCleanup) cleanupKind = InactiveNormalAndEHCleanup; CGF.pushDestroy(cleanupKind, addr, VT, destroyer, useArrayEHCleanup); // Remember where that cleanup was. capture.setCleanup(CGF.EHStack.stable_begin()); } } /// Enter a full-expression with a non-trivial number of objects to /// clean up. This is in this file because, at the moment, the only /// kind of cleanup object is a BlockDecl*. void CodeGenFunction::enterNonTrivialFullExpression(const ExprWithCleanups *E) { assert(E->getNumObjects() != 0); for (const ExprWithCleanups::CleanupObject &C : E->getObjects()) enterBlockScope(*this, C); } /// Find the layout for the given block in a linked list and remove it. static CGBlockInfo *findAndRemoveBlockInfo(CGBlockInfo **head, const BlockDecl *block) { while (true) { assert(head && *head); CGBlockInfo *cur = *head; // If this is the block we're looking for, splice it out of the list. if (cur->getBlockDecl() == block) { *head = cur->NextBlockInfo; return cur; } head = &cur->NextBlockInfo; } } /// Destroy a chain of block layouts. void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) { assert(head && "destroying an empty chain"); do { CGBlockInfo *cur = head; head = cur->NextBlockInfo; delete cur; } while (head != nullptr); } /// Emit a block literal expression in the current function. llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { // If the block has no captures, we won't have a pre-computed // layout for it. if (!blockExpr->getBlockDecl()->hasCaptures()) { // The block literal is emitted as a global variable, and the block invoke // function has to be extracted from its initializer. if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) { return Block; } CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName()); computeBlockInfo(CGM, this, blockInfo); blockInfo.BlockExpression = blockExpr; return EmitBlockLiteral(blockInfo); } // Find the block info for this block and take ownership of it. std::unique_ptr blockInfo; blockInfo.reset(findAndRemoveBlockInfo(&FirstBlockInfo, blockExpr->getBlockDecl())); blockInfo->BlockExpression = blockExpr; return EmitBlockLiteral(*blockInfo); } llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL; // Using the computed layout, generate the actual block function. bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda(); CodeGenFunction BlockCGF{CGM, true}; BlockCGF.SanOpts = SanOpts; auto *InvokeFn = BlockCGF.GenerateBlockFunction( CurGD, blockInfo, LocalDeclMap, isLambdaConv, blockInfo.CanBeGlobal); // If there is nothing to capture, we can emit this as a global block. if (blockInfo.CanBeGlobal) return CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression); // Otherwise, we have to emit this as a local block. Address blockAddr = blockInfo.LocalAddress; assert(blockAddr.isValid() && "block has no address!"); llvm::Constant *isa; llvm::Constant *descriptor; BlockFlags flags; if (!IsOpenCL) { // If the block is non-escaping, set field 'isa 'to NSConcreteGlobalBlock // and set the BLOCK_IS_GLOBAL bit of field 'flags'. Copying a non-escaping // block just returns the original block and releasing it is a no-op. llvm::Constant *blockISA = blockInfo.getBlockDecl()->doesNotEscape() ? CGM.getNSConcreteGlobalBlock() : CGM.getNSConcreteStackBlock(); isa = llvm::ConstantExpr::getBitCast(blockISA, VoidPtrTy); // Build the block descriptor. descriptor = buildBlockDescriptor(CGM, blockInfo); // Compute the initial on-stack block flags. flags = BLOCK_HAS_SIGNATURE; if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; if (blockInfo.needsCopyDisposeHelpers()) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; if (blockInfo.getBlockDecl()->doesNotEscape()) flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL; } auto projectField = [&](unsigned index, CharUnits offset, const Twine &name) -> Address { return Builder.CreateStructGEP(blockAddr, index, offset, name); }; auto storeField = [&](llvm::Value *value, unsigned index, CharUnits offset, const Twine &name) { Builder.CreateStore(value, projectField(index, offset, name)); }; // Initialize the block header. { // We assume all the header fields are densely packed. unsigned index = 0; CharUnits offset; auto addHeaderField = [&](llvm::Value *value, CharUnits size, const Twine &name) { storeField(value, index, offset, name); offset += size; index++; }; if (!IsOpenCL) { addHeaderField(isa, getPointerSize(), "block.isa"); addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()), getIntSize(), "block.flags"); addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(), "block.reserved"); } else { addHeaderField( llvm::ConstantInt::get(IntTy, blockInfo.BlockSize.getQuantity()), getIntSize(), "block.size"); addHeaderField( llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()), getIntSize(), "block.align"); } if (!IsOpenCL) { addHeaderField(llvm::ConstantExpr::getBitCast(InvokeFn, VoidPtrTy), getPointerSize(), "block.invoke"); addHeaderField(descriptor, getPointerSize(), "block.descriptor"); } else if (auto *Helper = CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) { addHeaderField( I.first, CharUnits::fromQuantity( CGM.getDataLayout().getTypeAllocSize(I.first->getType())), I.second); } } } // Finally, capture all the values into the block. const BlockDecl *blockDecl = blockInfo.getBlockDecl(); // First, 'this'. if (blockDecl->capturesCXXThis()) { Address addr = projectField(blockInfo.CXXThisIndex, blockInfo.CXXThisOffset, "block.captured-this.addr"); Builder.CreateStore(LoadCXXThis(), addr); } // Next, captured variables. for (const auto &CI : blockDecl->captures()) { const VarDecl *variable = CI.getVariable(); const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); // Ignore constant captures. if (capture.isConstant()) continue; QualType type = capture.fieldType(); // This will be a [[type]]*, except that a byref entry will just be // an i8**. Address blockField = projectField(capture.getIndex(), capture.getOffset(), "block.captured"); // Compute the address of the thing we're going to move into the // block literal. Address src = Address::invalid(); if (blockDecl->isConversionFromLambda()) { // The lambda capture in a lambda's conversion-to-block-pointer is // special; we'll simply emit it directly. src = Address::invalid(); } else if (CI.isByRef()) { if (BlockInfo && CI.isNested()) { // We need to use the capture from the enclosing block. const CGBlockInfo::Capture &enclosingCapture = BlockInfo->getCapture(variable); // This is a [[type]]*, except that a byref entry will just be an i8**. src = Builder.CreateStructGEP(LoadBlockStruct(), enclosingCapture.getIndex(), enclosingCapture.getOffset(), "block.capture.addr"); } else { auto I = LocalDeclMap.find(variable); assert(I != LocalDeclMap.end()); src = I->second; } } else { DeclRefExpr declRef(const_cast(variable), /*RefersToEnclosingVariableOrCapture*/ CI.isNested(), type.getNonReferenceType(), VK_LValue, SourceLocation()); src = EmitDeclRefLValue(&declRef).getAddress(); }; // For byrefs, we just write the pointer to the byref struct into // the block field. There's no need to chase the forwarding // pointer at this point, since we're building something that will // live a shorter life than the stack byref anyway. if (CI.isByRef()) { // Get a void* that points to the byref struct. llvm::Value *byrefPointer; if (CI.isNested()) byrefPointer = Builder.CreateLoad(src, "byref.capture"); else byrefPointer = Builder.CreateBitCast(src.getPointer(), VoidPtrTy); // Write that void* into the capture field. Builder.CreateStore(byrefPointer, blockField); // If we have a copy constructor, evaluate that into the block field. } else if (const Expr *copyExpr = CI.getCopyExpr()) { if (blockDecl->isConversionFromLambda()) { // If we have a lambda conversion, emit the expression // directly into the block instead. AggValueSlot Slot = AggValueSlot::forAddr(blockField, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap); EmitAggExpr(copyExpr, Slot); } else { EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr); } // If it's a reference variable, copy the reference into the block field. } else if (type->isReferenceType()) { Builder.CreateStore(src.getPointer(), blockField); // If type is const-qualified, copy the value into the block field. } else if (type.isConstQualified() && type.getObjCLifetime() == Qualifiers::OCL_Strong && CGM.getCodeGenOpts().OptimizationLevel != 0) { llvm::Value *value = Builder.CreateLoad(src, "captured"); Builder.CreateStore(value, blockField); // If this is an ARC __strong block-pointer variable, don't do a // block copy. // // TODO: this can be generalized into the normal initialization logic: // we should never need to do a block-copy when initializing a local // variable, because the local variable's lifetime should be strictly // contained within the stack block's. } else if (type.getObjCLifetime() == Qualifiers::OCL_Strong && type->isBlockPointerType()) { // Load the block and do a simple retain. llvm::Value *value = Builder.CreateLoad(src, "block.captured_block"); value = EmitARCRetainNonBlock(value); // Do a primitive store to the block field. Builder.CreateStore(value, blockField); // Otherwise, fake up a POD copy into the block field. } else { // Fake up a new variable so that EmitScalarInit doesn't think // we're referring to the variable in its own initializer. ImplicitParamDecl BlockFieldPseudoVar(getContext(), type, ImplicitParamDecl::Other); // We use one of these or the other depending on whether the // reference is nested. DeclRefExpr declRef(const_cast(variable), /*RefersToEnclosingVariableOrCapture*/ CI.isNested(), type, VK_LValue, SourceLocation()); ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, &declRef, VK_RValue); // FIXME: Pass a specific location for the expr init so that the store is // attributed to a reasonable location - otherwise it may be attributed to // locations of subexpressions in the initialization. EmitExprAsInit(&l2r, &BlockFieldPseudoVar, MakeAddrLValue(blockField, type, AlignmentSource::Decl), /*captured by init*/ false); } // Activate the cleanup if layout pushed one. if (!CI.isByRef()) { EHScopeStack::stable_iterator cleanup = capture.getCleanup(); if (cleanup.isValid()) ActivateCleanupBlock(cleanup, blockInfo.DominatingIP); } } // Cast to the converted block-pointer type, which happens (somewhat // unfortunately) to be a pointer to function type. llvm::Value *result = Builder.CreatePointerCast( blockAddr.getPointer(), ConvertType(blockInfo.getBlockExpr()->getType())); if (IsOpenCL) { CGM.getOpenCLRuntime().recordBlockInfo(blockInfo.BlockExpression, InvokeFn, result); } return result; } llvm::Type *CodeGenModule::getBlockDescriptorType() { if (BlockDescriptorType) return BlockDescriptorType; llvm::Type *UnsignedLongTy = getTypes().ConvertType(getContext().UnsignedLongTy); // struct __block_descriptor { // unsigned long reserved; // unsigned long block_size; // // // later, the following will be added // // struct { // void (*copyHelper)(); // void (*copyHelper)(); // } helpers; // !!! optional // // const char *signature; // the block signature // const char *layout; // reserved // }; BlockDescriptorType = llvm::StructType::create( "struct.__block_descriptor", UnsignedLongTy, UnsignedLongTy); // Now form a pointer to that. unsigned AddrSpace = 0; if (getLangOpts().OpenCL) AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_constant); BlockDescriptorType = llvm::PointerType::get(BlockDescriptorType, AddrSpace); return BlockDescriptorType; } llvm::Type *CodeGenModule::getGenericBlockLiteralType() { assert(!getLangOpts().OpenCL && "OpenCL does not need this"); if (GenericBlockLiteralType) return GenericBlockLiteralType; llvm::Type *BlockDescPtrTy = getBlockDescriptorType(); // struct __block_literal_generic { // void *__isa; // int __flags; // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; // }; GenericBlockLiteralType = llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy, IntTy, IntTy, VoidPtrTy, BlockDescPtrTy); return GenericBlockLiteralType; } RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { const BlockPointerType *BPT = E->getCallee()->getType()->getAs(); llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee()); llvm::Value *FuncPtr; if (!CGM.getLangOpts().OpenCL) { // Get a pointer to the generic block literal. llvm::Type *BlockLiteralTy = llvm::PointerType::get(CGM.getGenericBlockLiteralType(), 0); // Bitcast the callee to a block literal. BlockPtr = Builder.CreatePointerCast(BlockPtr, BlockLiteralTy, "block.literal"); // Get the function pointer from the literal. FuncPtr = Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, 3); } // Add the block literal. CallArgList Args; QualType VoidPtrQualTy = getContext().VoidPtrTy; llvm::Type *GenericVoidPtrTy = VoidPtrTy; if (getLangOpts().OpenCL) { GenericVoidPtrTy = CGM.getOpenCLRuntime().getGenericVoidPointerType(); VoidPtrQualTy = getContext().getPointerType(getContext().getAddrSpaceQualType( getContext().VoidTy, LangAS::opencl_generic)); } BlockPtr = Builder.CreatePointerCast(BlockPtr, GenericVoidPtrTy); Args.add(RValue::get(BlockPtr), VoidPtrQualTy); QualType FnType = BPT->getPointeeType(); // And the rest of the arguments. EmitCallArgs(Args, FnType->getAs(), E->arguments()); // Load the function. llvm::Value *Func; if (CGM.getLangOpts().OpenCL) Func = CGM.getOpenCLRuntime().getInvokeFunction(E->getCallee()); else Func = Builder.CreateAlignedLoad(FuncPtr, getPointerAlign()); const FunctionType *FuncTy = FnType->castAs(); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy); // Cast the function pointer to the right type. llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo); llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy); Func = Builder.CreatePointerCast(Func, BlockFTyPtr); // Prepare the callee. CGCallee Callee(CGCalleeInfo(), Func); // And call the block. return EmitCall(FnInfo, Callee, ReturnValue, Args); } Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable, bool isByRef) { assert(BlockInfo && "evaluating block ref without block information?"); const CGBlockInfo::Capture &capture = BlockInfo->getCapture(variable); // Handle constant captures. if (capture.isConstant()) return LocalDeclMap.find(variable)->second; Address addr = Builder.CreateStructGEP(LoadBlockStruct(), capture.getIndex(), capture.getOffset(), "block.capture.addr"); if (isByRef) { // addr should be a void** right now. Load, then cast the result // to byref*. auto &byrefInfo = getBlockByrefInfo(variable); addr = Address(Builder.CreateLoad(addr), byrefInfo.ByrefAlignment); auto byrefPointerType = llvm::PointerType::get(byrefInfo.Type, 0); addr = Builder.CreateBitCast(addr, byrefPointerType, "byref.addr"); addr = emitBlockByrefAddress(addr, byrefInfo, /*follow*/ true, variable->getName()); } if (capture.fieldType()->isReferenceType()) addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType())); return addr; } void CodeGenModule::setAddrOfGlobalBlock(const BlockExpr *BE, llvm::Constant *Addr) { bool Ok = EmittedGlobalBlocks.insert(std::make_pair(BE, Addr)).second; (void)Ok; assert(Ok && "Trying to replace an already-existing global block!"); } llvm::Constant * CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE, StringRef Name) { if (llvm::Constant *Block = getAddrOfGlobalBlockIfEmitted(BE)) return Block; CGBlockInfo blockInfo(BE->getBlockDecl(), Name); blockInfo.BlockExpression = BE; // Compute information about the layout, etc., of this block. computeBlockInfo(*this, nullptr, blockInfo); // Using that metadata, generate the actual block function. { CodeGenFunction::DeclMapTy LocalDeclMap; CodeGenFunction(*this).GenerateBlockFunction( GlobalDecl(), blockInfo, LocalDeclMap, /*IsLambdaConversionToBlock*/ false, /*BuildGlobalBlock*/ true); } return getAddrOfGlobalBlockIfEmitted(BE); } static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, const CGBlockInfo &blockInfo, llvm::Constant *blockFn) { assert(blockInfo.CanBeGlobal); // Callers should detect this case on their own: calling this function // generally requires computing layout information, which is a waste of time // if we've already emitted this block. assert(!CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression) && "Refusing to re-emit a global block."); // Generate the constants for the block literal initializer. ConstantInitBuilder builder(CGM); auto fields = builder.beginStruct(); bool IsOpenCL = CGM.getLangOpts().OpenCL; + bool IsWindows = CGM.getTarget().getTriple().isOSWindows(); if (!IsOpenCL) { // isa - fields.add(CGM.getNSConcreteGlobalBlock()); + if (IsWindows) + fields.addNullPointer(CGM.Int8PtrPtrTy); + else + fields.add(CGM.getNSConcreteGlobalBlock()); // __flags BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; fields.addInt(CGM.IntTy, flags.getBitMask()); // Reserved fields.addInt(CGM.IntTy, 0); // Function fields.add(blockFn); } else { fields.addInt(CGM.IntTy, blockInfo.BlockSize.getQuantity()); fields.addInt(CGM.IntTy, blockInfo.BlockAlign.getQuantity()); } if (!IsOpenCL) { // Descriptor fields.add(buildBlockDescriptor(CGM, blockInfo)); } else if (auto *Helper = CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) { for (auto I : Helper->getCustomFieldValues(CGM, blockInfo)) { fields.add(I); } } unsigned AddrSpace = 0; if (CGM.getContext().getLangOpts().OpenCL) AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); llvm::Constant *literal = fields.finishAndCreateGlobal( "__block_literal_global", blockInfo.BlockAlign, - /*constant*/ true, llvm::GlobalVariable::InternalLinkage, AddrSpace); + /*constant*/ !IsWindows, llvm::GlobalVariable::InternalLinkage, AddrSpace); + + // Windows does not allow globals to be initialised to point to globals in + // different DLLs. Any such variables must run code to initialise them. + if (IsWindows) { + auto *Init = llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, + {}), llvm::GlobalValue::InternalLinkage, ".block_isa_init", + &CGM.getModule()); + llvm::IRBuilder<> b(llvm::BasicBlock::Create(CGM.getLLVMContext(), "entry", + Init)); + b.CreateAlignedStore(CGM.getNSConcreteGlobalBlock(), + b.CreateStructGEP(literal, 0), CGM.getPointerAlign().getQuantity()); + b.CreateRetVoid(); + // We can't use the normal LLVM global initialisation array, because we + // need to specify that this runs early in library initialisation. + auto *InitVar = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*isConstant*/true, llvm::GlobalValue::InternalLinkage, + Init, ".block_isa_init_ptr"); + InitVar->setSection(".CRT$XCLa"); + CGM.addUsedGlobal(InitVar); + } // Return a constant of the appropriately-casted type. llvm::Type *RequiredType = CGM.getTypes().ConvertType(blockInfo.getBlockExpr()->getType()); llvm::Constant *Result = llvm::ConstantExpr::getPointerCast(literal, RequiredType); CGM.setAddrOfGlobalBlock(blockInfo.BlockExpression, Result); if (CGM.getContext().getLangOpts().OpenCL) CGM.getOpenCLRuntime().recordBlockInfo( blockInfo.BlockExpression, cast(blockFn->stripPointerCasts()), Result); return Result; } void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D, unsigned argNum, llvm::Value *arg) { assert(BlockInfo && "not emitting prologue of block invocation function?!"); // Allocate a stack slot like for any local variable to guarantee optimal // debug info at -O0. The mem2reg pass will eliminate it when optimizing. Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); Builder.CreateStore(arg, alloc); if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockLiteralArgVariable( *BlockInfo, D->getName(), argNum, cast(alloc.getPointer()), Builder); } } SourceLocation StartLoc = BlockInfo->getBlockExpr()->getBody()->getLocStart(); ApplyDebugLocation Scope(*this, StartLoc); // Instead of messing around with LocalDeclMap, just set the value // directly as BlockPointer. BlockPointer = Builder.CreatePointerCast( arg, BlockInfo->StructureType->getPointerTo( getContext().getLangOpts().OpenCL ? getContext().getTargetAddressSpace(LangAS::opencl_generic) : 0), "block"); } Address CodeGenFunction::LoadBlockStruct() { assert(BlockInfo && "not in a block invocation function!"); assert(BlockPointer && "no block pointer set!"); return Address(BlockPointer, BlockInfo->BlockAlign); } llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &blockInfo, const DeclMapTy &ldm, bool IsLambdaConversionToBlock, bool BuildGlobalBlock) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); CurGD = GD; CurEHLocation = blockInfo.getBlockExpr()->getLocEnd(); BlockInfo = &blockInfo; // Arrange for local static and local extern declarations to appear // to be local to this function as well, in case they're directly // referenced in a block. for (DeclMapTy::const_iterator i = ldm.begin(), e = ldm.end(); i != e; ++i) { const auto *var = dyn_cast(i->first); if (var && !var->hasLocalStorage()) setAddrOfLocalVar(var, i->second); } // Begin building the function declaration. // Build the argument list. FunctionArgList args; // The first argument is the block pointer. Just take it as a void* // and cast it later. QualType selfTy = getContext().VoidPtrTy; // For OpenCL passed block pointer can be private AS local variable or // global AS program scope variable (for the case with and without captures). // Generic AS is used therefore to be able to accommodate both private and // generic AS in one implementation. if (getLangOpts().OpenCL) selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType( getContext().VoidTy, LangAS::opencl_generic)); IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); ImplicitParamDecl SelfDecl(getContext(), const_cast(blockDecl), SourceLocation(), II, selfTy, ImplicitParamDecl::ObjCSelf); args.push_back(&SelfDecl); // Now add the rest of the parameters. args.append(blockDecl->param_begin(), blockDecl->param_end()); // Create the function declaration. const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType(); const CGFunctionInfo &fnInfo = CGM.getTypes().arrangeBlockFunctionDeclaration(fnType, args); if (CGM.ReturnSlotInterferesWithArgs(fnInfo)) blockInfo.UsesStret = true; llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo); StringRef name = CGM.getBlockMangledName(GD, blockDecl); llvm::Function *fn = llvm::Function::Create( fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule()); CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo); if (BuildGlobalBlock) { auto GenVoidPtrTy = getContext().getLangOpts().OpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy; buildGlobalBlock(CGM, blockInfo, llvm::ConstantExpr::getPointerCast(fn, GenVoidPtrTy)); } // Begin generating the function. StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args, blockDecl->getLocation(), blockInfo.getBlockExpr()->getBody()->getLocStart()); // Okay. Undo some of what StartFunction did. // At -O0 we generate an explicit alloca for the BlockPointer, so the RA // won't delete the dbg.declare intrinsics for captured variables. llvm::Value *BlockPointerDbgLoc = BlockPointer; if (CGM.getCodeGenOpts().OptimizationLevel == 0) { // Allocate a stack slot for it, so we can point the debugger to it Address Alloca = CreateTempAlloca(BlockPointer->getType(), getPointerAlign(), "block.addr"); // Set the DebugLocation to empty, so the store is recognized as a // frame setup instruction by llvm::DwarfDebug::beginFunction(). auto NL = ApplyDebugLocation::CreateEmpty(*this); Builder.CreateStore(BlockPointer, Alloca); BlockPointerDbgLoc = Alloca.getPointer(); } // If we have a C++ 'this' reference, go ahead and force it into // existence now. if (blockDecl->capturesCXXThis()) { Address addr = Builder.CreateStructGEP(LoadBlockStruct(), blockInfo.CXXThisIndex, blockInfo.CXXThisOffset, "block.captured-this"); CXXThisValue = Builder.CreateLoad(addr, "this"); } // Also force all the constant captures. for (const auto &CI : blockDecl->captures()) { const VarDecl *variable = CI.getVariable(); const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (!capture.isConstant()) continue; CharUnits align = getContext().getDeclAlign(variable); Address alloca = CreateMemTemp(variable->getType(), align, "block.captured-const"); Builder.CreateStore(capture.getConstant(), alloca); setAddrOfLocalVar(variable, alloca); } // Save a spot to insert the debug information for all the DeclRefExprs. llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); --entry_ptr; if (IsLambdaConversionToBlock) EmitLambdaBlockInvokeBody(); else { PGO.assignRegionCounters(GlobalDecl(blockDecl), fn); incrementProfileCounter(blockDecl->getBody()); EmitStmt(blockDecl->getBody()); } // Remember where we were... llvm::BasicBlock *resume = Builder.GetInsertBlock(); // Go back to the entry. ++entry_ptr; Builder.SetInsertPoint(entry, entry_ptr); // Emit debug information for all the DeclRefExprs. // FIXME: also for 'this' if (CGDebugInfo *DI = getDebugInfo()) { for (const auto &CI : blockDecl->captures()) { const VarDecl *variable = CI.getVariable(); DI->EmitLocation(Builder, variable->getLocation()); if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { auto addr = LocalDeclMap.find(variable)->second; (void)DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(), Builder); continue; } DI->EmitDeclareOfBlockDeclRefVariable( variable, BlockPointerDbgLoc, Builder, blockInfo, entry_ptr == entry->end() ? nullptr : &*entry_ptr); } } // Recover location if it was changed in the above loop. DI->EmitLocation(Builder, cast(blockDecl->getBody())->getRBracLoc()); } // And resume where we left off. if (resume == nullptr) Builder.ClearInsertionPoint(); else Builder.SetInsertPoint(resume); FinishFunction(cast(blockDecl->getBody())->getRBracLoc()); return fn; } namespace { /// Represents a type of copy/destroy operation that should be performed for an /// entity that's captured by a block. enum class BlockCaptureEntityKind { CXXRecord, // Copy or destroy ARCWeak, ARCStrong, NonTrivialCStruct, BlockObject, // Assign or release None }; /// Represents a captured entity that requires extra operations in order for /// this entity to be copied or destroyed correctly. struct BlockCaptureManagedEntity { BlockCaptureEntityKind Kind; BlockFieldFlags Flags; const BlockDecl::Capture &CI; const CGBlockInfo::Capture &Capture; BlockCaptureManagedEntity(BlockCaptureEntityKind Type, BlockFieldFlags Flags, const BlockDecl::Capture &CI, const CGBlockInfo::Capture &Capture) : Kind(Type), Flags(Flags), CI(CI), Capture(Capture) {} }; } // end anonymous namespace static std::pair computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, const LangOptions &LangOpts) { if (CI.getCopyExpr()) { assert(!CI.isByRef()); // don't bother computing flags return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags()); } BlockFieldFlags Flags; if (CI.isByRef()) { Flags = BLOCK_FIELD_IS_BYREF; if (T.isObjCGCWeak()) Flags |= BLOCK_FIELD_IS_WEAK; return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); } Flags = BLOCK_FIELD_IS_OBJECT; bool isBlockPointer = T->isBlockPointerType(); if (isBlockPointer) Flags = BLOCK_FIELD_IS_BLOCK; switch (T.isNonTrivialToPrimitiveCopy()) { case QualType::PCK_Struct: return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct, BlockFieldFlags()); case QualType::PCK_ARCWeak: // We need to register __weak direct captures with the runtime. return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags); case QualType::PCK_ARCStrong: // We need to retain the copied value for __strong direct captures. // If it's a block pointer, we have to copy the block and assign that to // the destination pointer, so we might as well use _Block_object_assign. // Otherwise we can avoid that. return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong : BlockCaptureEntityKind::BlockObject, Flags); case QualType::PCK_Trivial: case QualType::PCK_VolatileTrivial: { if (!T->isObjCRetainableType()) // For all other types, the memcpy is fine. return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); // Special rules for ARC captures: Qualifiers QS = T.getQualifiers(); // Non-ARC captures of retainable pointers are strong and // therefore require a call to _Block_object_assign. if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount) return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); // Otherwise the memcpy is fine. return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); } } llvm_unreachable("after exhaustive PrimitiveCopyKind switch"); } /// Find the set of block captures that need to be explicitly copied or destroy. static void findBlockCapturedManagedEntities( const CGBlockInfo &BlockInfo, const LangOptions &LangOpts, SmallVectorImpl &ManagedCaptures, llvm::function_ref( const BlockDecl::Capture &, QualType, const LangOptions &)> Predicate) { for (const auto &CI : BlockInfo.getBlockDecl()->captures()) { const VarDecl *Variable = CI.getVariable(); const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable); if (Capture.isConstant()) continue; auto Info = Predicate(CI, Variable->getType(), LangOpts); if (Info.first != BlockCaptureEntityKind::None) ManagedCaptures.emplace_back(Info.first, Info.second, CI, Capture); } } namespace { /// Release a __block variable. struct CallBlockRelease final : EHScopeStack::Cleanup { Address Addr; BlockFieldFlags FieldFlags; bool LoadBlockVarAddr; CallBlockRelease(Address Addr, BlockFieldFlags Flags, bool LoadValue) : Addr(Addr), FieldFlags(Flags), LoadBlockVarAddr(LoadValue) {} void Emit(CodeGenFunction &CGF, Flags flags) override { llvm::Value *BlockVarAddr; if (LoadBlockVarAddr) { BlockVarAddr = CGF.Builder.CreateLoad(Addr); BlockVarAddr = CGF.Builder.CreateBitCast(BlockVarAddr, CGF.VoidPtrTy); } else { BlockVarAddr = Addr.getPointer(); } CGF.BuildBlockRelease(BlockVarAddr, FieldFlags); } }; } // end anonymous namespace static void pushCaptureCleanup(BlockCaptureEntityKind CaptureKind, Address Field, QualType CaptureType, BlockFieldFlags Flags, bool EHOnly, CodeGenFunction &CGF) { switch (CaptureKind) { case BlockCaptureEntityKind::CXXRecord: case BlockCaptureEntityKind::ARCWeak: case BlockCaptureEntityKind::NonTrivialCStruct: case BlockCaptureEntityKind::ARCStrong: { if (CaptureType.isDestructedType() && (!EHOnly || CGF.needsEHCleanup(CaptureType.isDestructedType()))) { CodeGenFunction::Destroyer *Destroyer = CaptureKind == BlockCaptureEntityKind::ARCStrong ? CodeGenFunction::destroyARCStrongImprecise : CGF.getDestroyer(CaptureType.isDestructedType()); CleanupKind Kind = EHOnly ? EHCleanup : CGF.getCleanupKind(CaptureType.isDestructedType()); CGF.pushDestroy(Kind, Field, CaptureType, Destroyer, Kind & EHCleanup); } break; } case BlockCaptureEntityKind::BlockObject: { if (!EHOnly || CGF.getLangOpts().Exceptions) { CleanupKind Kind = EHOnly ? EHCleanup : NormalAndEHCleanup; CGF.enterByrefCleanup(Kind, Field, Flags, /*LoadBlockVarAddr*/ true); } break; } case BlockCaptureEntityKind::None: llvm_unreachable("unexpected BlockCaptureEntityKind"); } } /// Generate the copy-helper function for a block closure object: /// static void block_copy_helper(block_t *dst, block_t *src); /// The runtime will have previously initialized 'dst' by doing a /// bit-copy of 'src'. /// /// Note that this copies an entire block closure object to the heap; /// it should not be confused with a 'byref copy helper', which moves /// the contents of an individual __block variable to the heap. llvm::Constant * CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { ASTContext &C = getContext(); FunctionArgList args; ImplicitParamDecl DstDecl(getContext(), C.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&DstDecl); ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&SrcDecl); const CGFunctionInfo &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args); // FIXME: it would be nice if these were mergeable with things with // identical semantics. llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__copy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_block_"); FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, C.VoidTy, nullptr, SC_Static, false, false); CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); StartFunction(FD, C.VoidTy, Fn, FI, args); ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); Address src = GetAddrOfLocalVar(&SrcDecl); src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign); src = Builder.CreateBitCast(src, structPtrTy, "block.source"); Address dst = GetAddrOfLocalVar(&DstDecl); dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign); dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest"); SmallVector CopiedCaptures; findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures, computeCopyInfoForBlockCapture); for (const auto &CopiedCapture : CopiedCaptures) { const BlockDecl::Capture &CI = CopiedCapture.CI; const CGBlockInfo::Capture &capture = CopiedCapture.Capture; QualType captureType = CI.getVariable()->getType(); BlockFieldFlags flags = CopiedCapture.Flags; unsigned index = capture.getIndex(); Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset()); Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset()); // If there's an explicit copy expression, we do that. if (CI.getCopyExpr()) { assert(CopiedCapture.Kind == BlockCaptureEntityKind::CXXRecord); EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr()); } else if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCWeak) { EmitARCCopyWeak(dstField, srcField); // If this is a C struct that requires non-trivial copy construction, emit a // call to its copy constructor. } else if (CopiedCapture.Kind == BlockCaptureEntityKind::NonTrivialCStruct) { QualType varType = CI.getVariable()->getType(); callCStructCopyConstructor(MakeAddrLValue(dstField, varType), MakeAddrLValue(srcField, varType)); } else { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCStrong) { // At -O0, store null into the destination field (so that the // storeStrong doesn't over-release) and then call storeStrong. // This is a workaround to not having an initStrong call. if (CGM.getCodeGenOpts().OptimizationLevel == 0) { auto *ty = cast(srcValue->getType()); llvm::Value *null = llvm::ConstantPointerNull::get(ty); Builder.CreateStore(null, dstField); EmitARCStoreStrongCall(dstField, srcValue, true); // With optimization enabled, take advantage of the fact that // the blocks runtime guarantees a memcpy of the block data, and // just emit a retain of the src field. } else { EmitARCRetainNonBlock(srcValue); // Unless EH cleanup is required, we don't need this anymore, so kill // it. It's not quite worth the annoyance to avoid creating it in the // first place. if (!needsEHCleanup(captureType.isDestructedType())) cast(dstField.getPointer())->eraseFromParent(); } } else { assert(CopiedCapture.Kind == BlockCaptureEntityKind::BlockObject); srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); llvm::Value *dstAddr = Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy); llvm::Value *args[] = { dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask()) }; const VarDecl *variable = CI.getVariable(); bool copyCanThrow = false; if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) { const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(variable); if (copyExpr) { copyCanThrow = true; // FIXME: reuse the noexcept logic } } if (copyCanThrow) { EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args); } else { EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args); } } } // Ensure that we destroy the copied object if an exception is thrown later // in the helper function. pushCaptureCleanup(CopiedCapture.Kind, dstField, captureType, flags, /*EHOnly*/ true, *this); } FinishFunction(); return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); } static BlockFieldFlags getBlockFieldFlagsForObjCObjectPointer(const BlockDecl::Capture &CI, QualType T) { BlockFieldFlags Flags = BLOCK_FIELD_IS_OBJECT; if (T->isBlockPointerType()) Flags = BLOCK_FIELD_IS_BLOCK; return Flags; } static std::pair computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T, const LangOptions &LangOpts) { if (CI.isByRef()) { BlockFieldFlags Flags = BLOCK_FIELD_IS_BYREF; if (T.isObjCGCWeak()) Flags |= BLOCK_FIELD_IS_WEAK; return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags); } switch (T.isDestructedType()) { case QualType::DK_cxx_destructor: return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags()); case QualType::DK_objc_strong_lifetime: // Use objc_storeStrong for __strong direct captures; the // dynamic tools really like it when we do this. return std::make_pair(BlockCaptureEntityKind::ARCStrong, getBlockFieldFlagsForObjCObjectPointer(CI, T)); case QualType::DK_objc_weak_lifetime: // Support __weak direct captures. return std::make_pair(BlockCaptureEntityKind::ARCWeak, getBlockFieldFlagsForObjCObjectPointer(CI, T)); case QualType::DK_nontrivial_c_struct: return std::make_pair(BlockCaptureEntityKind::NonTrivialCStruct, BlockFieldFlags()); case QualType::DK_none: { // Non-ARC captures are strong, and we need to use _Block_object_dispose. if (T->isObjCRetainableType() && !T.getQualifiers().hasObjCLifetime() && !LangOpts.ObjCAutoRefCount) return std::make_pair(BlockCaptureEntityKind::BlockObject, getBlockFieldFlagsForObjCObjectPointer(CI, T)); // Otherwise, we have nothing to do. return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags()); } } llvm_unreachable("after exhaustive DestructionKind switch"); } /// Generate the destroy-helper function for a block closure object: /// static void block_destroy_helper(block_t *theBlock); /// /// Note that this destroys a heap-allocated block closure object; /// it should not be confused with a 'byref destroy helper', which /// destroys the heap-allocated contents of an individual __block /// variable. llvm::Constant * CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { ASTContext &C = getContext(); FunctionArgList args; ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&SrcDecl); const CGFunctionInfo &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__destroy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__destroy_helper_block_"); FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, C.VoidTy, nullptr, SC_Static, false, false); CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); StartFunction(FD, C.VoidTy, Fn, FI, args); ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()}; llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); Address src = GetAddrOfLocalVar(&SrcDecl); src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign); src = Builder.CreateBitCast(src, structPtrTy, "block"); CodeGenFunction::RunCleanupsScope cleanups(*this); SmallVector DestroyedCaptures; findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures, computeDestroyInfoForBlockCapture); for (const auto &DestroyedCapture : DestroyedCaptures) { const BlockDecl::Capture &CI = DestroyedCapture.CI; const CGBlockInfo::Capture &capture = DestroyedCapture.Capture; BlockFieldFlags flags = DestroyedCapture.Flags; Address srcField = Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset()); pushCaptureCleanup(DestroyedCapture.Kind, srcField, CI.getVariable()->getType(), flags, /*EHOnly*/ false, *this); } cleanups.ForceCleanup(); FinishFunction(); return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); } namespace { /// Emits the copy/dispose helper functions for a __block object of id type. class ObjectByrefHelpers final : public BlockByrefHelpers { BlockFieldFlags Flags; public: ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags) : BlockByrefHelpers(alignment), Flags(flags) {} void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy); srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy); llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField); unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask(); llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags); llvm::Value *fn = CGF.CGM.getBlockObjectAssign(); llvm::Value *args[] = { destField.getPointer(), srcValue, flagsVal }; CGF.EmitNounwindRuntimeCall(fn, args); } void emitDispose(CodeGenFunction &CGF, Address field) override { field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0)); llvm::Value *value = CGF.Builder.CreateLoad(field); CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER); } void profileImpl(llvm::FoldingSetNodeID &id) const override { id.AddInteger(Flags.getBitMask()); } }; /// Emits the copy/dispose helpers for an ARC __block __weak variable. class ARCWeakByrefHelpers final : public BlockByrefHelpers { public: ARCWeakByrefHelpers(CharUnits alignment) : BlockByrefHelpers(alignment) {} void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { CGF.EmitARCMoveWeak(destField, srcField); } void emitDispose(CodeGenFunction &CGF, Address field) override { CGF.EmitARCDestroyWeak(field); } void profileImpl(llvm::FoldingSetNodeID &id) const override { // 0 is distinguishable from all pointers and byref flags id.AddInteger(0); } }; /// Emits the copy/dispose helpers for an ARC __block __strong variable /// that's not of block-pointer type. class ARCStrongByrefHelpers final : public BlockByrefHelpers { public: ARCStrongByrefHelpers(CharUnits alignment) : BlockByrefHelpers(alignment) {} void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { // Do a "move" by copying the value and then zeroing out the old // variable. llvm::Value *value = CGF.Builder.CreateLoad(srcField); llvm::Value *null = llvm::ConstantPointerNull::get(cast(value->getType())); if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) { CGF.Builder.CreateStore(null, destField); CGF.EmitARCStoreStrongCall(destField, value, /*ignored*/ true); CGF.EmitARCStoreStrongCall(srcField, null, /*ignored*/ true); return; } CGF.Builder.CreateStore(value, destField); CGF.Builder.CreateStore(null, srcField); } void emitDispose(CodeGenFunction &CGF, Address field) override { CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime); } void profileImpl(llvm::FoldingSetNodeID &id) const override { // 1 is distinguishable from all pointers and byref flags id.AddInteger(1); } }; /// Emits the copy/dispose helpers for an ARC __block __strong /// variable that's of block-pointer type. class ARCStrongBlockByrefHelpers final : public BlockByrefHelpers { public: ARCStrongBlockByrefHelpers(CharUnits alignment) : BlockByrefHelpers(alignment) {} void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { // Do the copy with objc_retainBlock; that's all that // _Block_object_assign would do anyway, and we'd have to pass the // right arguments to make sure it doesn't get no-op'ed. llvm::Value *oldValue = CGF.Builder.CreateLoad(srcField); llvm::Value *copy = CGF.EmitARCRetainBlock(oldValue, /*mandatory*/ true); CGF.Builder.CreateStore(copy, destField); } void emitDispose(CodeGenFunction &CGF, Address field) override { CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime); } void profileImpl(llvm::FoldingSetNodeID &id) const override { // 2 is distinguishable from all pointers and byref flags id.AddInteger(2); } }; /// Emits the copy/dispose helpers for a __block variable with a /// nontrivial copy constructor or destructor. class CXXByrefHelpers final : public BlockByrefHelpers { QualType VarType; const Expr *CopyExpr; public: CXXByrefHelpers(CharUnits alignment, QualType type, const Expr *copyExpr) : BlockByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {} bool needsCopy() const override { return CopyExpr != nullptr; } void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { if (!CopyExpr) return; CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr); } void emitDispose(CodeGenFunction &CGF, Address field) override { EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin(); CGF.PushDestructorCleanup(VarType, field); CGF.PopCleanupBlocks(cleanupDepth); } void profileImpl(llvm::FoldingSetNodeID &id) const override { id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr()); } }; /// Emits the copy/dispose helpers for a __block variable that is a non-trivial /// C struct. class NonTrivialCStructByrefHelpers final : public BlockByrefHelpers { QualType VarType; public: NonTrivialCStructByrefHelpers(CharUnits alignment, QualType type) : BlockByrefHelpers(alignment), VarType(type) {} void emitCopy(CodeGenFunction &CGF, Address destField, Address srcField) override { CGF.callCStructMoveConstructor(CGF.MakeAddrLValue(destField, VarType), CGF.MakeAddrLValue(srcField, VarType)); } bool needsDispose() const override { return VarType.isDestructedType(); } void emitDispose(CodeGenFunction &CGF, Address field) override { EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin(); CGF.pushDestroy(VarType.isDestructedType(), field, VarType); CGF.PopCleanupBlocks(cleanupDepth); } void profileImpl(llvm::FoldingSetNodeID &id) const override { id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr()); } }; } // end anonymous namespace static llvm::Constant * generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo, BlockByrefHelpers &generator) { ASTContext &Context = CGF.getContext(); QualType R = Context.VoidTy; FunctionArgList args; ImplicitParamDecl Dst(CGF.getContext(), Context.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&Dst); ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&Src); const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args); llvm::FunctionType *LTy = CGF.CGM.getTypes().GetFunctionType(FI); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__Block_byref_object_copy_", &CGF.CGM.getModule()); IdentifierInfo *II = &Context.Idents.get("__Block_byref_object_copy_"); FunctionDecl *FD = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, R, nullptr, SC_Static, false, false); CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); CGF.StartFunction(FD, R, Fn, FI, args); if (generator.needsCopy()) { llvm::Type *byrefPtrType = byrefInfo.Type->getPointerTo(0); // dst->x Address destField = CGF.GetAddrOfLocalVar(&Dst); destField = Address(CGF.Builder.CreateLoad(destField), byrefInfo.ByrefAlignment); destField = CGF.Builder.CreateBitCast(destField, byrefPtrType); destField = CGF.emitBlockByrefAddress(destField, byrefInfo, false, "dest-object"); // src->x Address srcField = CGF.GetAddrOfLocalVar(&Src); srcField = Address(CGF.Builder.CreateLoad(srcField), byrefInfo.ByrefAlignment); srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType); srcField = CGF.emitBlockByrefAddress(srcField, byrefInfo, false, "src-object"); generator.emitCopy(CGF, destField, srcField); } CGF.FinishFunction(); return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy); } /// Build the copy helper for a __block variable. static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM, const BlockByrefInfo &byrefInfo, BlockByrefHelpers &generator) { CodeGenFunction CGF(CGM); return generateByrefCopyHelper(CGF, byrefInfo, generator); } /// Generate code for a __block variable's dispose helper. static llvm::Constant * generateByrefDisposeHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo, BlockByrefHelpers &generator) { ASTContext &Context = CGF.getContext(); QualType R = Context.VoidTy; FunctionArgList args; ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy, ImplicitParamDecl::Other); args.push_back(&Src); const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args); llvm::FunctionType *LTy = CGF.CGM.getTypes().GetFunctionType(FI); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__Block_byref_object_dispose_", &CGF.CGM.getModule()); IdentifierInfo *II = &Context.Idents.get("__Block_byref_object_dispose_"); FunctionDecl *FD = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, R, nullptr, SC_Static, false, false); CGF.CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); CGF.StartFunction(FD, R, Fn, FI, args); if (generator.needsDispose()) { Address addr = CGF.GetAddrOfLocalVar(&Src); addr = Address(CGF.Builder.CreateLoad(addr), byrefInfo.ByrefAlignment); auto byrefPtrType = byrefInfo.Type->getPointerTo(0); addr = CGF.Builder.CreateBitCast(addr, byrefPtrType); addr = CGF.emitBlockByrefAddress(addr, byrefInfo, false, "object"); generator.emitDispose(CGF, addr); } CGF.FinishFunction(); return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy); } /// Build the dispose helper for a __block variable. static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM, const BlockByrefInfo &byrefInfo, BlockByrefHelpers &generator) { CodeGenFunction CGF(CGM); return generateByrefDisposeHelper(CGF, byrefInfo, generator); } /// Lazily build the copy and dispose helpers for a __block variable /// with the given information. template static T *buildByrefHelpers(CodeGenModule &CGM, const BlockByrefInfo &byrefInfo, T &&generator) { llvm::FoldingSetNodeID id; generator.Profile(id); void *insertPos; BlockByrefHelpers *node = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos); if (node) return static_cast(node); generator.CopyHelper = buildByrefCopyHelper(CGM, byrefInfo, generator); generator.DisposeHelper = buildByrefDisposeHelper(CGM, byrefInfo, generator); T *copy = new (CGM.getContext()) T(std::forward(generator)); CGM.ByrefHelpersCache.InsertNode(copy, insertPos); return copy; } /// Build the copy and dispose helpers for the given __block variable /// emission. Places the helpers in the global cache. Returns null /// if no helpers are required. BlockByrefHelpers * CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, const AutoVarEmission &emission) { const VarDecl &var = *emission.Variable; QualType type = var.getType(); auto &byrefInfo = getBlockByrefInfo(&var); // The alignment we care about for the purposes of uniquing byref // helpers is the alignment of the actual byref value field. CharUnits valueAlignment = byrefInfo.ByrefAlignment.alignmentAtOffset(byrefInfo.FieldOffset); if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) { const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var); if (!copyExpr && record->hasTrivialDestructor()) return nullptr; return ::buildByrefHelpers( CGM, byrefInfo, CXXByrefHelpers(valueAlignment, type, copyExpr)); } // If type is a non-trivial C struct type that is non-trivial to // destructly move or destroy, build the copy and dispose helpers. if (type.isNonTrivialToPrimitiveDestructiveMove() == QualType::PCK_Struct || type.isDestructedType() == QualType::DK_nontrivial_c_struct) return ::buildByrefHelpers( CGM, byrefInfo, NonTrivialCStructByrefHelpers(valueAlignment, type)); // Otherwise, if we don't have a retainable type, there's nothing to do. // that the runtime does extra copies. if (!type->isObjCRetainableType()) return nullptr; Qualifiers qs = type.getQualifiers(); // If we have lifetime, that dominates. if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { switch (lifetime) { case Qualifiers::OCL_None: llvm_unreachable("impossible"); // These are just bits as far as the runtime is concerned. case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: return nullptr; // Tell the runtime that this is ARC __weak, called by the // byref routines. case Qualifiers::OCL_Weak: return ::buildByrefHelpers(CGM, byrefInfo, ARCWeakByrefHelpers(valueAlignment)); // ARC __strong __block variables need to be retained. case Qualifiers::OCL_Strong: // Block pointers need to be copied, and there's no direct // transfer possible. if (type->isBlockPointerType()) { return ::buildByrefHelpers(CGM, byrefInfo, ARCStrongBlockByrefHelpers(valueAlignment)); // Otherwise, we transfer ownership of the retain from the stack // to the heap. } else { return ::buildByrefHelpers(CGM, byrefInfo, ARCStrongByrefHelpers(valueAlignment)); } } llvm_unreachable("fell out of lifetime switch!"); } BlockFieldFlags flags; if (type->isBlockPointerType()) { flags |= BLOCK_FIELD_IS_BLOCK; } else if (CGM.getContext().isObjCNSObjectType(type) || type->isObjCObjectPointerType()) { flags |= BLOCK_FIELD_IS_OBJECT; } else { return nullptr; } if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK; return ::buildByrefHelpers(CGM, byrefInfo, ObjectByrefHelpers(valueAlignment, flags)); } Address CodeGenFunction::emitBlockByrefAddress(Address baseAddr, const VarDecl *var, bool followForward) { auto &info = getBlockByrefInfo(var); return emitBlockByrefAddress(baseAddr, info, followForward, var->getName()); } Address CodeGenFunction::emitBlockByrefAddress(Address baseAddr, const BlockByrefInfo &info, bool followForward, const llvm::Twine &name) { // Chase the forwarding address if requested. if (followForward) { Address forwardingAddr = Builder.CreateStructGEP(baseAddr, 1, getPointerSize(), "forwarding"); baseAddr = Address(Builder.CreateLoad(forwardingAddr), info.ByrefAlignment); } return Builder.CreateStructGEP(baseAddr, info.FieldIndex, info.FieldOffset, name); } /// BuildByrefInfo - This routine changes a __block variable declared as T x /// into: /// /// struct { /// void *__isa; /// void *__forwarding; /// int32_t __flags; /// int32_t __size; /// void *__copy_helper; // only if needed /// void *__destroy_helper; // only if needed /// void *__byref_variable_layout;// only if needed /// char padding[X]; // only if needed /// T x; /// } x /// const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) { auto it = BlockByrefInfos.find(D); if (it != BlockByrefInfos.end()) return it->second; llvm::StructType *byrefType = llvm::StructType::create(getLLVMContext(), "struct.__block_byref_" + D->getNameAsString()); QualType Ty = D->getType(); CharUnits size; SmallVector types; // void *__isa; types.push_back(Int8PtrTy); size += getPointerSize(); // void *__forwarding; types.push_back(llvm::PointerType::getUnqual(byrefType)); size += getPointerSize(); // int32_t __flags; types.push_back(Int32Ty); size += CharUnits::fromQuantity(4); // int32_t __size; types.push_back(Int32Ty); size += CharUnits::fromQuantity(4); // Note that this must match *exactly* the logic in buildByrefHelpers. bool hasCopyAndDispose = getContext().BlockRequiresCopying(Ty, D); if (hasCopyAndDispose) { /// void *__copy_helper; types.push_back(Int8PtrTy); size += getPointerSize(); /// void *__destroy_helper; types.push_back(Int8PtrTy); size += getPointerSize(); } bool HasByrefExtendedLayout = false; Qualifiers::ObjCLifetime Lifetime; if (getContext().getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout) && HasByrefExtendedLayout) { /// void *__byref_variable_layout; types.push_back(Int8PtrTy); size += CharUnits::fromQuantity(PointerSizeInBytes); } // T x; llvm::Type *varTy = ConvertTypeForMem(Ty); bool packed = false; CharUnits varAlign = getContext().getDeclAlign(D); CharUnits varOffset = size.alignTo(varAlign); // We may have to insert padding. if (varOffset != size) { llvm::Type *paddingTy = llvm::ArrayType::get(Int8Ty, (varOffset - size).getQuantity()); types.push_back(paddingTy); size = varOffset; // Conversely, we might have to prevent LLVM from inserting padding. } else if (CGM.getDataLayout().getABITypeAlignment(varTy) > varAlign.getQuantity()) { packed = true; } types.push_back(varTy); byrefType->setBody(types, packed); BlockByrefInfo info; info.Type = byrefType; info.FieldIndex = types.size() - 1; info.FieldOffset = varOffset; info.ByrefAlignment = std::max(varAlign, getPointerAlign()); auto pair = BlockByrefInfos.insert({D, info}); assert(pair.second && "info was inserted recursively?"); return pair.first->second; } /// Initialize the structural components of a __block variable, i.e. /// everything but the actual object. void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { // Find the address of the local. Address addr = emission.Addr; // That's an alloca of the byref structure type. llvm::StructType *byrefType = cast( cast(addr.getPointer()->getType())->getElementType()); unsigned nextHeaderIndex = 0; CharUnits nextHeaderOffset; auto storeHeaderField = [&](llvm::Value *value, CharUnits fieldSize, const Twine &name) { auto fieldAddr = Builder.CreateStructGEP(addr, nextHeaderIndex, nextHeaderOffset, name); Builder.CreateStore(value, fieldAddr); nextHeaderIndex++; nextHeaderOffset += fieldSize; }; // Build the byref helpers if necessary. This is null if we don't need any. BlockByrefHelpers *helpers = buildByrefHelpers(*byrefType, emission); const VarDecl &D = *emission.Variable; QualType type = D.getType(); bool HasByrefExtendedLayout; Qualifiers::ObjCLifetime ByrefLifetime; bool ByRefHasLifetime = getContext().getByrefLifetime(type, ByrefLifetime, HasByrefExtendedLayout); llvm::Value *V; // Initialize the 'isa', which is just 0 or 1. int isa = 0; if (type.isObjCGCWeak()) isa = 1; V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa"); storeHeaderField(V, getPointerSize(), "byref.isa"); // Store the address of the variable into its own forwarding pointer. storeHeaderField(addr.getPointer(), getPointerSize(), "byref.forwarding"); // Blocks ABI: // c) the flags field is set to either 0 if no helper functions are // needed or BLOCK_BYREF_HAS_COPY_DISPOSE if they are, BlockFlags flags; if (helpers) flags |= BLOCK_BYREF_HAS_COPY_DISPOSE; if (ByRefHasLifetime) { if (HasByrefExtendedLayout) flags |= BLOCK_BYREF_LAYOUT_EXTENDED; else switch (ByrefLifetime) { case Qualifiers::OCL_Strong: flags |= BLOCK_BYREF_LAYOUT_STRONG; break; case Qualifiers::OCL_Weak: flags |= BLOCK_BYREF_LAYOUT_WEAK; break; case Qualifiers::OCL_ExplicitNone: flags |= BLOCK_BYREF_LAYOUT_UNRETAINED; break; case Qualifiers::OCL_None: if (!type->isObjCObjectPointerType() && !type->isBlockPointerType()) flags |= BLOCK_BYREF_LAYOUT_NON_OBJECT; break; default: break; } if (CGM.getLangOpts().ObjCGCBitmapPrint) { printf("\n Inline flag for BYREF variable layout (%d):", flags.getBitMask()); if (flags & BLOCK_BYREF_HAS_COPY_DISPOSE) printf(" BLOCK_BYREF_HAS_COPY_DISPOSE"); if (flags & BLOCK_BYREF_LAYOUT_MASK) { BlockFlags ThisFlag(flags.getBitMask() & BLOCK_BYREF_LAYOUT_MASK); if (ThisFlag == BLOCK_BYREF_LAYOUT_EXTENDED) printf(" BLOCK_BYREF_LAYOUT_EXTENDED"); if (ThisFlag == BLOCK_BYREF_LAYOUT_STRONG) printf(" BLOCK_BYREF_LAYOUT_STRONG"); if (ThisFlag == BLOCK_BYREF_LAYOUT_WEAK) printf(" BLOCK_BYREF_LAYOUT_WEAK"); if (ThisFlag == BLOCK_BYREF_LAYOUT_UNRETAINED) printf(" BLOCK_BYREF_LAYOUT_UNRETAINED"); if (ThisFlag == BLOCK_BYREF_LAYOUT_NON_OBJECT) printf(" BLOCK_BYREF_LAYOUT_NON_OBJECT"); } printf("\n"); } } storeHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()), getIntSize(), "byref.flags"); CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType); V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity()); storeHeaderField(V, getIntSize(), "byref.size"); if (helpers) { storeHeaderField(helpers->CopyHelper, getPointerSize(), "byref.copyHelper"); storeHeaderField(helpers->DisposeHelper, getPointerSize(), "byref.disposeHelper"); } if (ByRefHasLifetime && HasByrefExtendedLayout) { auto layoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type); storeHeaderField(layoutInfo, getPointerSize(), "byref.layout"); } } void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) { llvm::Value *F = CGM.getBlockObjectDispose(); llvm::Value *args[] = { Builder.CreateBitCast(V, Int8PtrTy), llvm::ConstantInt::get(Int32Ty, flags.getBitMask()) }; EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors? } void CodeGenFunction::enterByrefCleanup(CleanupKind Kind, Address Addr, BlockFieldFlags Flags, bool LoadBlockVarAddr) { EHStack.pushCleanup(Kind, Addr, Flags, LoadBlockVarAddr); } /// Adjust the declaration of something from the blocks API. static void configureBlocksRuntimeObject(CodeGenModule &CGM, llvm::Constant *C) { auto *GV = cast(C->stripPointerCasts()); if (CGM.getTarget().getTriple().isOSBinFormatCOFF()) { IdentifierInfo &II = CGM.getContext().Idents.get(C->getName()); TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); assert((isa(C->stripPointerCasts()) || isa(C->stripPointerCasts())) && "expected Function or GlobalVariable"); const NamedDecl *ND = nullptr; for (const auto &Result : DC->lookup(&II)) if ((ND = dyn_cast(Result)) || (ND = dyn_cast(Result))) break; // TODO: support static blocks runtime if (GV->isDeclaration() && (!ND || !ND->hasAttr())) { GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); GV->setLinkage(llvm::GlobalValue::ExternalLinkage); } else { GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); GV->setLinkage(llvm::GlobalValue::ExternalLinkage); } } if (CGM.getLangOpts().BlocksRuntimeOptional && GV->isDeclaration() && GV->hasExternalLinkage()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); CGM.setDSOLocal(GV); } llvm::Constant *CodeGenModule::getBlockObjectDispose() { if (BlockObjectDispose) return BlockObjectDispose; llvm::Type *args[] = { Int8PtrTy, Int32Ty }; llvm::FunctionType *fty = llvm::FunctionType::get(VoidTy, args, false); BlockObjectDispose = CreateRuntimeFunction(fty, "_Block_object_dispose"); configureBlocksRuntimeObject(*this, BlockObjectDispose); return BlockObjectDispose; } llvm::Constant *CodeGenModule::getBlockObjectAssign() { if (BlockObjectAssign) return BlockObjectAssign; llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty }; llvm::FunctionType *fty = llvm::FunctionType::get(VoidTy, args, false); BlockObjectAssign = CreateRuntimeFunction(fty, "_Block_object_assign"); configureBlocksRuntimeObject(*this, BlockObjectAssign); return BlockObjectAssign; } llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { if (NSConcreteGlobalBlock) return NSConcreteGlobalBlock; NSConcreteGlobalBlock = GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock", Int8PtrTy->getPointerTo(), nullptr); configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock); return NSConcreteGlobalBlock; } llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { if (NSConcreteStackBlock) return NSConcreteStackBlock; NSConcreteStackBlock = GetOrCreateLLVMGlobal("_NSConcreteStackBlock", Int8PtrTy->getPointerTo(), nullptr); configureBlocksRuntimeObject(*this, NSConcreteStackBlock); return NSConcreteStackBlock; } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 3e994edc976b..915738b8b301 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1,3939 +1,3909 @@ //===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This provides Objective-C code generation targeting the GNU runtime. The // class in this file generates structures used by the GNU Objective-C runtime // library. These structures are defined in objc/objc.h and objc/objc-api.h in // the GNU runtime distribution. // //===----------------------------------------------------------------------===// #include "CGObjCRuntime.h" #include "CGCleanup.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" #include using namespace clang; using namespace CodeGen; namespace { std::string SymbolNameForMethod( StringRef ClassName, StringRef CategoryName, const Selector MethodName, bool isClassMethod) { std::string MethodNameColonStripped = MethodName.getAsString(); std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), ':', '_'); return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + CategoryName + "_" + MethodNameColonStripped).str(); } /// Class that lazily initialises the runtime function. Avoids inserting the /// types and the function declaration into a module if they're not used, and /// avoids constructing the type more than once if it's used more than once. class LazyRuntimeFunction { CodeGenModule *CGM; llvm::FunctionType *FTy; const char *FunctionName; llvm::Constant *Function; public: /// Constructor leaves this class uninitialized, because it is intended to /// be used as a field in another class and not all of the types that are /// used as arguments will necessarily be available at construction time. LazyRuntimeFunction() : CGM(nullptr), FunctionName(nullptr), Function(nullptr) {} /// Initialises the lazy function with the name, return type, and the types /// of the arguments. template void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy, Tys *... Types) { CGM = Mod; FunctionName = name; Function = nullptr; if(sizeof...(Tys)) { SmallVector ArgTys({Types...}); FTy = llvm::FunctionType::get(RetTy, ArgTys, false); } else { FTy = llvm::FunctionType::get(RetTy, None, false); } } llvm::FunctionType *getType() { return FTy; } /// Overloaded cast operator, allows the class to be implicitly cast to an /// LLVM constant. operator llvm::Constant *() { if (!Function) { if (!FunctionName) return nullptr; Function = CGM->CreateRuntimeFunction(FTy, FunctionName); } return Function; } operator llvm::Function *() { return cast((llvm::Constant *)*this); } }; /// GNU Objective-C runtime code generation. This class implements the parts of /// Objective-C support that are specific to the GNU family of runtimes (GCC, /// GNUstep and ObjFW). class CGObjCGNU : public CGObjCRuntime { protected: /// The LLVM module into which output is inserted llvm::Module &TheModule; /// strut objc_super. Used for sending messages to super. This structure /// contains the receiver (object) and the expected class. llvm::StructType *ObjCSuperTy; /// struct objc_super*. The type of the argument to the superclass message /// lookup functions. llvm::PointerType *PtrToObjCSuperTy; /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring /// SEL is included in a header somewhere, in which case it will be whatever /// type is declared in that header, most likely {i8*, i8*}. llvm::PointerType *SelectorTy; /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the /// places where it's used llvm::IntegerType *Int8Ty; /// Pointer to i8 - LLVM type of char*, for all of the places where the /// runtime needs to deal with C strings. llvm::PointerType *PtrToInt8Ty; /// struct objc_protocol type llvm::StructType *ProtocolTy; /// Protocol * type. llvm::PointerType *ProtocolPtrTy; /// Instance Method Pointer type. This is a pointer to a function that takes, /// at a minimum, an object and a selector, and is the generic type for /// Objective-C methods. Due to differences between variadic / non-variadic /// calling conventions, it must always be cast to the correct type before /// actually being used. llvm::PointerType *IMPTy; /// Type of an untyped Objective-C object. Clang treats id as a built-in type /// when compiling Objective-C code, so this may be an opaque pointer (i8*), /// but if the runtime header declaring it is included then it may be a /// pointer to a structure. llvm::PointerType *IdTy; /// Pointer to a pointer to an Objective-C object. Used in the new ABI /// message lookup function and some GC-related functions. llvm::PointerType *PtrToIdTy; /// The clang type of id. Used when using the clang CGCall infrastructure to /// call Objective-C methods. CanQualType ASTIdTy; /// LLVM type for C int type. llvm::IntegerType *IntTy; /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is /// used in the code to document the difference between i8* meaning a pointer /// to a C string and i8* meaning a pointer to some opaque type. llvm::PointerType *PtrTy; /// LLVM type for C long type. The runtime uses this in a lot of places where /// it should be using intptr_t, but we can't fix this without breaking /// compatibility with GCC... llvm::IntegerType *LongTy; /// LLVM type for C size_t. Used in various runtime data structures. llvm::IntegerType *SizeTy; /// LLVM type for C intptr_t. llvm::IntegerType *IntPtrTy; /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions. llvm::IntegerType *PtrDiffTy; /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance /// variables. llvm::PointerType *PtrToIntTy; /// LLVM type for Objective-C BOOL type. llvm::Type *BoolTy; /// 32-bit integer type, to save us needing to look it up every time it's used. llvm::IntegerType *Int32Ty; /// 64-bit integer type, to save us needing to look it up every time it's used. llvm::IntegerType *Int64Ty; /// The type of struct objc_property. llvm::StructType *PropertyMetadataTy; /// Metadata kind used to tie method lookups to message sends. The GNUstep /// runtime provides some LLVM passes that can use this to do things like /// automatic IMP caching and speculative inlining. unsigned msgSendMDKind; /// Helper to check if we are targeting a specific runtime version or later. bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) { const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime; return (R.getKind() == kind) && (R.getVersion() >= VersionTuple(major, minor)); } std::string SymbolForProtocol(StringRef Name) { return (StringRef("._OBJC_PROTOCOL_") + Name).str(); } std::string SymbolForProtocolRef(StringRef Name) { return (StringRef("._OBJC_REF_PROTOCOL_") + Name).str(); } /// Helper function that generates a constant string and returns a pointer to /// the start of the string. The result of this function can be used anywhere /// where the C code specifies const char*. llvm::Constant *MakeConstantString(StringRef Str, const char *Name = "") { ConstantAddress Array = CGM.GetAddrOfConstantCString(Str, Name); return llvm::ConstantExpr::getGetElementPtr(Array.getElementType(), Array.getPointer(), Zeros); } /// Emits a linkonce_odr string, whose name is the prefix followed by the /// string value. This allows the linker to combine the strings between /// different modules. Used for EH typeinfo names, selector strings, and a /// few other things. llvm::Constant *ExportUniqueString(const std::string &Str, const std::string &prefix, bool Private=false) { std::string name = prefix + Str; auto *ConstStr = TheModule.getGlobalVariable(name); if (!ConstStr) { llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str); auto *GV = new llvm::GlobalVariable(TheModule, value->getType(), true, llvm::GlobalValue::LinkOnceODRLinkage, value, name); if (Private) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); ConstStr = GV; } return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(), ConstStr, Zeros); } /// Returns a property name and encoding string. llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD, const Decl *Container) { assert(!isRuntime(ObjCRuntime::GNUstep, 2)); if (isRuntime(ObjCRuntime::GNUstep, 1, 6)) { std::string NameAndAttributes; std::string TypeStr = CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container); NameAndAttributes += '\0'; NameAndAttributes += TypeStr.length() + 3; NameAndAttributes += TypeStr; NameAndAttributes += '\0'; NameAndAttributes += PD->getNameAsString(); return MakeConstantString(NameAndAttributes); } return MakeConstantString(PD->getNameAsString()); } /// Push the property attributes into two structure fields. void PushPropertyAttributes(ConstantStructBuilder &Fields, const ObjCPropertyDecl *property, bool isSynthesized=true, bool isDynamic=true) { int attrs = property->getPropertyAttributes(); // For read-only properties, clear the copy and retain flags if (attrs & ObjCPropertyDecl::OBJC_PR_readonly) { attrs &= ~ObjCPropertyDecl::OBJC_PR_copy; attrs &= ~ObjCPropertyDecl::OBJC_PR_retain; attrs &= ~ObjCPropertyDecl::OBJC_PR_weak; attrs &= ~ObjCPropertyDecl::OBJC_PR_strong; } // The first flags field has the same attribute values as clang uses internally Fields.addInt(Int8Ty, attrs & 0xff); attrs >>= 8; attrs <<= 2; // For protocol properties, synthesized and dynamic have no meaning, so we // reuse these flags to indicate that this is a protocol property (both set // has no meaning, as a property can't be both synthesized and dynamic) attrs |= isSynthesized ? (1<<0) : 0; attrs |= isDynamic ? (1<<1) : 0; // The second field is the next four fields left shifted by two, with the // low bit set to indicate whether the field is synthesized or dynamic. Fields.addInt(Int8Ty, attrs & 0xff); // Two padding fields Fields.addInt(Int8Ty, 0); Fields.addInt(Int8Ty, 0); } virtual ConstantArrayBuilder PushPropertyListHeader(ConstantStructBuilder &Fields, int count) { // int count; Fields.addInt(IntTy, count); // int size; (only in GNUstep v2 ABI. if (isRuntime(ObjCRuntime::GNUstep, 2)) { llvm::DataLayout td(&TheModule); Fields.addInt(IntTy, td.getTypeSizeInBits(PropertyMetadataTy) / CGM.getContext().getCharWidth()); } // struct objc_property_list *next; Fields.add(NULLPtr); // struct objc_property properties[] return Fields.beginArray(PropertyMetadataTy); } virtual void PushProperty(ConstantArrayBuilder &PropertiesArray, const ObjCPropertyDecl *property, const Decl *OCD, bool isSynthesized=true, bool isDynamic=true) { auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy); ASTContext &Context = CGM.getContext(); Fields.add(MakePropertyEncodingString(property, OCD)); PushPropertyAttributes(Fields, property, isSynthesized, isDynamic); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) { std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); Fields.add(MakeConstantString(accessor->getSelector().getAsString())); Fields.add(TypeEncoding); } else { Fields.add(NULLPtr); Fields.add(NULLPtr); } }; addPropertyMethod(property->getGetterMethodDecl()); addPropertyMethod(property->getSetterMethodDecl()); Fields.finishAndAddTo(PropertiesArray); } /// Ensures that the value has the required type, by inserting a bitcast if /// required. This function lets us avoid inserting bitcasts that are /// redundant. llvm::Value* EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) { if (V->getType() == Ty) return V; return B.CreateBitCast(V, Ty); } Address EnforceType(CGBuilderTy &B, Address V, llvm::Type *Ty) { if (V.getType() == Ty) return V; return B.CreateBitCast(V, Ty); } // Some zeros used for GEPs in lots of places. llvm::Constant *Zeros[2]; /// Null pointer value. Mainly used as a terminator in various arrays. llvm::Constant *NULLPtr; /// LLVM context. llvm::LLVMContext &VMContext; protected: /// Placeholder for the class. Lots of things refer to the class before we've /// actually emitted it. We use this alias as a placeholder, and then replace /// it with a pointer to the class structure before finally emitting the /// module. llvm::GlobalAlias *ClassPtrAlias; /// Placeholder for the metaclass. Lots of things refer to the class before /// we've / actually emitted it. We use this alias as a placeholder, and then /// replace / it with a pointer to the metaclass structure before finally /// emitting the / module. llvm::GlobalAlias *MetaClassPtrAlias; /// All of the classes that have been generated for this compilation units. std::vector Classes; /// All of the categories that have been generated for this compilation units. std::vector Categories; /// All of the Objective-C constant strings that have been generated for this /// compilation units. std::vector ConstantStrings; /// Map from string values to Objective-C constant strings in the output. /// Used to prevent emitting Objective-C strings more than once. This should /// not be required at all - CodeGenModule should manage this list. llvm::StringMap ObjCStrings; /// All of the protocols that have been declared. llvm::StringMap ExistingProtocols; /// For each variant of a selector, we store the type encoding and a /// placeholder value. For an untyped selector, the type will be the empty /// string. Selector references are all done via the module's selector table, /// so we create an alias as a placeholder and then replace it with the real /// value later. typedef std::pair TypedSelector; /// Type of the selector map. This is roughly equivalent to the structure /// used in the GNUstep runtime, which maintains a list of all of the valid /// types for a selector in a table. typedef llvm::DenseMap > SelectorMap; /// A map from selectors to selector types. This allows us to emit all /// selectors of the same name and type together. SelectorMap SelectorTable; /// Selectors related to memory management. When compiling in GC mode, we /// omit these. Selector RetainSel, ReleaseSel, AutoreleaseSel; /// Runtime functions used for memory management in GC mode. Note that clang /// supports code generation for calling these functions, but neither GNU /// runtime actually supports this API properly yet. LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn, WeakAssignFn, GlobalAssignFn; typedef std::pair ClassAliasPair; /// All classes that have aliases set for them. std::vector ClassAliases; protected: /// Function used for throwing Objective-C exceptions. LazyRuntimeFunction ExceptionThrowFn; /// Function used for rethrowing exceptions, used at the end of \@finally or /// \@synchronize blocks. LazyRuntimeFunction ExceptionReThrowFn; /// Function called when entering a catch function. This is required for /// differentiating Objective-C exceptions and foreign exceptions. LazyRuntimeFunction EnterCatchFn; /// Function called when exiting from a catch block. Used to do exception /// cleanup. LazyRuntimeFunction ExitCatchFn; /// Function called when entering an \@synchronize block. Acquires the lock. LazyRuntimeFunction SyncEnterFn; /// Function called when exiting an \@synchronize block. Releases the lock. LazyRuntimeFunction SyncExitFn; private: /// Function called if fast enumeration detects that the collection is /// modified during the update. LazyRuntimeFunction EnumerationMutationFn; /// Function for implementing synthesized property getters that return an /// object. LazyRuntimeFunction GetPropertyFn; /// Function for implementing synthesized property setters that return an /// object. LazyRuntimeFunction SetPropertyFn; /// Function used for non-object declared property getters. LazyRuntimeFunction GetStructPropertyFn; /// Function used for non-object declared property setters. LazyRuntimeFunction SetStructPropertyFn; protected: /// The version of the runtime that this class targets. Must match the /// version in the runtime. int RuntimeVersion; /// The version of the protocol class. Used to differentiate between ObjC1 /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional /// components and can not contain declared properties. We always emit /// Objective-C 2 property structures, but we have to pretend that they're /// Objective-C 1 property structures when targeting the GCC runtime or it /// will abort. const int ProtocolVersion; /// The version of the class ABI. This value is used in the class structure /// and indicates how various fields should be interpreted. const int ClassABIVersion; /// Generates an instance variable list structure. This is a structure /// containing a size and an array of structures containing instance variable /// metadata. This is used purely for introspection in the fragile ABI. In /// the non-fragile ABI, it's used for instance variable fixup. virtual llvm::Constant *GenerateIvarList(ArrayRef IvarNames, ArrayRef IvarTypes, ArrayRef IvarOffsets, ArrayRef IvarAlign, ArrayRef IvarOwnership); /// Generates a method list structure. This is a structure containing a size /// and an array of structures containing method metadata. /// /// This structure is used by both classes and categories, and contains a next /// pointer allowing them to be chained together in a linked list. llvm::Constant *GenerateMethodList(StringRef ClassName, StringRef CategoryName, ArrayRef Methods, bool isClassMethodList); /// Emits an empty protocol. This is used for \@protocol() where no protocol /// is found. The runtime will (hopefully) fix up the pointer to refer to the /// real protocol. virtual llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName); /// Generates a list of property metadata structures. This follows the same /// pattern as method and instance variable metadata lists. llvm::Constant *GeneratePropertyList(const Decl *Container, const ObjCContainerDecl *OCD, bool isClassProperty=false, bool protocolOptionalProperties=false); /// Generates a list of referenced protocols. Classes, categories, and /// protocols all use this structure. llvm::Constant *GenerateProtocolList(ArrayRef Protocols); /// To ensure that all protocols are seen by the runtime, we add a category on /// a class defined in the runtime, declaring no methods, but adopting the /// protocols. This is a horribly ugly hack, but it allows us to collect all /// of the protocols without changing the ABI. void GenerateProtocolHolderCategory(); /// Generates a class structure. llvm::Constant *GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, unsigned info, const char *Name, llvm::Constant *Version, llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, llvm::Constant *StrongIvarBitmap, llvm::Constant *WeakIvarBitmap, bool isMeta=false); /// Generates a method list. This is used by protocols to define the required /// and optional methods. virtual llvm::Constant *GenerateProtocolMethodList( ArrayRef Methods); /// Emits optional and required method lists. template void EmitProtocolMethodList(T &&Methods, llvm::Constant *&Required, llvm::Constant *&Optional) { SmallVector RequiredMethods; SmallVector OptionalMethods; for (const auto *I : Methods) if (I->isOptional()) OptionalMethods.push_back(I); else RequiredMethods.push_back(I); Required = GenerateProtocolMethodList(RequiredMethods); Optional = GenerateProtocolMethodList(OptionalMethods); } /// Returns a selector with the specified type encoding. An empty string is /// used to return an untyped selector (with the types field set to NULL). virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel, const std::string &TypeEncoding); /// Returns the name of ivar offset variables. In the GNUstep v1 ABI, this /// contains the class and ivar names, in the v2 ABI this contains the type /// encoding as well. virtual std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar) { const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + '.' + Ivar->getNameAsString(); return Name; } /// Returns the variable used to store the offset of an instance variable. llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); /// Emits a reference to a class. This allows the linker to object if there /// is no class of the matching name. void EmitClassRef(const std::string &className); /// Emits a pointer to the named class virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF, const std::string &Name, bool isWeak); /// Looks up the method for sending a message to the specified object. This /// mechanism differs between the GCC and GNU runtimes, so this method must be /// overridden in subclasses. virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node, MessageSendInfo &MSI) = 0; /// Looks up the method for sending a message to a superclass. This /// mechanism differs between the GCC and GNU runtimes, so this method must /// be overridden in subclasses. virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, llvm::Value *cmd, MessageSendInfo &MSI) = 0; /// Libobjc2 uses a bitfield representation where small(ish) bitfields are /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 /// bits set to their values, LSB first, while larger ones are stored in a /// structure of this / form: /// /// struct { int32_t length; int32_t values[length]; }; /// /// The values in the array are stored in host-endian format, with the least /// significant bit being assumed to come first in the bitfield. Therefore, /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, /// while a bitfield / with the 63rd bit set will be 1<<64. llvm::Constant *MakeBitField(ArrayRef bits); public: CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion, unsigned classABI=1); ConstantAddress GenerateConstantString(const StringLiteral *) override; RValue GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) override; RValue GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) override; llvm::Value *GetClass(CodeGenFunction &CGF, const ObjCInterfaceDecl *OID) override; llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override; Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override; llvm::Value *GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl *Method) override; virtual llvm::Constant *GetConstantSelector(Selector Sel, const std::string &TypeEncoding) { llvm_unreachable("Runtime unable to generate constant selector"); } llvm::Constant *GetConstantSelector(const ObjCMethodDecl *M) { return GetConstantSelector(M->getSelector(), CGM.getContext().getObjCEncodingForMethodDecl(M)); } llvm::Constant *GetEHType(QualType T) override; llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) override; void GenerateCategory(const ObjCCategoryImplDecl *CMD) override; void GenerateClass(const ObjCImplementationDecl *ClassDecl) override; void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override; llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) override; void GenerateProtocol(const ObjCProtocolDecl *PD) override; llvm::Function *ModuleInitFunction() override; llvm::Constant *GetPropertyGetFunction() override; llvm::Constant *GetPropertySetFunction() override; llvm::Constant *GetOptimizedPropertySetFunction(bool atomic, bool copy) override; llvm::Constant *GetSetStructFunction() override; llvm::Constant *GetGetStructFunction() override; llvm::Constant *GetCppAtomicObjectGetFunction() override; llvm::Constant *GetCppAtomicObjectSetFunction() override; llvm::Constant *EnumerationMutationFunction() override; void EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) override; void EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) override; void EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S, bool ClearInsertionPoint=true) override; llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF, Address AddrWeakObj) override; void EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) override; void EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, Address dest, bool threadlocal=false) override; void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, Address dest, llvm::Value *ivarOffset) override; void EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, Address dest) override; void EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *Size) override; LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) override; llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) override; llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override; llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) override { return NULLPtr; } llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) override { return NULLPtr; } llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, QualType T) override { return NULLPtr; } }; /// Class representing the legacy GCC Objective-C ABI. This is the default when /// -fobjc-nonfragile-abi is not specified. /// /// The GCC ABI target actually generates code that is approximately compatible /// with the new GNUstep runtime ABI, but refrains from using any features that /// would not work with the GCC runtime. For example, clang always generates /// the extended form of the class structure, and the extra fields are simply /// ignored by GCC libobjc. class CGObjCGCC : public CGObjCGNU { /// The GCC ABI message lookup function. Returns an IMP pointing to the /// method implementation for this message. LazyRuntimeFunction MsgLookupFn; /// The GCC ABI superclass message lookup function. Takes a pointer to a /// structure describing the receiver and the class, and a selector as /// arguments. Returns the IMP for the corresponding method. LazyRuntimeFunction MsgLookupSuperFn; protected: llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *args[] = { EnforceType(Builder, Receiver, IdTy), EnforceType(Builder, cmd, SelectorTy) }; llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args); imp->setMetadata(msgSendMDKind, node); return imp.getInstruction(); } llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy).getPointer(), cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } public: CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) { // IMP objc_msg_lookup(id, SEL); MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy); // IMP objc_msg_lookup_super(struct objc_super*, SEL); MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, PtrToObjCSuperTy, SelectorTy); } }; /// Class used when targeting the new GNUstep runtime ABI. class CGObjCGNUstep : public CGObjCGNU { /// The slot lookup function. Returns a pointer to a cacheable structure /// that contains (among other things) the IMP. LazyRuntimeFunction SlotLookupFn; /// The GNUstep ABI superclass message lookup function. Takes a pointer to /// a structure describing the receiver and the class, and a selector as /// arguments. Returns the slot for the corresponding method. Superclass /// message lookup rarely changes, so this is a good caching opportunity. LazyRuntimeFunction SlotLookupSuperFn; /// Specialised function for setting atomic retain properties LazyRuntimeFunction SetPropertyAtomic; /// Specialised function for setting atomic copy properties LazyRuntimeFunction SetPropertyAtomicCopy; /// Specialised function for setting nonatomic retain properties LazyRuntimeFunction SetPropertyNonAtomic; /// Specialised function for setting nonatomic copy properties LazyRuntimeFunction SetPropertyNonAtomicCopy; /// Function to perform atomic copies of C++ objects with nontrivial copy /// constructors from Objective-C ivars. LazyRuntimeFunction CxxAtomicObjectGetFn; /// Function to perform atomic copies of C++ objects with nontrivial copy /// constructors to Objective-C ivars. LazyRuntimeFunction CxxAtomicObjectSetFn; /// Type of an slot structure pointer. This is returned by the various /// lookup functions. llvm::Type *SlotTy; public: llvm::Constant *GetEHType(QualType T) override; protected: llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Function *LookupFn = SlotLookupFn; // Store the receiver on the stack so that we can reload it later Address ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); Builder.CreateStore(Receiver, ReceiverPtr); llvm::Value *self; if (isa(CGF.CurCodeDecl)) { self = CGF.LoadObjCSelf(); } else { self = llvm::ConstantPointerNull::get(IdTy); } // The lookup function is guaranteed not to capture the receiver pointer. LookupFn->addParamAttr(0, llvm::Attribute::NoCapture); llvm::Value *args[] = { EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), EnforceType(Builder, cmd, SelectorTy), EnforceType(Builder, self, IdTy) }; llvm::CallSite slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args); slot.setOnlyReadsMemory(); slot->setMetadata(msgSendMDKind, node); // Load the imp from the slot llvm::Value *imp = Builder.CreateAlignedLoad( Builder.CreateStructGEP(nullptr, slot.getInstruction(), 4), CGF.getPointerAlign()); // The lookup function may have changed the receiver, so make sure we use // the new one. Receiver = Builder.CreateLoad(ReceiverPtr, true); return imp; } llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = {ObjCSuper.getPointer(), cmd}; llvm::CallInst *slot = CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs); slot->setOnlyReadsMemory(); return Builder.CreateAlignedLoad(Builder.CreateStructGEP(nullptr, slot, 4), CGF.getPointerAlign()); } public: CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 9, 3, 1) {} CGObjCGNUstep(CodeGenModule &Mod, unsigned ABI, unsigned ProtocolABI, unsigned ClassABI) : CGObjCGNU(Mod, ABI, ProtocolABI, ClassABI) { const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime; llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy); SlotTy = llvm::PointerType::getUnqual(SlotStructTy); // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender); SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy, SelectorTy, IdTy); // Slot_t objc_slot_lookup_super(struct objc_super*, SEL); SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy, PtrToObjCSuperTy, SelectorTy); // If we're in ObjC++ mode, then we want to make if (CGM.getLangOpts().CPlusPlus) { llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // void *__cxa_begin_catch(void *e) EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy); // void __cxa_end_catch(void) ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy); // void _Unwind_Resume_or_Rethrow(void*) ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy); } else if (R.getVersion() >= VersionTuple(1, 7)) { llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // id objc_begin_catch(void *e) EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy); // void objc_end_catch(void) ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy); // void _Unwind_Resume_or_Rethrow(void*) ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy); } llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy", VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); // void objc_setCppObjectAtomic(void *dest, const void *src, void // *helper); CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy, PtrTy, PtrTy); // void objc_getCppObjectAtomic(void *dest, const void *src, void // *helper); CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy, PtrTy, PtrTy); } llvm::Constant *GetCppAtomicObjectGetFunction() override { // The optimised functions were added in version 1.7 of the GNUstep // runtime. assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= VersionTuple(1, 7)); return CxxAtomicObjectGetFn; } llvm::Constant *GetCppAtomicObjectSetFunction() override { // The optimised functions were added in version 1.7 of the GNUstep // runtime. assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= VersionTuple(1, 7)); return CxxAtomicObjectSetFn; } llvm::Constant *GetOptimizedPropertySetFunction(bool atomic, bool copy) override { // The optimised property functions omit the GC check, and so are not // safe to use in GC mode. The standard functions are fast in GC mode, // so there is less advantage in using them. assert ((CGM.getLangOpts().getGC() == LangOptions::NonGC)); // The optimised functions were added in version 1.7 of the GNUstep // runtime. assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= VersionTuple(1, 7)); if (atomic) { if (copy) return SetPropertyAtomicCopy; return SetPropertyAtomic; } return copy ? SetPropertyNonAtomicCopy : SetPropertyNonAtomic; } }; /// GNUstep Objective-C ABI version 2 implementation. /// This is the ABI that provides a clean break with the legacy GCC ABI and /// cleans up a number of things that were added to work around 1980s linkers. class CGObjCGNUstep2 : public CGObjCGNUstep { /// The section for selectors. static constexpr const char *const SelSection = "__objc_selectors"; /// The section for classes. static constexpr const char *const ClsSection = "__objc_classes"; /// The section for references to classes. static constexpr const char *const ClsRefSection = "__objc_class_refs"; /// The section for categories. static constexpr const char *const CatSection = "__objc_cats"; /// The section for protocols. static constexpr const char *const ProtocolSection = "__objc_protocols"; /// The section for protocol references. static constexpr const char *const ProtocolRefSection = "__objc_protocol_refs"; /// The section for class aliases static constexpr const char *const ClassAliasSection = "__objc_class_aliases"; /// The section for constexpr constant strings static constexpr const char *const ConstantStringSection = "__objc_constant_string"; /// The GCC ABI superclass message lookup function. Takes a pointer to a /// structure describing the receiver and the class, and a selector as /// arguments. Returns the IMP for the corresponding method. LazyRuntimeFunction MsgLookupSuperFn; /// A flag indicating if we've emitted at least one protocol. /// If we haven't, then we need to emit an empty protocol, to ensure that the /// __start__objc_protocols and __stop__objc_protocols sections exist. bool EmittedProtocol = false; /// A flag indicating if we've emitted at least one protocol reference. /// If we haven't, then we need to emit an empty protocol, to ensure that the /// __start__objc_protocol_refs and __stop__objc_protocol_refs sections /// exist. bool EmittedProtocolRef = false; /// A flag indicating if we've emitted at least one class. /// If we haven't, then we need to emit an empty protocol, to ensure that the /// __start__objc_classes and __stop__objc_classes sections / exist. bool EmittedClass = false; /// Generate the name of a symbol for a reference to a class. Accesses to /// classes should be indirected via this. std::string SymbolForClassRef(StringRef Name, bool isWeak) { if (isWeak) return (StringRef("._OBJC_WEAK_REF_CLASS_") + Name).str(); else return (StringRef("._OBJC_REF_CLASS_") + Name).str(); } /// Generate the name of a class symbol. std::string SymbolForClass(StringRef Name) { return (StringRef("._OBJC_CLASS_") + Name).str(); } void CallRuntimeFunction(CGBuilderTy &B, StringRef FunctionName, ArrayRef Args) { SmallVector Types; for (auto *Arg : Args) Types.push_back(Arg->getType()); llvm::FunctionType *FT = llvm::FunctionType::get(B.getVoidTy(), Types, false); llvm::Value *Fn = CGM.CreateRuntimeFunction(FT, FunctionName); B.CreateCall(Fn, Args); } ConstantAddress GenerateConstantString(const StringLiteral *SL) override { auto Str = SL->getString(); CharUnits Align = CGM.getPointerAlign(); // Look for an existing one llvm::StringMap::iterator old = ObjCStrings.find(Str); if (old != ObjCStrings.end()) return ConstantAddress(old->getValue(), Align); bool isNonASCII = SL->containsNonAscii(); auto LiteralLength = SL->getLength(); if ((CGM.getTarget().getPointerWidth(0) == 64) && (LiteralLength < 9) && !isNonASCII) { // Tiny strings are only used on 64-bit platforms. They store 8 7-bit // ASCII characters in the high 56 bits, followed by a 4-bit length and a // 3-bit tag (which is always 4). uint64_t str = 0; // Fill in the characters for (unsigned i=0 ; igetCodeUnit(i)) << ((64 - 4 - 3) - (i*7)); // Fill in the length str |= LiteralLength << 3; // Set the tag str |= 4; auto *ObjCStr = llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int64Ty, str), IdTy); ObjCStrings[Str] = ObjCStr; return ConstantAddress(ObjCStr, Align); } StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass; if (StringClass.empty()) StringClass = "NSConstantString"; std::string Sym = SymbolForClass(StringClass); llvm::Constant *isa = TheModule.getNamedGlobal(Sym); if (!isa) isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false, llvm::GlobalValue::ExternalLinkage, nullptr, Sym); else if (isa->getType() != PtrToIdTy) isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); // struct // { // Class isa; // uint32_t flags; // uint32_t length; // Number of codepoints // uint32_t size; // Number of bytes // uint32_t hash; // const char *data; // }; ConstantInitBuilder Builder(CGM); auto Fields = Builder.beginStruct(); Fields.add(isa); // For now, all non-ASCII strings are represented as UTF-16. As such, the // number of bytes is simply double the number of UTF-16 codepoints. In // ASCII strings, the number of bytes is equal to the number of non-ASCII // codepoints. if (isNonASCII) { unsigned NumU8CodeUnits = Str.size(); // A UTF-16 representation of a unicode string contains at most the same // number of code units as a UTF-8 representation. Allocate that much // space, plus one for the final null character. SmallVector ToBuf(NumU8CodeUnits + 1); const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)Str.data(); llvm::UTF16 *ToPtr = &ToBuf[0]; (void)llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumU8CodeUnits, &ToPtr, ToPtr + NumU8CodeUnits, llvm::strictConversion); uint32_t StringLength = ToPtr - &ToBuf[0]; // Add null terminator *ToPtr = 0; // Flags: 2 indicates UTF-16 encoding Fields.addInt(Int32Ty, 2); // Number of UTF-16 codepoints Fields.addInt(Int32Ty, StringLength); // Number of bytes Fields.addInt(Int32Ty, StringLength * 2); // Hash. Not currently initialised by the compiler. Fields.addInt(Int32Ty, 0); // pointer to the data string. auto Arr = llvm::makeArrayRef(&ToBuf[0], ToPtr+1); auto *C = llvm::ConstantDataArray::get(VMContext, Arr); auto *Buffer = new llvm::GlobalVariable(TheModule, C->getType(), /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, C, ".str"); Buffer->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); Fields.add(Buffer); } else { // Flags: 0 indicates ASCII encoding Fields.addInt(Int32Ty, 0); // Number of UTF-16 codepoints, each ASCII byte is a UTF-16 codepoint Fields.addInt(Int32Ty, Str.size()); // Number of bytes Fields.addInt(Int32Ty, Str.size()); // Hash. Not currently initialised by the compiler. Fields.addInt(Int32Ty, 0); // Data pointer Fields.add(MakeConstantString(Str)); } std::string StringName; bool isNamed = !isNonASCII; if (isNamed) { StringName = ".objc_str_"; for (int i=0,e=Str.size() ; isetSection(ConstantStringSection); if (isNamed) { ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName)); ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility); } llvm::Constant *ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStrGV, IdTy); ObjCStrings[Str] = ObjCStr; ConstantStrings.push_back(ObjCStr); return ConstantAddress(ObjCStr, Align); } void PushProperty(ConstantArrayBuilder &PropertiesArray, const ObjCPropertyDecl *property, const Decl *OCD, bool isSynthesized=true, bool isDynamic=true) override { // struct objc_property // { // const char *name; // const char *attributes; // const char *type; // SEL getter; // SEL setter; // }; auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy); ASTContext &Context = CGM.getContext(); Fields.add(MakeConstantString(property->getNameAsString())); std::string TypeStr = CGM.getContext().getObjCEncodingForPropertyDecl(property, OCD); Fields.add(MakeConstantString(TypeStr)); std::string typeStr; Context.getObjCEncodingForType(property->getType(), typeStr); Fields.add(MakeConstantString(typeStr)); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) { std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor); Fields.add(GetConstantSelector(accessor->getSelector(), TypeStr)); } else { Fields.add(NULLPtr); } }; addPropertyMethod(property->getGetterMethodDecl()); addPropertyMethod(property->getSetterMethodDecl()); Fields.finishAndAddTo(PropertiesArray); } llvm::Constant * GenerateProtocolMethodList(ArrayRef Methods) override { // struct objc_protocol_method_description // { // SEL selector; // const char *types; // }; llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty }); ASTContext &Context = CGM.getContext(); ConstantInitBuilder Builder(CGM); // struct objc_protocol_method_description_list // { // int count; // int size; // struct objc_protocol_method_description methods[]; // }; auto MethodList = Builder.beginStruct(); // int count; MethodList.addInt(IntTy, Methods.size()); // int size; // sizeof(struct objc_method_description) llvm::DataLayout td(&TheModule); MethodList.addInt(IntTy, td.getTypeSizeInBits(ObjCMethodDescTy) / CGM.getContext().getCharWidth()); // struct objc_method_description[] auto MethodArray = MethodList.beginArray(ObjCMethodDescTy); for (auto *M : Methods) { auto Method = MethodArray.beginStruct(ObjCMethodDescTy); Method.add(CGObjCGNU::GetConstantSelector(M)); Method.add(GetTypeString(Context.getObjCEncodingForMethodDecl(M, true))); Method.finishAndAddTo(MethodArray); } MethodArray.finishAndAddTo(MethodList); return MethodList.finishAndCreateGlobal(".objc_protocol_method_list", CGM.getPointerAlign()); } llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, llvm::Value *cmd, MessageSendInfo &MSI) override { // Don't access the slot unless we're trying to cache the result. CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = {CGObjCGNU::EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy).getPointer(), cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } llvm::GlobalVariable *GetClassVar(StringRef Name, bool isWeak=false) { std::string SymbolName = SymbolForClassRef(Name, isWeak); auto *ClassSymbol = TheModule.getNamedGlobal(SymbolName); if (ClassSymbol) return ClassSymbol; ClassSymbol = new llvm::GlobalVariable(TheModule, IdTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, SymbolName); // If this is a weak symbol, then we are creating a valid definition for // the symbol, pointing to a weak definition of the real class pointer. If // this is not a weak reference, then we are expecting another compilation // unit to provide the real indirection symbol. if (isWeak) ClassSymbol->setInitializer(new llvm::GlobalVariable(TheModule, Int8Ty, false, llvm::GlobalValue::ExternalWeakLinkage, nullptr, SymbolForClass(Name))); assert(ClassSymbol->getName() == SymbolName); return ClassSymbol; } llvm::Value *GetClassNamed(CodeGenFunction &CGF, const std::string &Name, bool isWeak) override { return CGF.Builder.CreateLoad(Address(GetClassVar(Name, isWeak), CGM.getPointerAlign())); } int32_t FlagsForOwnership(Qualifiers::ObjCLifetime Ownership) { // typedef enum { // ownership_invalid = 0, // ownership_strong = 1, // ownership_weak = 2, // ownership_unsafe = 3 // } ivar_ownership; int Flag; switch (Ownership) { case Qualifiers::OCL_Strong: Flag = 1; break; case Qualifiers::OCL_Weak: Flag = 2; break; case Qualifiers::OCL_ExplicitNone: Flag = 3; break; case Qualifiers::OCL_None: case Qualifiers::OCL_Autoreleasing: assert(Ownership != Qualifiers::OCL_Autoreleasing); Flag = 0; } return Flag; } llvm::Constant *GenerateIvarList(ArrayRef IvarNames, ArrayRef IvarTypes, ArrayRef IvarOffsets, ArrayRef IvarAlign, ArrayRef IvarOwnership) override { llvm_unreachable("Method should not be called!"); } llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName) override { std::string Name = SymbolForProtocol(ProtocolName); auto *GV = TheModule.getGlobalVariable(Name); if (!GV) { // Emit a placeholder symbol. GV = new llvm::GlobalVariable(TheModule, ProtocolTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, Name); GV->setAlignment(CGM.getPointerAlign().getQuantity()); } return llvm::ConstantExpr::getBitCast(GV, ProtocolPtrTy); } /// Existing protocol references. llvm::StringMap ExistingProtocolRefs; llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) override { auto Name = PD->getNameAsString(); auto *&Ref = ExistingProtocolRefs[Name]; if (!Ref) { auto *&Protocol = ExistingProtocols[Name]; if (!Protocol) Protocol = GenerateProtocolRef(PD); std::string RefName = SymbolForProtocolRef(Name); assert(!TheModule.getGlobalVariable(RefName)); // Emit a reference symbol. auto GV = new llvm::GlobalVariable(TheModule, ProtocolPtrTy, false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName); GV->setSection(ProtocolRefSection); GV->setAlignment(CGM.getPointerAlign().getQuantity()); Ref = GV; } EmittedProtocolRef = true; return CGF.Builder.CreateAlignedLoad(Ref, CGM.getPointerAlign()); } llvm::Constant *GenerateProtocolList(ArrayRef Protocols) { llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(ProtocolPtrTy, Protocols.size()); llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, Protocols); ConstantInitBuilder builder(CGM); auto ProtocolBuilder = builder.beginStruct(); ProtocolBuilder.addNullPointer(PtrTy); ProtocolBuilder.addInt(SizeTy, Protocols.size()); ProtocolBuilder.add(ProtocolArray); return ProtocolBuilder.finishAndCreateGlobal(".objc_protocol_list", CGM.getPointerAlign(), false, llvm::GlobalValue::InternalLinkage); } void GenerateProtocol(const ObjCProtocolDecl *PD) override { // Do nothing - we only emit referenced protocols. } llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD) { std::string ProtocolName = PD->getNameAsString(); auto *&Protocol = ExistingProtocols[ProtocolName]; if (Protocol) return Protocol; EmittedProtocol = true; // Use the protocol definition, if there is one. if (const ObjCProtocolDecl *Def = PD->getDefinition()) PD = Def; SmallVector Protocols; for (const auto *PI : PD->protocols()) Protocols.push_back( llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI), ProtocolPtrTy)); llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); // Collect information about methods llvm::Constant *InstanceMethodList, *OptionalInstanceMethodList; llvm::Constant *ClassMethodList, *OptionalClassMethodList; EmitProtocolMethodList(PD->instance_methods(), InstanceMethodList, OptionalInstanceMethodList); EmitProtocolMethodList(PD->class_methods(), ClassMethodList, OptionalClassMethodList); auto SymName = SymbolForProtocol(ProtocolName); auto *OldGV = TheModule.getGlobalVariable(SymName); // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. ConstantInitBuilder builder(CGM); auto ProtocolBuilder = builder.beginStruct(); ProtocolBuilder.add(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); ProtocolBuilder.add(MakeConstantString(ProtocolName)); ProtocolBuilder.add(ProtocolList); ProtocolBuilder.add(InstanceMethodList); ProtocolBuilder.add(ClassMethodList); ProtocolBuilder.add(OptionalInstanceMethodList); ProtocolBuilder.add(OptionalClassMethodList); // Required instance properties ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, false)); // Optional instance properties ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, true)); // Required class properties ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, false)); // Optional class properties ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, true)); auto *GV = ProtocolBuilder.finishAndCreateGlobal(SymName, CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); GV->setSection(ProtocolSection); GV->setComdat(TheModule.getOrInsertComdat(SymName)); if (OldGV) { OldGV->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GV, OldGV->getType())); OldGV->removeFromParent(); GV->setName(SymName); } Protocol = GV; return GV; } llvm::Constant *EnforceType(llvm::Constant *Val, llvm::Type *Ty) { if (Val->getType() == Ty) return Val; return llvm::ConstantExpr::getBitCast(Val, Ty); } llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel, const std::string &TypeEncoding) override { return GetConstantSelector(Sel, TypeEncoding); } llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) { if (TypeEncoding.empty()) return NULLPtr; std::string MangledTypes = TypeEncoding; std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1'); std::string TypesVarName = ".objc_sel_types_" + MangledTypes; auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName); if (!TypesGlobal) { llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext, TypeEncoding); auto *GV = new llvm::GlobalVariable(TheModule, Init->getType(), true, llvm::GlobalValue::LinkOnceODRLinkage, Init, TypesVarName); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); TypesGlobal = GV; } return llvm::ConstantExpr::getGetElementPtr(TypesGlobal->getValueType(), TypesGlobal, Zeros); } llvm::Constant *GetConstantSelector(Selector Sel, const std::string &TypeEncoding) override { // @ is used as a special character in symbol names (used for symbol // versioning), so mangle the name to not include it. Replace it with a // character that is not a valid type encoding character (and, being // non-printable, never will be!) std::string MangledTypes = TypeEncoding; std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1'); auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" + MangledTypes).str(); if (auto *GV = TheModule.getNamedGlobal(SelVarName)) return EnforceType(GV, SelectorTy); ConstantInitBuilder builder(CGM); auto SelBuilder = builder.beginStruct(); SelBuilder.add(ExportUniqueString(Sel.getAsString(), ".objc_sel_name_", true)); SelBuilder.add(GetTypeString(TypeEncoding)); auto *GV = SelBuilder.finishAndCreateGlobal(SelVarName, CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); GV->setComdat(TheModule.getOrInsertComdat(SelVarName)); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); GV->setSection(SelSection); auto *SelVal = EnforceType(GV, SelectorTy); return SelVal; } std::pair GetSectionBounds(StringRef Section) { auto *Start = new llvm::GlobalVariable(TheModule, PtrTy, /*isConstant*/false, llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__start_") + Section); Start->setVisibility(llvm::GlobalValue::HiddenVisibility); auto *Stop = new llvm::GlobalVariable(TheModule, PtrTy, /*isConstant*/false, llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__stop_") + Section); Stop->setVisibility(llvm::GlobalValue::HiddenVisibility); return { Start, Stop }; } llvm::Function *ModuleInitFunction() override { llvm::Function *LoadFunction = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), llvm::GlobalValue::LinkOnceODRLinkage, ".objcv2_load_function", &TheModule); LoadFunction->setVisibility(llvm::GlobalValue::HiddenVisibility); LoadFunction->setComdat(TheModule.getOrInsertComdat(".objcv2_load_function")); llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); CGBuilderTy B(CGM, VMContext); B.SetInsertPoint(EntryBB); ConstantInitBuilder builder(CGM); auto InitStructBuilder = builder.beginStruct(); InitStructBuilder.addInt(Int64Ty, 0); auto addSection = [&](const char *section) { auto bounds = GetSectionBounds(section); InitStructBuilder.add(bounds.first); InitStructBuilder.add(bounds.second); }; addSection(SelSection); addSection(ClsSection); addSection(ClsRefSection); addSection(CatSection); addSection(ProtocolSection); addSection(ProtocolRefSection); addSection(ClassAliasSection); addSection(ConstantStringSection); auto *InitStruct = InitStructBuilder.finishAndCreateGlobal(".objc_init", CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); InitStruct->setVisibility(llvm::GlobalValue::HiddenVisibility); InitStruct->setComdat(TheModule.getOrInsertComdat(".objc_init")); CallRuntimeFunction(B, "__objc_load", {InitStruct});; B.CreateRetVoid(); // Make sure that the optimisers don't delete this function. CGM.addCompilerUsedGlobal(LoadFunction); // FIXME: Currently ELF only! // We have to do this by hand, rather than with @llvm.ctors, so that the // linker can remove the duplicate invocations. auto *InitVar = new llvm::GlobalVariable(TheModule, LoadFunction->getType(), /*isConstant*/true, llvm::GlobalValue::LinkOnceAnyLinkage, LoadFunction, ".objc_ctor"); // Check that this hasn't been renamed. This shouldn't happen, because // this function should be called precisely once. assert(InitVar->getName() == ".objc_ctor"); InitVar->setSection(".ctors"); InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility); InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor")); CGM.addCompilerUsedGlobal(InitVar); for (auto *C : Categories) { auto *Cat = cast(C->stripPointerCasts()); Cat->setSection(CatSection); CGM.addUsedGlobal(Cat); } // Add a null value fore each special section so that we can always // guarantee that the _start and _stop symbols will exist and be // meaningful. auto createNullGlobal = [&](StringRef Name, ArrayRef Init, StringRef Section) { auto nullBuilder = builder.beginStruct(); for (auto *F : Init) nullBuilder.add(F); auto GV = nullBuilder.finishAndCreateGlobal(Name, CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); GV->setSection(Section); GV->setComdat(TheModule.getOrInsertComdat(Name)); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.addUsedGlobal(GV); return GV; }; createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr}, SelSection); if (Categories.empty()) createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr}, CatSection); if (!EmittedClass) { createNullGlobal(".objc_null_cls_init_ref", NULLPtr, ClsSection); createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr }, ClsRefSection); } if (!EmittedProtocol) createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr}, ProtocolSection); if (!EmittedProtocolRef) createNullGlobal(".objc_null_protocol_ref", {NULLPtr}, ProtocolRefSection); if (!ClassAliases.empty()) for (auto clsAlias : ClassAliases) createNullGlobal(std::string(".objc_class_alias") + clsAlias.second, { MakeConstantString(clsAlias.second), GetClassVar(clsAlias.first) }, ClassAliasSection); else createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr }, ClassAliasSection); if (ConstantStrings.empty()) { auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0); createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero, i32Zero, i32Zero, i32Zero, NULLPtr }, ConstantStringSection); } ConstantStrings.clear(); Categories.clear(); Classes.clear(); return nullptr;//CGObjCGNU::ModuleInitFunction(); } /// In the v2 ABI, ivar offset variables use the type encoding in their name /// to trigger linker failures if the types don't match. std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar) override { std::string TypeEncoding; CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding); // Prevent the @ from being interpreted as a symbol version. std::replace(TypeEncoding.begin(), TypeEncoding.end(), '@', '\1'); const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + '.' + Ivar->getNameAsString() + '.' + TypeEncoding; return Name; } llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) override { const std::string Name = GetIVarOffsetVariableName(Ivar->getContainingInterface(), Ivar); llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); if (!IvarOffsetPointer) IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, Name); CharUnits Align = CGM.getIntAlign(); llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(IvarOffsetPointer, Align); if (Offset->getType() != PtrDiffTy) Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy); return Offset; } void GenerateClass(const ObjCImplementationDecl *OID) override { ASTContext &Context = CGM.getContext(); // Get the class name ObjCInterfaceDecl *classDecl = const_cast(OID->getClassInterface()); std::string className = classDecl->getNameAsString(); auto *classNameConstant = MakeConstantString(className); ConstantInitBuilder builder(CGM); auto metaclassFields = builder.beginStruct(); // struct objc_class *isa; metaclassFields.addNullPointer(PtrTy); // struct objc_class *super_class; metaclassFields.addNullPointer(PtrTy); // const char *name; metaclassFields.add(classNameConstant); // long version; metaclassFields.addInt(LongTy, 0); // unsigned long info; // objc_class_flag_meta metaclassFields.addInt(LongTy, 1); // long instance_size; // Setting this to zero is consistent with the older ABI, but it might be // more sensible to set this to sizeof(struct objc_class) metaclassFields.addInt(LongTy, 0); // struct objc_ivar_list *ivars; metaclassFields.addNullPointer(PtrTy); // struct objc_method_list *methods // FIXME: Almost identical code is copied and pasted below for the // class, but refactoring it cleanly requires C++14 generic lambdas. if (OID->classmeth_begin() == OID->classmeth_end()) metaclassFields.addNullPointer(PtrTy); else { SmallVector ClassMethods; ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(), OID->classmeth_end()); metaclassFields.addBitCast( GenerateMethodList(className, "", ClassMethods, true), PtrTy); } // void *dtable; metaclassFields.addNullPointer(PtrTy); // IMP cxx_construct; metaclassFields.addNullPointer(PtrTy); // IMP cxx_destruct; metaclassFields.addNullPointer(PtrTy); // struct objc_class *subclass_list metaclassFields.addNullPointer(PtrTy); // struct objc_class *sibling_class metaclassFields.addNullPointer(PtrTy); // struct objc_protocol_list *protocols; metaclassFields.addNullPointer(PtrTy); // struct reference_list *extra_data; metaclassFields.addNullPointer(PtrTy); // long abi_version; metaclassFields.addInt(LongTy, 0); // struct objc_property_list *properties metaclassFields.add(GeneratePropertyList(OID, classDecl, /*isClassProperty*/true)); auto *metaclass = metaclassFields.finishAndCreateGlobal("._OBJC_METACLASS_" + className, CGM.getPointerAlign()); auto classFields = builder.beginStruct(); // struct objc_class *isa; classFields.add(metaclass); // struct objc_class *super_class; // Get the superclass name. const ObjCInterfaceDecl * SuperClassDecl = OID->getClassInterface()->getSuperClass(); if (SuperClassDecl) { auto SuperClassName = SymbolForClass(SuperClassDecl->getNameAsString()); llvm::Constant *SuperClass = TheModule.getNamedGlobal(SuperClassName); if (!SuperClass) { SuperClass = new llvm::GlobalVariable(TheModule, PtrTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, SuperClassName); } classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, PtrTy)); } else classFields.addNullPointer(PtrTy); // const char *name; classFields.add(classNameConstant); // long version; classFields.addInt(LongTy, 0); // unsigned long info; // !objc_class_flag_meta classFields.addInt(LongTy, 0); // long instance_size; int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); // Instance size is negative for classes that have not yet had their ivar // layout calculated. classFields.addInt(LongTy, 0 - (Context.getASTObjCImplementationLayout(OID).getSize().getQuantity() - superInstanceSize)); if (classDecl->all_declared_ivar_begin() == nullptr) classFields.addNullPointer(PtrTy); else { int ivar_count = 0; for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) ivar_count++; llvm::DataLayout td(&TheModule); // struct objc_ivar_list *ivars; ConstantInitBuilder b(CGM); auto ivarListBuilder = b.beginStruct(); // int count; ivarListBuilder.addInt(IntTy, ivar_count); // size_t size; llvm::StructType *ObjCIvarTy = llvm::StructType::get( PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, Int32Ty, Int32Ty); ivarListBuilder.addInt(SizeTy, td.getTypeSizeInBits(ObjCIvarTy) / CGM.getContext().getCharWidth()); // struct objc_ivar ivars[] auto ivarArrayBuilder = ivarListBuilder.beginArray(); CodeGenTypes &Types = CGM.getTypes(); for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { auto ivarTy = IVD->getType(); auto ivarBuilder = ivarArrayBuilder.beginStruct(); // const char *name; ivarBuilder.add(MakeConstantString(IVD->getNameAsString())); // const char *type; std::string TypeStr; //Context.getObjCEncodingForType(ivarTy, TypeStr, IVD, true); Context.getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, ivarTy, TypeStr, true); ivarBuilder.add(MakeConstantString(TypeStr)); // int *offset; uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset - superInstanceSize; llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); std::string OffsetName = GetIVarOffsetVariableName(classDecl, IVD); llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName); if (OffsetVar) OffsetVar->setInitializer(OffsetValue); else OffsetVar = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::ExternalLinkage, OffsetValue, OffsetName); auto ivarVisibility = (IVD->getAccessControl() == ObjCIvarDecl::Private || IVD->getAccessControl() == ObjCIvarDecl::Package || classDecl->getVisibility() == HiddenVisibility) ? llvm::GlobalValue::HiddenVisibility : llvm::GlobalValue::DefaultVisibility; OffsetVar->setVisibility(ivarVisibility); ivarBuilder.add(OffsetVar); // Ivar size ivarBuilder.addInt(Int32Ty, td.getTypeSizeInBits(Types.ConvertType(ivarTy)) / CGM.getContext().getCharWidth()); // Alignment will be stored as a base-2 log of the alignment. int align = llvm::Log2_32(Context.getTypeAlignInChars(ivarTy).getQuantity()); // Objects that require more than 2^64-byte alignment should be impossible! assert(align < 64); // uint32_t flags; // Bits 0-1 are ownership. // Bit 2 indicates an extended type encoding // Bits 3-8 contain log2(aligment) ivarBuilder.addInt(Int32Ty, (align << 3) | (1<<2) | FlagsForOwnership(ivarTy.getQualifiers().getObjCLifetime())); ivarBuilder.finishAndAddTo(ivarArrayBuilder); } ivarArrayBuilder.finishAndAddTo(ivarListBuilder); auto ivarList = ivarListBuilder.finishAndCreateGlobal(".objc_ivar_list", CGM.getPointerAlign(), /*constant*/ false, llvm::GlobalValue::PrivateLinkage); classFields.add(ivarList); } // struct objc_method_list *methods SmallVector InstanceMethods; InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(), OID->instmeth_end()); for (auto *propImpl : OID->property_impls()) if (propImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); auto addIfExists = [&](const ObjCMethodDecl* OMD) { if (OMD) InstanceMethods.push_back(OMD); }; addIfExists(prop->getGetterMethodDecl()); addIfExists(prop->getSetterMethodDecl()); } if (InstanceMethods.size() == 0) classFields.addNullPointer(PtrTy); else classFields.addBitCast( GenerateMethodList(className, "", InstanceMethods, false), PtrTy); // void *dtable; classFields.addNullPointer(PtrTy); // IMP cxx_construct; classFields.addNullPointer(PtrTy); // IMP cxx_destruct; classFields.addNullPointer(PtrTy); // struct objc_class *subclass_list classFields.addNullPointer(PtrTy); // struct objc_class *sibling_class classFields.addNullPointer(PtrTy); // struct objc_protocol_list *protocols; SmallVector Protocols; for (const auto *I : classDecl->protocols()) Protocols.push_back( llvm::ConstantExpr::getBitCast(GenerateProtocolRef(I), ProtocolPtrTy)); if (Protocols.empty()) classFields.addNullPointer(PtrTy); else classFields.add(GenerateProtocolList(Protocols)); // struct reference_list *extra_data; classFields.addNullPointer(PtrTy); // long abi_version; classFields.addInt(LongTy, 0); // struct objc_property_list *properties classFields.add(GeneratePropertyList(OID, classDecl)); auto *classStruct = classFields.finishAndCreateGlobal(SymbolForClass(className), CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); if (CGM.getTriple().isOSBinFormatCOFF()) { auto Storage = llvm::GlobalValue::DefaultStorageClass; if (OID->getClassInterface()->hasAttr()) Storage = llvm::GlobalValue::DLLImportStorageClass; else if (OID->getClassInterface()->hasAttr()) Storage = llvm::GlobalValue::DLLExportStorageClass; cast(classStruct)->setDLLStorageClass(Storage); } auto *classRefSymbol = GetClassVar(className); classRefSymbol->setSection(ClsRefSection); classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy)); // Resolve the class aliases, if they exist. // FIXME: Class pointer aliases shouldn't exist! if (ClassPtrAlias) { ClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(classStruct, IdTy)); ClassPtrAlias->eraseFromParent(); ClassPtrAlias = nullptr; } if (auto Placeholder = TheModule.getNamedGlobal(SymbolForClass(className))) if (Placeholder != classStruct) { Placeholder->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(classStruct, Placeholder->getType())); Placeholder->eraseFromParent(); classStruct->setName(SymbolForClass(className)); } if (MetaClassPtrAlias) { MetaClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(metaclass, IdTy)); MetaClassPtrAlias->eraseFromParent(); MetaClassPtrAlias = nullptr; } assert(classStruct->getName() == SymbolForClass(className)); auto classInitRef = new llvm::GlobalVariable(TheModule, classStruct->getType(), false, llvm::GlobalValue::ExternalLinkage, classStruct, "._OBJC_INIT_CLASS_" + className); classInitRef->setSection(ClsSection); CGM.addUsedGlobal(classInitRef); EmittedClass = true; } public: CGObjCGNUstep2(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10, 4, 2) { MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, PtrToObjCSuperTy, SelectorTy); // struct objc_property // { // const char *name; // const char *attributes; // const char *type; // SEL getter; // SEL setter; // } PropertyMetadataTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); } }; /// Support for the ObjFW runtime. class CGObjCObjFW: public CGObjCGNU { protected: /// The GCC ABI message lookup function. Returns an IMP pointing to the /// method implementation for this message. LazyRuntimeFunction MsgLookupFn; /// stret lookup function. While this does not seem to make sense at the /// first look, this is required to call the correct forwarding function. LazyRuntimeFunction MsgLookupFnSRet; /// The GCC ABI superclass message lookup function. Takes a pointer to a /// structure describing the receiver and the class, and a selector as /// arguments. Returns the IMP for the corresponding method. LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet; llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, llvm::Value *cmd, llvm::MDNode *node, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *args[] = { EnforceType(Builder, Receiver, IdTy), EnforceType(Builder, cmd, SelectorTy) }; llvm::CallSite imp; if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFnSRet, args); else imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args); imp->setMetadata(msgSendMDKind, node); return imp.getInstruction(); } llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = { EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd, }; if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFnSRet, lookupArgs); else return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } llvm::Value *GetClassNamed(CodeGenFunction &CGF, const std::string &Name, bool isWeak) override { if (isWeak) return CGObjCGNU::GetClassNamed(CGF, Name, isWeak); EmitClassRef(Name); std::string SymbolName = "_OBJC_CLASS_" + Name; llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(SymbolName); if (!ClassSymbol) ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, SymbolName); return ClassSymbol; } public: CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) { // IMP objc_msg_lookup(id, SEL); MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy); MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy, SelectorTy); // IMP objc_msg_lookup_super(struct objc_super*, SEL); MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, PtrToObjCSuperTy, SelectorTy); MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy, PtrToObjCSuperTy, SelectorTy); } }; } // end anonymous namespace /// Emits a reference to a dummy variable which is emitted with each class. /// This ensures that a linker error will be generated when trying to link /// together modules where a referenced class is not defined. void CGObjCGNU::EmitClassRef(const std::string &className) { std::string symbolRef = "__objc_class_ref_" + className; // Don't emit two copies of the same symbol if (TheModule.getGlobalVariable(symbolRef)) return; std::string symbolName = "__objc_class_name_" + className; llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName); if (!ClassSymbol) { ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, symbolName); } new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true, llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, unsigned protocolClassVersion, unsigned classABI) : CGObjCRuntime(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()), ClassPtrAlias(nullptr), MetaClassPtrAlias(nullptr), RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) { msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); CodeGenTypes &Types = CGM.getTypes(); IntTy = cast( Types.ConvertType(CGM.getContext().IntTy)); LongTy = cast( Types.ConvertType(CGM.getContext().LongTy)); SizeTy = cast( Types.ConvertType(CGM.getContext().getSizeType())); PtrDiffTy = cast( Types.ConvertType(CGM.getContext().getPointerDiffType())); BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Int8Ty = llvm::Type::getInt8Ty(VMContext); // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); ProtocolPtrTy = llvm::PointerType::getUnqual( Types.ConvertType(CGM.getContext().getObjCProtoType())); Zeros[0] = llvm::ConstantInt::get(LongTy, 0); Zeros[1] = Zeros[0]; NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // Get the selector Type. QualType selTy = CGM.getContext().getObjCSelType(); if (QualType() == selTy) { SelectorTy = PtrToInt8Ty; } else { SelectorTy = cast(CGM.getTypes().ConvertType(selTy)); } PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; Int32Ty = llvm::Type::getInt32Ty(VMContext); Int64Ty = llvm::Type::getInt64Ty(VMContext); IntPtrTy = CGM.getDataLayout().getPointerSizeInBits() == 32 ? Int32Ty : Int64Ty; // Object type QualType UnqualIdTy = CGM.getContext().getObjCIdType(); ASTIdTy = CanQualType(); if (UnqualIdTy != QualType()) { ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy); IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); } else { IdTy = PtrToInt8Ty; } PtrToIdTy = llvm::PointerType::getUnqual(IdTy); ProtocolTy = llvm::StructType::get(IdTy, PtrToInt8Ty, // name PtrToInt8Ty, // protocols PtrToInt8Ty, // instance methods PtrToInt8Ty, // class methods PtrToInt8Ty, // optional instance methods PtrToInt8Ty, // optional class methods PtrToInt8Ty, // properties PtrToInt8Ty);// optional properties // struct objc_property_gsv1 // { // const char *name; // char attributes; // char attributes2; // char unused1; // char unused2; // const char *getter_name; // const char *getter_types; // const char *setter_name; // const char *setter_types; // } PropertyMetadataTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); ObjCSuperTy = llvm::StructType::get(IdTy, IdTy); PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy); llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // void objc_exception_throw(id); ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); // int objc_sync_enter(id); SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy); // int objc_sync_exit(id); SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy); // void objc_enumerationMutation (id) EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy); // id objc_getProperty(id, SEL, ptrdiff_t, BOOL) GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy, PtrDiffTy, BoolTy); // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL) SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy, PtrDiffTy, IdTy, BoolTy, BoolTy); // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy, PtrDiffTy, BoolTy, BoolTy); // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy, PtrDiffTy, BoolTy, BoolTy); // IMP type llvm::Type *IMPArgs[] = { IdTy, SelectorTy }; IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs, true)); const LangOptions &Opts = CGM.getLangOpts(); if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount) RuntimeVersion = 10; // Don't bother initialising the GC stuff unless we're compiling in GC mode if (Opts.getGC() != LangOptions::NonGC) { // This is a bit of an hack. We should sort this out by having a proper // CGObjCGNUstep subclass for GC, but we may want to really support the old // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now // Get selectors needed in GC mode RetainSel = GetNullarySelector("retain", CGM.getContext()); ReleaseSel = GetNullarySelector("release", CGM.getContext()); AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext()); // Get functions needed in GC mode // id objc_assign_ivar(id, id, ptrdiff_t); IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy); // id objc_assign_strongCast (id, id*) StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy, PtrToIdTy); // id objc_assign_global(id, id*); GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy); // id objc_assign_weak(id, id*); WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy); // id objc_read_weak(id*); WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy); // void *objc_memmove_collectable(void*, void *, size_t); MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy, SizeTy); } } llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF, const std::string &Name, bool isWeak) { llvm::Constant *ClassName = MakeConstantString(Name); // With the incompatible ABI, this will need to be replaced with a direct // reference to the class symbol. For the compatible nonfragile ABI we are // still performing this lookup at run time but emitting the symbol for the // class externally so that we can make the switch later. // // Libobjc2 contains an LLVM pass that replaces calls to objc_lookup_class // with memoized versions or with static references if it's safe to do so. if (!isWeak) EmitClassRef(Name); llvm::Constant *ClassLookupFn = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true), "objc_lookup_class"); return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName); } // This has to perform the lookup every time, since posing and related // techniques can modify the name -> class mapping. llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF, const ObjCInterfaceDecl *OID) { auto *Value = GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported()); if (auto *ClassSymbol = dyn_cast(Value)) CGM.setGVProperties(ClassSymbol, OID); return Value; } llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) { auto *Value = GetClassNamed(CGF, "NSAutoreleasePool", false); if (CGM.getTriple().isOSBinFormatCOFF()) { if (auto *ClassSymbol = dyn_cast(Value)) { IdentifierInfo &II = CGF.CGM.getContext().Idents.get("NSAutoreleasePool"); TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); const VarDecl *VD = nullptr; for (const auto &Result : DC->lookup(&II)) if ((VD = dyn_cast(Result))) break; CGM.setGVProperties(ClassSymbol, VD); } } return Value; } llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel, const std::string &TypeEncoding) { SmallVectorImpl &Types = SelectorTable[Sel]; llvm::GlobalAlias *SelValue = nullptr; for (SmallVectorImpl::iterator i = Types.begin(), e = Types.end() ; i!=e ; i++) { if (i->first == TypeEncoding) { SelValue = i->second; break; } } if (!SelValue) { SelValue = llvm::GlobalAlias::create( SelectorTy->getElementType(), 0, llvm::GlobalValue::PrivateLinkage, ".objc_selector_" + Sel.getAsString(), &TheModule); Types.emplace_back(TypeEncoding, SelValue); } return SelValue; } Address CGObjCGNU::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) { llvm::Value *SelValue = GetSelector(CGF, Sel); // Store it to a temporary. Does this satisfy the semantics of // GetAddrOfSelector? Hopefully. Address tmp = CGF.CreateTempAlloca(SelValue->getType(), CGF.getPointerAlign()); CGF.Builder.CreateStore(SelValue, tmp); return tmp; } llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel) { return GetSelector(CGF, Sel, std::string()); } llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl *Method) { std::string SelTypes = CGM.getContext().getObjCEncodingForMethodDecl(Method); return GetSelector(CGF, Method->getSelector(), SelTypes); } llvm::Constant *CGObjCGNU::GetEHType(QualType T) { if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { // With the old ABI, there was only one kind of catchall, which broke // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as // a pointer indicating object catchalls, and NULL to indicate real // catchalls if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { return MakeConstantString("@id"); } else { return nullptr; } } // All other types should be Objective-C interface pointer types. const ObjCObjectPointerType *OPT = T->getAs(); assert(OPT && "Invalid @catch type."); const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface(); assert(IDecl && "Invalid @catch type."); return MakeConstantString(IDecl->getIdentifier()->getName()); } llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) { if (!CGM.getLangOpts().CPlusPlus) return CGObjCGNU::GetEHType(T); // For Objective-C++, we want to provide the ability to catch both C++ and // Objective-C objects in the same function. // There's a particular fixed type info for 'id'. if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { llvm::Constant *IDEHType = CGM.getModule().getGlobalVariable("__objc_id_type_info"); if (!IDEHType) IDEHType = new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty, false, llvm::GlobalValue::ExternalLinkage, nullptr, "__objc_id_type_info"); return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty); } const ObjCObjectPointerType *PT = T->getAs(); assert(PT && "Invalid @catch type."); const ObjCInterfaceType *IT = PT->getInterfaceType(); assert(IT && "Invalid @catch type."); std::string className = IT->getDecl()->getIdentifier()->getName(); std::string typeinfoName = "__objc_eh_typeinfo_" + className; // Return the existing typeinfo if it exists llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName); if (typeinfo) return llvm::ConstantExpr::getBitCast(typeinfo, PtrToInt8Ty); // Otherwise create it. // vtable for gnustep::libobjc::__objc_class_type_info // It's quite ugly hard-coding this. Ideally we'd generate it using the host // platform's name mangling. const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE"; auto *Vtable = TheModule.getGlobalVariable(vtableName); if (!Vtable) { Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true, llvm::GlobalValue::ExternalLinkage, nullptr, vtableName); } llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2); auto *BVtable = llvm::ConstantExpr::getBitCast( llvm::ConstantExpr::getGetElementPtr(Vtable->getValueType(), Vtable, Two), PtrToInt8Ty); llvm::Constant *typeName = ExportUniqueString(className, "__objc_eh_typename_"); ConstantInitBuilder builder(CGM); auto fields = builder.beginStruct(); fields.add(BVtable); fields.add(typeName); llvm::Constant *TI = fields.finishAndCreateGlobal("__objc_eh_typeinfo_" + className, CGM.getPointerAlign(), /*constant*/ false, llvm::GlobalValue::LinkOnceODRLinkage); return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty); } /// Generate an NSConstantString object. ConstantAddress CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { std::string Str = SL->getString().str(); CharUnits Align = CGM.getPointerAlign(); // Look for an existing one llvm::StringMap::iterator old = ObjCStrings.find(Str); if (old != ObjCStrings.end()) return ConstantAddress(old->getValue(), Align); StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass; if (StringClass.empty()) StringClass = "NSConstantString"; std::string Sym = "_OBJC_CLASS_"; Sym += StringClass; llvm::Constant *isa = TheModule.getNamedGlobal(Sym); if (!isa) isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false, llvm::GlobalValue::ExternalWeakLinkage, nullptr, Sym); else if (isa->getType() != PtrToIdTy) isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); ConstantInitBuilder Builder(CGM); auto Fields = Builder.beginStruct(); Fields.add(isa); Fields.add(MakeConstantString(Str)); Fields.addInt(IntTy, Str.size()); llvm::Constant *ObjCStr = Fields.finishAndCreateGlobal(".objc_str", Align); ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty); ObjCStrings[Str] = ObjCStr; ConstantStrings.push_back(ObjCStr); return ConstantAddress(ObjCStr, Align); } ///Generates a message send where the super is the receiver. This is a message ///send to self with special delivery semantics indicating which class's method ///should be called. RValue CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, const ObjCInterfaceDecl *Class, bool isCategoryImpl, llvm::Value *Receiver, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { CGBuilderTy &Builder = CGF.Builder; if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(nullptr); } } llvm::Value *cmd = GetSelector(CGF, Sel); CallArgList ActualArgs; ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy); ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); llvm::Value *ReceiverClass = nullptr; bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2); if (isV2ABI) { ReceiverClass = GetClassNamed(CGF, Class->getSuperClass()->getNameAsString(), /*isWeak*/false); if (IsClassMessage) { // Load the isa pointer of the superclass is this is a class method. ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual(IdTy)); ReceiverClass = Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign()); } ReceiverClass = EnforceType(Builder, ReceiverClass, IdTy); } else { if (isCategoryImpl) { llvm::Constant *classLookupFunction = nullptr; if (IsClassMessage) { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, PtrTy, true), "objc_get_meta_class"); } else { classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, PtrTy, true), "objc_get_class"); } ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); } else { // Set up global aliases for the metaclass or class pointer if they do not // already exist. These will are forward-references which will be set to // pointers to the class and metaclass structure created for the runtime // load function. To send a message to super, we look up the value of the // super_class pointer from either the class or metaclass structure. if (IsClassMessage) { if (!MetaClassPtrAlias) { MetaClassPtrAlias = llvm::GlobalAlias::create( IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule); } ReceiverClass = MetaClassPtrAlias; } else { if (!ClassPtrAlias) { ClassPtrAlias = llvm::GlobalAlias::create( IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage, ".objc_class_ref" + Class->getNameAsString(), &TheModule); } ReceiverClass = ClassPtrAlias; } } // Cast the pointer to a simplified version of the class structure llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy); ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual(CastTy)); // Get the superclass pointer ReceiverClass = Builder.CreateStructGEP(CastTy, ReceiverClass, 1); // Load the superclass pointer ReceiverClass = Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign()); } // Construct the structure used to look up the IMP llvm::StructType *ObjCSuperTy = llvm::StructType::get(Receiver->getType(), IdTy); Address ObjCSuper = CGF.CreateTempAlloca(ObjCSuperTy, CGF.getPointerAlign()); Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero())); Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize())); ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy); // Get the IMP llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI); imp = EnforceType(Builder, imp, MSI.MessengerType); llvm::Metadata *impMD[] = { llvm::MDString::get(VMContext, Sel.getAsString()), llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( llvm::Type::getInt1Ty(VMContext), IsClassMessage))}; llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); CGCallee callee(CGCalleeInfo(), imp); llvm::Instruction *call; RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); call->setMetadata(msgSendMDKind, node); return msgRet; } /// Generate code for a message send expression. RValue CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Receiver, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { CGBuilderTy &Builder = CGF.Builder; // Strip out message sends to retain / release in GC mode if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(EnforceType(Builder, Receiver, CGM.getTypes().ConvertType(ResultType))); } if (Sel == ReleaseSel) { return RValue::get(nullptr); } } // If the return type is something that goes in an integer register, the // runtime will handle 0 returns. For other cases, we fill in the 0 value // ourselves. // // The language spec says the result of this kind of message send is // undefined, but lots of people seem to have forgotten to read that // paragraph and insist on sending messages to nil that have structure // returns. With GCC, this generates a random return value (whatever happens // to be on the stack / in those registers at the time) on most platforms, // and generates an illegal instruction trap on SPARC. With LLVM it corrupts // the stack. bool isPointerSizedReturn = (ResultType->isAnyPointerType() || ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType()); llvm::BasicBlock *startBB = nullptr; llvm::BasicBlock *messageBB = nullptr; llvm::BasicBlock *continueBB = nullptr; if (!isPointerSizedReturn) { startBB = Builder.GetInsertBlock(); messageBB = CGF.createBasicBlock("msgSend"); continueBB = CGF.createBasicBlock("continue"); llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, llvm::Constant::getNullValue(Receiver->getType())); Builder.CreateCondBr(isNil, continueBB, messageBB); CGF.EmitBlock(messageBB); } IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) cmd = GetSelector(CGF, Method); else cmd = GetSelector(CGF, Sel); cmd = EnforceType(Builder, cmd, SelectorTy); Receiver = EnforceType(Builder, Receiver, IdTy); llvm::Metadata *impMD[] = { llvm::MDString::get(VMContext, Sel.getAsString()), llvm::MDString::get(VMContext, Class ? Class->getNameAsString() : ""), llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( llvm::Type::getInt1Ty(VMContext), Class != nullptr))}; llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); CallArgList ActualArgs; ActualArgs.add(RValue::get(Receiver), ASTIdTy); ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); // Get the IMP to call llvm::Value *imp; // If we have non-legacy dispatch specified, we try using the objc_msgSend() // functions. These are not supported on all platforms (or all runtimes on a // given platform), so we switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { case CodeGenOptions::Legacy: imp = LookupIMP(CGF, Receiver, cmd, node, MSI); break; case CodeGenOptions::Mixed: case CodeGenOptions::NonLegacy: if (CGM.ReturnTypeUsesFPRet(ResultType)) { imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend_fpret"); } else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) { // The actual types here don't matter - we're going to bitcast the // function anyway imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend_stret"); } else { imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend"); } } // Reset the receiver in case the lookup modified it ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy); imp = EnforceType(Builder, imp, MSI.MessengerType); llvm::Instruction *call; CGCallee callee(CGCalleeInfo(), imp); RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); call->setMetadata(msgSendMDKind, node); if (!isPointerSizedReturn) { messageBB = CGF.Builder.GetInsertBlock(); CGF.Builder.CreateBr(continueBB); CGF.EmitBlock(continueBB); if (msgRet.isScalar()) { llvm::Value *v = msgRet.getScalarVal(); llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); phi->addIncoming(v, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); msgRet = RValue::get(phi); } else if (msgRet.isAggregate()) { Address v = msgRet.getAggregateAddress(); llvm::PHINode *phi = Builder.CreatePHI(v.getType(), 2); llvm::Type *RetTy = v.getElementType(); Address NullVal = CGF.CreateTempAlloca(RetTy, v.getAlignment(), "null"); CGF.InitTempAlloca(NullVal, llvm::Constant::getNullValue(RetTy)); phi->addIncoming(v.getPointer(), messageBB); phi->addIncoming(NullVal.getPointer(), startBB); msgRet = RValue::getAggregate(Address(phi, v.getAlignment())); } else /* isComplex() */ { std::pair v = msgRet.getComplexVal(); llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2); phi->addIncoming(v.first, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), startBB); llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2); phi2->addIncoming(v.second, messageBB); phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), startBB); msgRet = RValue::getComplex(phi, phi2); } } return msgRet; } /// Generates a MethodList. Used in construction of a objc_class and /// objc_category structures. llvm::Constant *CGObjCGNU:: GenerateMethodList(StringRef ClassName, StringRef CategoryName, ArrayRef Methods, bool isClassMethodList) { if (Methods.empty()) return NULLPtr; ConstantInitBuilder Builder(CGM); auto MethodList = Builder.beginStruct(); MethodList.addNullPointer(CGM.Int8PtrTy); MethodList.addInt(Int32Ty, Methods.size()); // Get the method structure type. llvm::StructType *ObjCMethodTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types IMPTy // Method pointer }); bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2); if (isV2ABI) { // size_t size; llvm::DataLayout td(&TheModule); MethodList.addInt(SizeTy, td.getTypeSizeInBits(ObjCMethodTy) / CGM.getContext().getCharWidth()); ObjCMethodTy = llvm::StructType::get(CGM.getLLVMContext(), { IMPTy, // Method pointer PtrToInt8Ty, // Selector PtrToInt8Ty // Extended type encoding }); } else { ObjCMethodTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types IMPTy // Method pointer }); } auto MethodArray = MethodList.beginArray(); ASTContext &Context = CGM.getContext(); for (const auto *OMD : Methods) { llvm::Constant *FnPtr = TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName, OMD->getSelector(), isClassMethodList)); assert(FnPtr && "Can't generate metadata for method that doesn't exist"); auto Method = MethodArray.beginStruct(ObjCMethodTy); if (isV2ABI) { Method.addBitCast(FnPtr, IMPTy); Method.add(GetConstantSelector(OMD->getSelector(), Context.getObjCEncodingForMethodDecl(OMD))); Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD, true))); } else { Method.add(MakeConstantString(OMD->getSelector().getAsString())); Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD))); Method.addBitCast(FnPtr, IMPTy); } Method.finishAndAddTo(MethodArray); } MethodArray.finishAndAddTo(MethodList); // Create an instance of the structure return MethodList.finishAndCreateGlobal(".objc_method_list", CGM.getPointerAlign()); } /// Generates an IvarList. Used in construction of a objc_class. llvm::Constant *CGObjCGNU:: GenerateIvarList(ArrayRef IvarNames, ArrayRef IvarTypes, ArrayRef IvarOffsets, ArrayRef IvarAlign, ArrayRef IvarOwnership) { if (IvarNames.empty()) return NULLPtr; ConstantInitBuilder Builder(CGM); // Structure containing array count followed by array. auto IvarList = Builder.beginStruct(); IvarList.addInt(IntTy, (int)IvarNames.size()); // Get the ivar structure type. llvm::StructType *ObjCIvarTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy); // Array of ivar structures. auto Ivars = IvarList.beginArray(ObjCIvarTy); for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) { auto Ivar = Ivars.beginStruct(ObjCIvarTy); Ivar.add(IvarNames[i]); Ivar.add(IvarTypes[i]); Ivar.add(IvarOffsets[i]); Ivar.finishAndAddTo(Ivars); } Ivars.finishAndAddTo(IvarList); // Create an instance of the structure return IvarList.finishAndCreateGlobal(".objc_ivar_list", CGM.getPointerAlign()); } /// Generate a class structure llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, unsigned info, const char *Name, llvm::Constant *Version, llvm::Constant *InstanceSize, llvm::Constant *IVars, llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, llvm::Constant *Properties, llvm::Constant *StrongIvarBitmap, llvm::Constant *WeakIvarBitmap, bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. // // Fields marked New ABI are part of the GNUstep runtime. We emit them // anyway; the classes will still work with the GNU runtime, they will just // be ignored. llvm::StructType *ClassTy = llvm::StructType::get( PtrToInt8Ty, // isa PtrToInt8Ty, // super_class PtrToInt8Ty, // name LongTy, // version LongTy, // info LongTy, // instance_size IVars->getType(), // ivars Methods->getType(), // methods // These are all filled in by the runtime, so we pretend PtrTy, // dtable PtrTy, // subclass_list PtrTy, // sibling_class PtrTy, // protocols PtrTy, // gc_object_type // New ABI: LongTy, // abi_version IvarOffsets->getType(), // ivar_offsets Properties->getType(), // properties IntPtrTy, // strong_pointers IntPtrTy // weak_pointers ); ConstantInitBuilder Builder(CGM); auto Elements = Builder.beginStruct(ClassTy); // Fill in the structure // isa Elements.addBitCast(MetaClass, PtrToInt8Ty); // super_class Elements.add(SuperClass); // name Elements.add(MakeConstantString(Name, ".class_name")); // version Elements.addInt(LongTy, 0); // info Elements.addInt(LongTy, info); // instance_size if (isMeta) { llvm::DataLayout td(&TheModule); Elements.addInt(LongTy, td.getTypeSizeInBits(ClassTy) / CGM.getContext().getCharWidth()); } else Elements.add(InstanceSize); // ivars Elements.add(IVars); // methods Elements.add(Methods); // These are all filled in by the runtime, so we pretend // dtable Elements.add(NULLPtr); // subclass_list Elements.add(NULLPtr); // sibling_class Elements.add(NULLPtr); // protocols Elements.addBitCast(Protocols, PtrTy); // gc_object_type Elements.add(NULLPtr); // abi_version Elements.addInt(LongTy, ClassABIVersion); // ivar_offsets Elements.add(IvarOffsets); // properties Elements.add(Properties); // strong_pointers Elements.add(StrongIvarBitmap); // weak_pointers Elements.add(WeakIvarBitmap); // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. We may already have some weak references to // this, so check and fix them properly. std::string ClassSym((isMeta ? "_OBJC_METACLASS_": "_OBJC_CLASS_") + std::string(Name)); llvm::GlobalVariable *ClassRef = TheModule.getNamedGlobal(ClassSym); llvm::Constant *Class = Elements.finishAndCreateGlobal(ClassSym, CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); if (ClassRef) { ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class, ClassRef->getType())); ClassRef->removeFromParent(); Class->setName(ClassSym); } return Class; } llvm::Constant *CGObjCGNU:: GenerateProtocolMethodList(ArrayRef Methods) { // Get the method structure type. llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty }); ASTContext &Context = CGM.getContext(); ConstantInitBuilder Builder(CGM); auto MethodList = Builder.beginStruct(); MethodList.addInt(IntTy, Methods.size()); auto MethodArray = MethodList.beginArray(ObjCMethodDescTy); for (auto *M : Methods) { auto Method = MethodArray.beginStruct(ObjCMethodDescTy); Method.add(MakeConstantString(M->getSelector().getAsString())); Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(M))); Method.finishAndAddTo(MethodArray); } MethodArray.finishAndAddTo(MethodList); return MethodList.finishAndCreateGlobal(".objc_method_list", CGM.getPointerAlign()); } // Create the protocol list structure used in classes, categories and so on llvm::Constant * CGObjCGNU::GenerateProtocolList(ArrayRef Protocols) { ConstantInitBuilder Builder(CGM); auto ProtocolList = Builder.beginStruct(); ProtocolList.add(NULLPtr); ProtocolList.addInt(LongTy, Protocols.size()); auto Elements = ProtocolList.beginArray(PtrToInt8Ty); for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); iter != endIter ; iter++) { llvm::Constant *protocol = nullptr; llvm::StringMap::iterator value = ExistingProtocols.find(*iter); if (value == ExistingProtocols.end()) { protocol = GenerateEmptyProtocol(*iter); } else { protocol = value->getValue(); } Elements.addBitCast(protocol, PtrToInt8Ty); } Elements.finishAndAddTo(ProtocolList); return ProtocolList.finishAndCreateGlobal(".objc_protocol_list", CGM.getPointerAlign()); } llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) { llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()]; if (!protocol) GenerateProtocol(PD); llvm::Type *T = CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } llvm::Constant * CGObjCGNU::GenerateEmptyProtocol(StringRef ProtocolName) { llvm::Constant *ProtocolList = GenerateProtocolList({}); llvm::Constant *MethodList = GenerateProtocolMethodList({}); MethodList = llvm::ConstantExpr::getBitCast(MethodList, PtrToInt8Ty); // Protocols are objects containing lists of the methods implemented and // protocols adopted. ConstantInitBuilder Builder(CGM); auto Elements = Builder.beginStruct(); // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. Elements.add(llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.add(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.add(ProtocolList); /* .protocol_list */ Elements.add(MethodList); /* .instance_methods */ Elements.add(MethodList); /* .class_methods */ Elements.add(MethodList); /* .optional_instance_methods */ Elements.add(MethodList); /* .optional_class_methods */ Elements.add(NULLPtr); /* .properties */ Elements.add(NULLPtr); /* .optional_properties */ return Elements.finishAndCreateGlobal(SymbolForProtocol(ProtocolName), CGM.getPointerAlign()); } void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { std::string ProtocolName = PD->getNameAsString(); // Use the protocol definition, if there is one. if (const ObjCProtocolDecl *Def = PD->getDefinition()) PD = Def; SmallVector Protocols; for (const auto *PI : PD->protocols()) Protocols.push_back(PI->getNameAsString()); SmallVector InstanceMethods; SmallVector OptionalInstanceMethods; for (const auto *I : PD->instance_methods()) if (I->isOptional()) OptionalInstanceMethods.push_back(I); else InstanceMethods.push_back(I); // Collect information about class methods: SmallVector ClassMethods; SmallVector OptionalClassMethods; for (const auto *I : PD->class_methods()) if (I->isOptional()) OptionalClassMethods.push_back(I); else ClassMethods.push_back(I); llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); llvm::Constant *InstanceMethodList = GenerateProtocolMethodList(InstanceMethods); llvm::Constant *ClassMethodList = GenerateProtocolMethodList(ClassMethods); llvm::Constant *OptionalInstanceMethodList = GenerateProtocolMethodList(OptionalInstanceMethods); llvm::Constant *OptionalClassMethodList = GenerateProtocolMethodList(OptionalClassMethods); // Property metadata: name, attributes, isSynthesized, setter name, setter // types, getter name, getter types. // The isSynthesized value is always set to 0 in a protocol. It exists to // simplify the runtime library by allowing it to use the same data // structures for protocol metadata everywhere. llvm::Constant *PropertyList = GeneratePropertyList(nullptr, PD, false, false); llvm::Constant *OptionalPropertyList = GeneratePropertyList(nullptr, PD, false, true); // Protocols are objects containing lists of the methods implemented and // protocols adopted. // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. ConstantInitBuilder Builder(CGM); auto Elements = Builder.beginStruct(); Elements.add( llvm::ConstantExpr::getIntToPtr( llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); Elements.add(MakeConstantString(ProtocolName)); Elements.add(ProtocolList); Elements.add(InstanceMethodList); Elements.add(ClassMethodList); Elements.add(OptionalInstanceMethodList); Elements.add(OptionalClassMethodList); Elements.add(PropertyList); Elements.add(OptionalPropertyList); ExistingProtocols[ProtocolName] = llvm::ConstantExpr::getBitCast( Elements.finishAndCreateGlobal(".objc_protocol", CGM.getPointerAlign()), IdTy); } void CGObjCGNU::GenerateProtocolHolderCategory() { // Collect information about instance methods ConstantInitBuilder Builder(CGM); auto Elements = Builder.beginStruct(); const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; const std::string CategoryName = "AnotherHack"; Elements.add(MakeConstantString(CategoryName)); Elements.add(MakeConstantString(ClassName)); // Instance method list Elements.addBitCast(GenerateMethodList( ClassName, CategoryName, {}, false), PtrTy); // Class method list Elements.addBitCast(GenerateMethodList( ClassName, CategoryName, {}, true), PtrTy); // Protocol list ConstantInitBuilder ProtocolListBuilder(CGM); auto ProtocolList = ProtocolListBuilder.beginStruct(); ProtocolList.add(NULLPtr); ProtocolList.addInt(LongTy, ExistingProtocols.size()); auto ProtocolElements = ProtocolList.beginArray(PtrTy); for (auto iter = ExistingProtocols.begin(), endIter = ExistingProtocols.end(); iter != endIter ; iter++) { ProtocolElements.addBitCast(iter->getValue(), PtrTy); } ProtocolElements.finishAndAddTo(ProtocolList); Elements.addBitCast( ProtocolList.finishAndCreateGlobal(".objc_protocol_list", CGM.getPointerAlign()), PtrTy); Categories.push_back(llvm::ConstantExpr::getBitCast( Elements.finishAndCreateGlobal("", CGM.getPointerAlign()), PtrTy)); } /// Libobjc2 uses a bitfield representation where small(ish) bitfields are /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 /// bits set to their values, LSB first, while larger ones are stored in a /// structure of this / form: /// /// struct { int32_t length; int32_t values[length]; }; /// /// The values in the array are stored in host-endian format, with the least /// significant bit being assumed to come first in the bitfield. Therefore, a /// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a /// bitfield / with the 63rd bit set will be 1<<64. llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef bits) { int bitCount = bits.size(); int ptrBits = CGM.getDataLayout().getPointerSizeInBits(); if (bitCount < ptrBits) { uint64_t val = 1; for (int i=0 ; i values; int v=0; while (v < bitCount) { int32_t word = 0; for (int i=0 ; (i<32) && (vgetClassInterface(); std::string ClassName = Class->getNameAsString(); std::string CategoryName = OCD->getNameAsString(); // Collect the names of referenced protocols SmallVector Protocols; const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl(); const ObjCList &Protos = CatDecl->getReferencedProtocols(); for (ObjCList::iterator I = Protos.begin(), E = Protos.end(); I != E; ++I) Protocols.push_back((*I)->getNameAsString()); ConstantInitBuilder Builder(CGM); auto Elements = Builder.beginStruct(); Elements.add(MakeConstantString(CategoryName)); Elements.add(MakeConstantString(ClassName)); // Instance method list SmallVector InstanceMethods; InstanceMethods.insert(InstanceMethods.begin(), OCD->instmeth_begin(), OCD->instmeth_end()); Elements.addBitCast( GenerateMethodList(ClassName, CategoryName, InstanceMethods, false), PtrTy); // Class method list SmallVector ClassMethods; ClassMethods.insert(ClassMethods.begin(), OCD->classmeth_begin(), OCD->classmeth_end()); Elements.addBitCast( GenerateMethodList(ClassName, CategoryName, ClassMethods, true), PtrTy); // Protocol list Elements.addBitCast(GenerateProtocolList(Protocols), PtrTy); if (isRuntime(ObjCRuntime::GNUstep, 2)) { const ObjCCategoryDecl *Category = Class->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { // Instance properties Elements.addBitCast(GeneratePropertyList(OCD, Category, false), PtrTy); // Class properties Elements.addBitCast(GeneratePropertyList(OCD, Category, true), PtrTy); } else { Elements.addNullPointer(PtrTy); Elements.addNullPointer(PtrTy); } } Categories.push_back(llvm::ConstantExpr::getBitCast( Elements.finishAndCreateGlobal( std::string(".objc_category_")+ClassName+CategoryName, CGM.getPointerAlign()), PtrTy)); } llvm::Constant *CGObjCGNU::GeneratePropertyList(const Decl *Container, const ObjCContainerDecl *OCD, bool isClassProperty, bool protocolOptionalProperties) { SmallVector Properties; llvm::SmallPtrSet PropertySet; bool isProtocol = isa(OCD); ASTContext &Context = CGM.getContext(); std::function collectProtocolProperties = [&](const ObjCProtocolDecl *Proto) { for (const auto *P : Proto->protocols()) collectProtocolProperties(P); for (const auto *PD : Proto->properties()) { if (isClassProperty != PD->isClassProperty()) continue; // Skip any properties that are declared in protocols that this class // conforms to but are not actually implemented by this class. if (!isProtocol && !Context.getObjCPropertyImplDeclForPropertyDecl(PD, Container)) continue; if (!PropertySet.insert(PD->getIdentifier()).second) continue; Properties.push_back(PD); } }; if (const ObjCInterfaceDecl *OID = dyn_cast(OCD)) for (const ObjCCategoryDecl *ClassExt : OID->known_extensions()) for (auto *PD : ClassExt->properties()) { if (isClassProperty != PD->isClassProperty()) continue; PropertySet.insert(PD->getIdentifier()); Properties.push_back(PD); } for (const auto *PD : OCD->properties()) { if (isClassProperty != PD->isClassProperty()) continue; // If we're generating a list for a protocol, skip optional / required ones // when generating the other list. if (isProtocol && (protocolOptionalProperties != PD->isOptional())) continue; // Don't emit duplicate metadata for properties that were already in a // class extension. if (!PropertySet.insert(PD->getIdentifier()).second) continue; Properties.push_back(PD); } if (const ObjCInterfaceDecl *OID = dyn_cast(OCD)) for (const auto *P : OID->all_referenced_protocols()) collectProtocolProperties(P); else if (const ObjCCategoryDecl *CD = dyn_cast(OCD)) for (const auto *P : CD->protocols()) collectProtocolProperties(P); auto numProperties = Properties.size(); if (numProperties == 0) return NULLPtr; ConstantInitBuilder builder(CGM); auto propertyList = builder.beginStruct(); auto properties = PushPropertyListHeader(propertyList, numProperties); // Add all of the property methods need adding to the method list and to the // property metadata list. for (auto *property : Properties) { bool isSynthesized = false; bool isDynamic = false; if (!isProtocol) { auto *propertyImpl = Context.getObjCPropertyImplDeclForPropertyDecl(property, Container); if (propertyImpl) { isSynthesized = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); isDynamic = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); } } PushProperty(properties, property, Container, isSynthesized, isDynamic); } properties.finishAndAddTo(propertyList); return propertyList.finishAndCreateGlobal(".objc_property_list", CGM.getPointerAlign()); } void CGObjCGNU::RegisterAlias(const ObjCCompatibleAliasDecl *OAD) { // Get the class declaration for which the alias is specified. ObjCInterfaceDecl *ClassDecl = const_cast(OAD->getClassInterface()); ClassAliases.emplace_back(ClassDecl->getNameAsString(), OAD->getNameAsString()); } void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { ASTContext &Context = CGM.getContext(); // Get the superclass name. const ObjCInterfaceDecl * SuperClassDecl = OID->getClassInterface()->getSuperClass(); std::string SuperClassName; if (SuperClassDecl) { SuperClassName = SuperClassDecl->getNameAsString(); EmitClassRef(SuperClassName); } // Get the class name ObjCInterfaceDecl *ClassDecl = const_cast(OID->getClassInterface()); std::string ClassName = ClassDecl->getNameAsString(); // Emit the symbol that is used to generate linker errors if this class is // referenced in other modules but not declared. std::string classSymbolName = "__objc_class_name_" + ClassName; if (auto *symbol = TheModule.getGlobalVariable(classSymbolName)) { symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0)); } else { new llvm::GlobalVariable(TheModule, LongTy, false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(LongTy, 0), classSymbolName); } // Get the size of instances. int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize().getQuantity(); // Collect information about instance variables. SmallVector IvarNames; SmallVector IvarTypes; SmallVector IvarOffsets; SmallVector IvarAligns; SmallVector IvarOwnership; ConstantInitBuilder IvarOffsetBuilder(CGM); auto IvarOffsetValues = IvarOffsetBuilder.beginArray(PtrToIntTy); SmallVector WeakIvars; SmallVector StrongIvars; int superInstanceSize = !SuperClassDecl ? 0 : Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); // For non-fragile ivars, set the instance size to 0 - {the size of just this // class}. The runtime will then set this to the correct value on load. if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { instanceSize = 0 - (instanceSize - superInstanceSize); } for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { // Store the name IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; Context.getObjCEncodingForType(IVD->getType(), TypeStr, IVD); IvarTypes.push_back(MakeConstantString(TypeStr)); IvarAligns.push_back(llvm::ConstantInt::get(IntTy, Context.getTypeSize(IVD->getType()))); // Get the offset uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { Offset = BaseOffset - superInstanceSize; } llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); // Create the direct offset value std::string OffsetName = "__objc_ivar_offset_value_" + ClassName +"." + IVD->getNameAsString(); llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName); if (OffsetVar) { OffsetVar->setInitializer(OffsetValue); // If this is the real definition, change its linkage type so that // different modules will use this one, rather than their private // copy. OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage); } else OffsetVar = new llvm::GlobalVariable(TheModule, Int32Ty, false, llvm::GlobalValue::ExternalLinkage, OffsetValue, OffsetName); IvarOffsets.push_back(OffsetValue); IvarOffsetValues.add(OffsetVar); Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); IvarOwnership.push_back(lt); switch (lt) { case Qualifiers::OCL_Strong: StrongIvars.push_back(true); WeakIvars.push_back(false); break; case Qualifiers::OCL_Weak: StrongIvars.push_back(false); WeakIvars.push_back(true); break; default: StrongIvars.push_back(false); WeakIvars.push_back(false); } } llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); llvm::GlobalVariable *IvarOffsetArray = IvarOffsetValues.finishAndCreateGlobal(".ivar.offsets", CGM.getPointerAlign()); // Collect information about instance methods SmallVector InstanceMethods; InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(), OID->instmeth_end()); SmallVector ClassMethods; ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(), OID->classmeth_end()); // Collect the same information about synthesized properties, which don't // show up in the instance method lists. for (auto *propertyImpl : OID->property_impls()) if (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *property = propertyImpl->getPropertyDecl(); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) InstanceMethods.push_back(accessor); }; addPropertyMethod(property->getGetterMethodDecl()); addPropertyMethod(property->getSetterMethodDecl()); } llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); // Collect the names of referenced protocols SmallVector Protocols; for (const auto *I : ClassDecl->protocols()) Protocols.push_back(I->getNameAsString()); // Get the superclass pointer. llvm::Constant *SuperClass; if (!SuperClassName.empty()) { SuperClass = MakeConstantString(SuperClassName, ".super_class_name"); } else { SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty); } // Empty vector used to construct empty method lists SmallVector empty; // Generate the method and instance variable lists llvm::Constant *MethodList = GenerateMethodList(ClassName, "", InstanceMethods, false); llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "", ClassMethods, true); llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes, IvarOffsets, IvarAligns, IvarOwnership); // Irrespective of whether we are compiling for a fragile or non-fragile ABI, // we emit a symbol containing the offset for each ivar in the class. This // allows code compiled for the non-Fragile ABI to inherit from code compiled // for the legacy ABI, without causing problems. The converse is also // possible, but causes all ivar accesses to be fragile. // Offset pointer for getting at the correct field in the ivar list when // setting up the alias. These are: The base address for the global, the // ivar array (second field), the ivar in this list (set for each ivar), and // the offset (third field in ivar structure) llvm::Type *IndexTy = Int32Ty; llvm::Constant *offsetPointerIndexes[] = {Zeros[0], llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 2 : 1), nullptr, llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 3 : 2) }; unsigned ivarIndex = 0; for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { const std::string Name = GetIVarOffsetVariableName(ClassDecl, IVD); offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex); // Get the correct ivar field llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr( cast(IvarList)->getValueType(), IvarList, offsetPointerIndexes); // Get the existing variable, if one exists. llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name); if (offset) { offset->setInitializer(offsetValue); // If this is the real definition, change its linkage type so that // different modules will use this one, rather than their private // copy. offset->setLinkage(llvm::GlobalValue::ExternalLinkage); } else // Add a new alias if there isn't one already. new llvm::GlobalVariable(TheModule, offsetValue->getType(), false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name); ++ivarIndex; } llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0); //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure( NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), nullptr, Zeros[0], NULLPtr, ClassMethodList, NULLPtr, NULLPtr, GeneratePropertyList(OID, ClassDecl, true), ZeroPtr, ZeroPtr, true); CGM.setGVProperties(cast(MetaClassStruct), OID->getClassInterface()); // Generate the class structure llvm::Constant *ClassStruct = GenerateClassStructure( MetaClassStruct, SuperClass, 0x11L, ClassName.c_str(), nullptr, llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList, GenerateProtocolList(Protocols), IvarOffsetArray, Properties, StrongIvarBitmap, WeakIvarBitmap); CGM.setGVProperties(cast(ClassStruct), OID->getClassInterface()); // Resolve the class aliases, if they exist. if (ClassPtrAlias) { ClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(ClassStruct, IdTy)); ClassPtrAlias->eraseFromParent(); ClassPtrAlias = nullptr; } if (MetaClassPtrAlias) { MetaClassPtrAlias->replaceAllUsesWith( llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy)); MetaClassPtrAlias->eraseFromParent(); MetaClassPtrAlias = nullptr; } // Add class structure to list to be added to the symtab later ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty); Classes.push_back(ClassStruct); } llvm::Function *CGObjCGNU::ModuleInitFunction() { // Only emit an ObjC load function if no Objective-C stuff has been called if (Classes.empty() && Categories.empty() && ConstantStrings.empty() && ExistingProtocols.empty() && SelectorTable.empty()) return nullptr; // Add all referenced protocols to a category. GenerateProtocolHolderCategory(); llvm::StructType *selStructTy = dyn_cast(SelectorTy->getElementType()); llvm::Type *selStructPtrTy = SelectorTy; if (!selStructTy) { selStructTy = llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty }); selStructPtrTy = llvm::PointerType::getUnqual(selStructTy); } // Generate statics list: llvm::Constant *statics = NULLPtr; if (!ConstantStrings.empty()) { llvm::GlobalVariable *fileStatics = [&] { ConstantInitBuilder builder(CGM); auto staticsStruct = builder.beginStruct(); StringRef stringClass = CGM.getLangOpts().ObjCConstantStringClass; if (stringClass.empty()) stringClass = "NXConstantString"; staticsStruct.add(MakeConstantString(stringClass, ".objc_static_class_name")); auto array = staticsStruct.beginArray(); array.addAll(ConstantStrings); array.add(NULLPtr); array.finishAndAddTo(staticsStruct); return staticsStruct.finishAndCreateGlobal(".objc_statics", CGM.getPointerAlign()); }(); ConstantInitBuilder builder(CGM); auto allStaticsArray = builder.beginArray(fileStatics->getType()); allStaticsArray.add(fileStatics); allStaticsArray.addNullPointer(fileStatics->getType()); statics = allStaticsArray.finishAndCreateGlobal(".objc_statics_ptr", CGM.getPointerAlign()); statics = llvm::ConstantExpr::getBitCast(statics, PtrTy); } // Array of classes, categories, and constant objects. SmallVector selectorAliases; unsigned selectorCount; // Pointer to an array of selectors used in this module. llvm::GlobalVariable *selectorList = [&] { ConstantInitBuilder builder(CGM); auto selectors = builder.beginArray(selStructTy); auto &table = SelectorTable; // MSVC workaround for (auto &entry : table) { std::string selNameStr = entry.first.getAsString(); llvm::Constant *selName = ExportUniqueString(selNameStr, ".objc_sel_name"); for (TypedSelector &sel : entry.second) { llvm::Constant *selectorTypeEncoding = NULLPtr; if (!sel.first.empty()) selectorTypeEncoding = MakeConstantString(sel.first, ".objc_sel_types"); auto selStruct = selectors.beginStruct(selStructTy); selStruct.add(selName); selStruct.add(selectorTypeEncoding); selStruct.finishAndAddTo(selectors); // Store the selector alias for later replacement selectorAliases.push_back(sel.second); } } // Remember the number of entries in the selector table. selectorCount = selectors.size(); // NULL-terminate the selector list. This should not actually be required, // because the selector list has a length field. Unfortunately, the GCC // runtime decides to ignore the length field and expects a NULL terminator, // and GCC cooperates with this by always setting the length to 0. auto selStruct = selectors.beginStruct(selStructTy); selStruct.add(NULLPtr); selStruct.add(NULLPtr); selStruct.finishAndAddTo(selectors); return selectors.finishAndCreateGlobal(".objc_selector_list", CGM.getPointerAlign()); }(); // Now that all of the static selectors exist, create pointers to them. for (unsigned i = 0; i < selectorCount; ++i) { llvm::Constant *idxs[] = { Zeros[0], llvm::ConstantInt::get(Int32Ty, i) }; // FIXME: We're generating redundant loads and stores here! llvm::Constant *selPtr = llvm::ConstantExpr::getGetElementPtr( selectorList->getValueType(), selectorList, idxs); // If selectors are defined as an opaque type, cast the pointer to this // type. selPtr = llvm::ConstantExpr::getBitCast(selPtr, SelectorTy); selectorAliases[i]->replaceAllUsesWith(selPtr); selectorAliases[i]->eraseFromParent(); } llvm::GlobalVariable *symtab = [&] { ConstantInitBuilder builder(CGM); auto symtab = builder.beginStruct(); // Number of static selectors symtab.addInt(LongTy, selectorCount); symtab.addBitCast(selectorList, selStructPtrTy); // Number of classes defined. symtab.addInt(CGM.Int16Ty, Classes.size()); // Number of categories defined symtab.addInt(CGM.Int16Ty, Categories.size()); // Create an array of classes, then categories, then static object instances auto classList = symtab.beginArray(PtrToInt8Ty); classList.addAll(Classes); classList.addAll(Categories); // NULL-terminated list of static object instances (mainly constant strings) classList.add(statics); classList.add(NULLPtr); classList.finishAndAddTo(symtab); // Construct the symbol table. return symtab.finishAndCreateGlobal("", CGM.getPointerAlign()); }(); // The symbol table is contained in a module which has some version-checking // constants llvm::Constant *module = [&] { llvm::Type *moduleEltTys[] = { LongTy, LongTy, PtrToInt8Ty, symtab->getType(), IntTy }; llvm::StructType *moduleTy = llvm::StructType::get(CGM.getLLVMContext(), makeArrayRef(moduleEltTys).drop_back(unsigned(RuntimeVersion < 10))); ConstantInitBuilder builder(CGM); auto module = builder.beginStruct(moduleTy); // Runtime version, used for ABI compatibility checking. module.addInt(LongTy, RuntimeVersion); // sizeof(ModuleTy) module.addInt(LongTy, CGM.getDataLayout().getTypeStoreSize(moduleTy)); // The path to the source file where this module was declared SourceManager &SM = CGM.getContext().getSourceManager(); const FileEntry *mainFile = SM.getFileEntryForID(SM.getMainFileID()); std::string path = (Twine(mainFile->getDir()->getName()) + "/" + mainFile->getName()).str(); module.add(MakeConstantString(path, ".objc_source_file_name")); module.add(symtab); if (RuntimeVersion >= 10) { switch (CGM.getLangOpts().getGC()) { case LangOptions::GCOnly: module.addInt(IntTy, 2); break; case LangOptions::NonGC: if (CGM.getLangOpts().ObjCAutoRefCount) module.addInt(IntTy, 1); else module.addInt(IntTy, 0); break; case LangOptions::HybridGC: module.addInt(IntTy, 1); break; } } return module.finishAndCreateGlobal("", CGM.getPointerAlign()); }(); // Create the load function calling the runtime entry point with the module // structure llvm::Function * LoadFunction = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), llvm::GlobalValue::InternalLinkage, ".objc_load_function", &TheModule); llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); CGBuilderTy Builder(CGM, VMContext); Builder.SetInsertPoint(EntryBB); llvm::FunctionType *FT = llvm::FunctionType::get(Builder.getVoidTy(), module->getType(), true); llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class"); Builder.CreateCall(Register, module); if (!ClassAliases.empty()) { llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty}; llvm::FunctionType *RegisterAliasTy = llvm::FunctionType::get(Builder.getVoidTy(), ArgTypes, false); llvm::Function *RegisterAlias = llvm::Function::Create( RegisterAliasTy, llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np", &TheModule); llvm::BasicBlock *AliasBB = llvm::BasicBlock::Create(VMContext, "alias", LoadFunction); llvm::BasicBlock *NoAliasBB = llvm::BasicBlock::Create(VMContext, "no_alias", LoadFunction); // Branch based on whether the runtime provided class_registerAlias_np() llvm::Value *HasRegisterAlias = Builder.CreateICmpNE(RegisterAlias, llvm::Constant::getNullValue(RegisterAlias->getType())); Builder.CreateCondBr(HasRegisterAlias, AliasBB, NoAliasBB); // The true branch (has alias registration function): Builder.SetInsertPoint(AliasBB); // Emit alias registration calls: for (std::vector::iterator iter = ClassAliases.begin(); iter != ClassAliases.end(); ++iter) { llvm::Constant *TheClass = TheModule.getGlobalVariable("_OBJC_CLASS_" + iter->first, true); if (TheClass) { TheClass = llvm::ConstantExpr::getBitCast(TheClass, PtrTy); Builder.CreateCall(RegisterAlias, {TheClass, MakeConstantString(iter->second)}); } } // Jump to end: Builder.CreateBr(NoAliasBB); // Missing alias registration function, just return from the function: Builder.SetInsertPoint(NoAliasBB); } Builder.CreateRetVoid(); return LoadFunction; } llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { const ObjCCategoryImplDecl *OCD = dyn_cast(OMD->getDeclContext()); StringRef CategoryName = OCD ? OCD->getName() : ""; StringRef ClassName = CD->getName(); Selector MethodName = OMD->getSelector(); bool isClassMethod = !OMD->isInstanceMethod(); CodeGenTypes &Types = CGM.getTypes(); llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName, MethodName, isClassMethod); llvm::Function *Method = llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, FunctionName, &TheModule); return Method; } llvm::Constant *CGObjCGNU::GetPropertyGetFunction() { return GetPropertyFn; } llvm::Constant *CGObjCGNU::GetPropertySetFunction() { return SetPropertyFn; } llvm::Constant *CGObjCGNU::GetOptimizedPropertySetFunction(bool atomic, bool copy) { return nullptr; } llvm::Constant *CGObjCGNU::GetGetStructFunction() { return GetStructPropertyFn; } llvm::Constant *CGObjCGNU::GetSetStructFunction() { return SetStructPropertyFn; } llvm::Constant *CGObjCGNU::GetCppAtomicObjectGetFunction() { return nullptr; } llvm::Constant *CGObjCGNU::GetCppAtomicObjectSetFunction() { return nullptr; } llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { return EnumerationMutationFn; } void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn); } void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) { // Unlike the Apple non-fragile runtimes, which also uses // unwind-based zero cost exceptions, the GNU Objective C runtime's // EH support isn't a veneer over C++ EH. Instead, exception // objects are created by objc_exception_throw and destroyed by // the personality function; this avoids the need for bracketing // catch handlers with calls to __blah_begin_catch/__blah_end_catch // (or even _Unwind_DeleteException), but probably doesn't // interoperate very well with foreign exceptions. // // In Objective-C++ mode, we actually emit something equivalent to the C++ // exception handler. EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn); } void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S, bool ClearInsertionPoint) { llvm::Value *ExceptionAsObject; if (const Expr *ThrowExpr = S.getThrowExpr()) { llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); ExceptionAsObject = Exception; } else { assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && "Unexpected rethrow outside @catch block."); ExceptionAsObject = CGF.ObjCEHValueStack.back(); } ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); llvm::CallSite Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject); Throw.setDoesNotReturn(); CGF.Builder.CreateUnreachable(); if (ClearInsertionPoint) CGF.Builder.ClearInsertionPoint(); } llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, Address AddrWeakObj) { CGBuilderTy &B = CGF.Builder; AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy); return B.CreateCall(WeakReadFn.getType(), WeakReadFn, AddrWeakObj.getPointer()); } void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); B.CreateCall(WeakAssignFn.getType(), WeakAssignFn, {src, dst.getPointer()}); } void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst, bool threadlocal) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); // FIXME. Add threadloca assign API assert(!threadlocal && "EmitObjCGlobalAssign - Threal Local API NYI"); B.CreateCall(GlobalAssignFn.getType(), GlobalAssignFn, {src, dst.getPointer()}); } void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst, llvm::Value *ivarOffset) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, IdTy); B.CreateCall(IvarAssignFn.getType(), IvarAssignFn, {src, dst.getPointer(), ivarOffset}); } void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); B.CreateCall(StrongCastAssignFn.getType(), StrongCastAssignFn, {src, dst.getPointer()}); } void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *Size) { CGBuilderTy &B = CGF.Builder; DestPtr = EnforceType(B, DestPtr, PtrTy); SrcPtr = EnforceType(B, SrcPtr, PtrTy); B.CreateCall(MemMoveFn.getType(), MemMoveFn, {DestPtr.getPointer(), SrcPtr.getPointer(), Size}); } llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar) { const std::string Name = GetIVarOffsetVariableName(ID, Ivar); // Emit the variable and initialize it with what we think the correct value // is. This allows code compiled with non-fragile ivars to work correctly // when linked against code which isn't (most of the time). llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); - if (!IvarOffsetPointer) { - // This will cause a run-time crash if we accidentally use it. A value of - // 0 would seem more sensible, but will silently overwrite the isa pointer - // causing a great deal of confusion. - uint64_t Offset = -1; - // We can't call ComputeIvarBaseOffset() here if we have the - // implementation, because it will create an invalid ASTRecordLayout object - // that we are then stuck with forever, so we only initialize the ivar - // offset variable with a guess if we only have the interface. The - // initializer will be reset later anyway, when we are generating the class - // description. - if (!CGM.getContext().getObjCImplementation( - const_cast(ID))) - Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); - - llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(Int32Ty, Offset, - /*isSigned*/true); - // Don't emit the guess in non-PIC code because the linker will not be able - // to replace it with the real version for a library. In non-PIC code you - // must compile with the fragile ABI if you want to use ivars from a - // GCC-compiled class. - if (CGM.getLangOpts().PICLevel) { - llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule, - Int32Ty, false, - llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess"); - IvarOffsetPointer = new llvm::GlobalVariable(TheModule, - IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage, - IvarOffsetGV, Name); - } else { - IvarOffsetPointer = new llvm::GlobalVariable(TheModule, - llvm::Type::getInt32PtrTy(VMContext), false, - llvm::GlobalValue::ExternalLinkage, nullptr, Name); - } - } + if (!IvarOffsetPointer) + IvarOffsetPointer = new llvm::GlobalVariable(TheModule, + llvm::Type::getInt32PtrTy(VMContext), false, + llvm::GlobalValue::ExternalLinkage, nullptr, Name); return IvarOffsetPointer; } LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = ObjectTy->getAs()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *OIVD) { for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next; next = next->getNextIvar()) { if (OIVD == next) return OID; } // Otherwise check in the super class. if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) return FindIvarInterface(Context, Super, OIVD); return nullptr; } llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); // The MSVC linker cannot have a single global defined as LinkOnceAnyLinkage // and ExternalLinkage, so create a reference to the ivar global and rely on // the definition being created as part of GenerateClass. if (RuntimeVersion < 10 || CGF.CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) return CGF.Builder.CreateZExtOrBitCast( CGF.Builder.CreateAlignedLoad( Int32Ty, CGF.Builder.CreateAlignedLoad( ObjCIvarOffsetVariable(Interface, Ivar), CGF.getPointerAlign(), "ivar"), CharUnits::fromQuantity(4)), PtrDiffTy); std::string name = "__objc_ivar_offset_value_" + Interface->getNameAsString() +"." + Ivar->getNameAsString(); CharUnits Align = CGM.getIntAlign(); llvm::Value *Offset = TheModule.getGlobalVariable(name); if (!Offset) { auto GV = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::LinkOnceAnyLinkage, llvm::Constant::getNullValue(IntTy), name); GV->setAlignment(Align.getQuantity()); Offset = GV; } Offset = CGF.Builder.CreateAlignedLoad(Offset, Align); if (Offset->getType() != PtrDiffTy) Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy); return Offset; } uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true); } CGObjCRuntime * clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) { auto Runtime = CGM.getLangOpts().ObjCRuntime; switch (Runtime.getKind()) { case ObjCRuntime::GNUstep: if (Runtime.getVersion() >= VersionTuple(2, 0)) return new CGObjCGNUstep2(CGM); return new CGObjCGNUstep(CGM); case ObjCRuntime::GCC: return new CGObjCGCC(CGM); case ObjCRuntime::ObjFW: return new CGObjCObjFW(CGM); case ObjCRuntime::FragileMacOSX: case ObjCRuntime::MacOSX: case ObjCRuntime::iOS: case ObjCRuntime::WatchOS: llvm_unreachable("these runtimes are not GNU runtimes"); } llvm_unreachable("bad runtime"); } diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index d499364002f0..1a2b0616dc77 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -1,1070 +1,1071 @@ //===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/CodeGen/CodeGenAction.h" #include "CodeGenModule.h" #include "CoverageMappingGen.h" #include "MacroPPCallbacks.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclGroup.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Transforms/IPO/Internalize.h" #include using namespace clang; using namespace llvm; namespace clang { class BackendConsumer; class ClangDiagnosticHandler final : public DiagnosticHandler { public: ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon) : CodeGenOpts(CGOpts), BackendCon(BCon) {} bool handleDiagnostics(const DiagnosticInfo &DI) override; bool isAnalysisRemarkEnabled(StringRef PassName) const override { return (CodeGenOpts.OptimizationRemarkAnalysisPattern && CodeGenOpts.OptimizationRemarkAnalysisPattern->match(PassName)); } bool isMissedOptRemarkEnabled(StringRef PassName) const override { return (CodeGenOpts.OptimizationRemarkMissedPattern && CodeGenOpts.OptimizationRemarkMissedPattern->match(PassName)); } bool isPassedOptRemarkEnabled(StringRef PassName) const override { return (CodeGenOpts.OptimizationRemarkPattern && CodeGenOpts.OptimizationRemarkPattern->match(PassName)); } bool isAnyRemarkEnabled() const override { return (CodeGenOpts.OptimizationRemarkAnalysisPattern || CodeGenOpts.OptimizationRemarkMissedPattern || CodeGenOpts.OptimizationRemarkPattern); } private: const CodeGenOptions &CodeGenOpts; BackendConsumer *BackendCon; }; class BackendConsumer : public ASTConsumer { using LinkModule = CodeGenAction::LinkModule; virtual void anchor(); DiagnosticsEngine &Diags; BackendAction Action; const HeaderSearchOptions &HeaderSearchOpts; const CodeGenOptions &CodeGenOpts; const TargetOptions &TargetOpts; const LangOptions &LangOpts; std::unique_ptr AsmOutStream; ASTContext *Context; Timer LLVMIRGeneration; unsigned LLVMIRGenerationRefCount; /// True if we've finished generating IR. This prevents us from generating /// additional LLVM IR after emitting output in HandleTranslationUnit. This /// can happen when Clang plugins trigger additional AST deserialization. bool IRGenFinished = false; std::unique_ptr Gen; SmallVector LinkModules; // This is here so that the diagnostic printer knows the module a diagnostic // refers to. llvm::Module *CurLinkModule = nullptr; public: BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, const HeaderSearchOptions &HeaderSearchOpts, const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, const TargetOptions &TargetOpts, const LangOptions &LangOpts, bool TimePasses, const std::string &InFile, SmallVector LinkModules, std::unique_ptr OS, LLVMContext &C, CoverageSourceInfo *CoverageInfo = nullptr) : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), AsmOutStream(std::move(OS)), Context(nullptr), LLVMIRGeneration("irgen", "LLVM IR Generation Time"), LLVMIRGenerationRefCount(0), Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts, CodeGenOpts, C, CoverageInfo)), LinkModules(std::move(LinkModules)) { FrontendTimesIsEnabled = TimePasses; + llvm::TimePassesIsEnabled = TimePasses; } llvm::Module *getModule() const { return Gen->GetModule(); } std::unique_ptr takeModule() { return std::unique_ptr(Gen->ReleaseModule()); } CodeGenerator *getCodeGenerator() { return Gen.get(); } void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override { Gen->HandleCXXStaticMemberVarInstantiation(VD); } void Initialize(ASTContext &Ctx) override { assert(!Context && "initialized multiple times"); Context = &Ctx; if (FrontendTimesIsEnabled) LLVMIRGeneration.startTimer(); Gen->Initialize(Ctx); if (FrontendTimesIsEnabled) LLVMIRGeneration.stopTimer(); } bool HandleTopLevelDecl(DeclGroupRef D) override { PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), Context->getSourceManager(), "LLVM IR generation of declaration"); // Recurse. if (FrontendTimesIsEnabled) { LLVMIRGenerationRefCount += 1; if (LLVMIRGenerationRefCount == 1) LLVMIRGeneration.startTimer(); } Gen->HandleTopLevelDecl(D); if (FrontendTimesIsEnabled) { LLVMIRGenerationRefCount -= 1; if (LLVMIRGenerationRefCount == 0) LLVMIRGeneration.stopTimer(); } return true; } void HandleInlineFunctionDefinition(FunctionDecl *D) override { PrettyStackTraceDecl CrashInfo(D, SourceLocation(), Context->getSourceManager(), "LLVM IR generation of inline function"); if (FrontendTimesIsEnabled) LLVMIRGeneration.startTimer(); Gen->HandleInlineFunctionDefinition(D); if (FrontendTimesIsEnabled) LLVMIRGeneration.stopTimer(); } void HandleInterestingDecl(DeclGroupRef D) override { // Ignore interesting decls from the AST reader after IRGen is finished. if (!IRGenFinished) HandleTopLevelDecl(D); } // Links each entry in LinkModules into our module. Returns true on error. bool LinkInModules() { for (auto &LM : LinkModules) { if (LM.PropagateAttrs) for (Function &F : *LM.Module) Gen->CGM().AddDefaultFnAttrs(F); CurLinkModule = LM.Module.get(); bool Err; if (LM.Internalize) { Err = Linker::linkModules( *getModule(), std::move(LM.Module), LM.LinkFlags, [](llvm::Module &M, const llvm::StringSet<> &GVS) { internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { return !GV.hasName() || (GVS.count(GV.getName()) == 0); }); }); } else { Err = Linker::linkModules(*getModule(), std::move(LM.Module), LM.LinkFlags); } if (Err) return true; } return false; // success } void HandleTranslationUnit(ASTContext &C) override { { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); if (FrontendTimesIsEnabled) { LLVMIRGenerationRefCount += 1; if (LLVMIRGenerationRefCount == 1) LLVMIRGeneration.startTimer(); } Gen->HandleTranslationUnit(C); if (FrontendTimesIsEnabled) { LLVMIRGenerationRefCount -= 1; if (LLVMIRGenerationRefCount == 0) LLVMIRGeneration.stopTimer(); } IRGenFinished = true; } // Silently ignore if we weren't initialized for some reason. if (!getModule()) return; // Install an inline asm handler so that diagnostics get printed through // our diagnostics hooks. LLVMContext &Ctx = getModule()->getContext(); LLVMContext::InlineAsmDiagHandlerTy OldHandler = Ctx.getInlineAsmDiagnosticHandler(); void *OldContext = Ctx.getInlineAsmDiagnosticContext(); Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this); std::unique_ptr OldDiagnosticHandler = Ctx.getDiagnosticHandler(); Ctx.setDiagnosticHandler(llvm::make_unique( CodeGenOpts, this)); Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness); if (CodeGenOpts.DiagnosticsHotnessThreshold != 0) Ctx.setDiagnosticsHotnessThreshold( CodeGenOpts.DiagnosticsHotnessThreshold); std::unique_ptr OptRecordFile; if (!CodeGenOpts.OptRecordFile.empty()) { std::error_code EC; OptRecordFile = llvm::make_unique( CodeGenOpts.OptRecordFile, EC, sys::fs::F_None); if (EC) { Diags.Report(diag::err_cannot_open_file) << CodeGenOpts.OptRecordFile << EC.message(); return; } Ctx.setDiagnosticsOutputFile( llvm::make_unique(OptRecordFile->os())); if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone) Ctx.setDiagnosticsHotnessRequested(true); } // Link each LinkModule into our module. if (LinkInModules()) return; EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts, C.getTargetInfo().getDataLayout(), getModule(), Action, std::move(AsmOutStream)); Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); if (OptRecordFile) OptRecordFile->keep(); } void HandleTagDeclDefinition(TagDecl *D) override { PrettyStackTraceDecl CrashInfo(D, SourceLocation(), Context->getSourceManager(), "LLVM IR generation of declaration"); Gen->HandleTagDeclDefinition(D); } void HandleTagDeclRequiredDefinition(const TagDecl *D) override { Gen->HandleTagDeclRequiredDefinition(D); } void CompleteTentativeDefinition(VarDecl *D) override { Gen->CompleteTentativeDefinition(D); } void AssignInheritanceModel(CXXRecordDecl *RD) override { Gen->AssignInheritanceModel(RD); } void HandleVTable(CXXRecordDecl *RD) override { Gen->HandleVTable(RD); } static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, unsigned LocCookie) { SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); } /// Get the best possible source location to represent a diagnostic that /// may have associated debug info. const FullSourceLoc getBestLocationFromDebugLoc(const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo, StringRef &Filename, unsigned &Line, unsigned &Column) const; void InlineAsmDiagHandler2(const llvm::SMDiagnostic &, SourceLocation LocCookie); void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI); /// Specialized handler for InlineAsm diagnostic. /// \return True if the diagnostic has been successfully reported, false /// otherwise. bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D); /// Specialized handler for StackSize diagnostic. /// \return True if the diagnostic has been successfully reported, false /// otherwise. bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D); /// Specialized handler for unsupported backend feature diagnostic. void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D); /// Specialized handlers for optimization remarks. /// Note that these handlers only accept remarks and they always handle /// them. void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID); void OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D); void OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisFPCommute &D); void OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisAliasing &D); void OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D); }; void BackendConsumer::anchor() {} } bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { BackendCon->DiagnosticHandlerImpl(DI); return true; } /// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr /// buffer to be a valid FullSourceLoc. static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, SourceManager &CSM) { // Get both the clang and llvm source managers. The location is relative to // a memory buffer that the LLVM Source Manager is handling, we need to add // a copy to the Clang source manager. const llvm::SourceMgr &LSM = *D.getSourceMgr(); // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr // already owns its one and clang::SourceManager wants to own its one. const MemoryBuffer *LBuf = LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); // Create the copy and transfer ownership to clang::SourceManager. // TODO: Avoid copying files into memory. std::unique_ptr CBuf = llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(), LBuf->getBufferIdentifier()); // FIXME: Keep a file ID map instead of creating new IDs for each location. FileID FID = CSM.createFileID(std::move(CBuf)); // Translate the offset into the file. unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); SourceLocation NewLoc = CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset); return FullSourceLoc(NewLoc, CSM); } /// InlineAsmDiagHandler2 - This function is invoked when the backend hits an /// error parsing inline asm. The SMDiagnostic indicates the error relative to /// the temporary memory buffer that the inline asm parser has set up. void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, SourceLocation LocCookie) { // There are a couple of different kinds of errors we could get here. First, // we re-format the SMDiagnostic in terms of a clang diagnostic. // Strip "error: " off the start of the message string. StringRef Message = D.getMessage(); if (Message.startswith("error: ")) Message = Message.substr(7); // If the SMDiagnostic has an inline asm source location, translate it. FullSourceLoc Loc; if (D.getLoc() != SMLoc()) Loc = ConvertBackendLocation(D, Context->getSourceManager()); unsigned DiagID; switch (D.getKind()) { case llvm::SourceMgr::DK_Error: DiagID = diag::err_fe_inline_asm; break; case llvm::SourceMgr::DK_Warning: DiagID = diag::warn_fe_inline_asm; break; case llvm::SourceMgr::DK_Note: DiagID = diag::note_fe_inline_asm; break; case llvm::SourceMgr::DK_Remark: llvm_unreachable("remarks unexpected"); } // If this problem has clang-level source location information, report the // issue in the source with a note showing the instantiated // code. if (LocCookie.isValid()) { Diags.Report(LocCookie, DiagID).AddString(Message); if (D.getLoc().isValid()) { DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here); // Convert the SMDiagnostic ranges into SourceRange and attach them // to the diagnostic. for (const std::pair &Range : D.getRanges()) { unsigned Column = D.getColumnNo(); B << SourceRange(Loc.getLocWithOffset(Range.first - Column), Loc.getLocWithOffset(Range.second - Column)); } } return; } // Otherwise, report the backend issue as occurring in the generated .s file. // If Loc is invalid, we still need to report the issue, it just gets no // location info. Diags.Report(Loc, DiagID).AddString(Message); } #define ComputeDiagID(Severity, GroupName, DiagID) \ do { \ switch (Severity) { \ case llvm::DS_Error: \ DiagID = diag::err_fe_##GroupName; \ break; \ case llvm::DS_Warning: \ DiagID = diag::warn_fe_##GroupName; \ break; \ case llvm::DS_Remark: \ llvm_unreachable("'remark' severity not expected"); \ break; \ case llvm::DS_Note: \ DiagID = diag::note_fe_##GroupName; \ break; \ } \ } while (false) #define ComputeDiagRemarkID(Severity, GroupName, DiagID) \ do { \ switch (Severity) { \ case llvm::DS_Error: \ DiagID = diag::err_fe_##GroupName; \ break; \ case llvm::DS_Warning: \ DiagID = diag::warn_fe_##GroupName; \ break; \ case llvm::DS_Remark: \ DiagID = diag::remark_fe_##GroupName; \ break; \ case llvm::DS_Note: \ DiagID = diag::note_fe_##GroupName; \ break; \ } \ } while (false) bool BackendConsumer::InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D) { unsigned DiagID; ComputeDiagID(D.getSeverity(), inline_asm, DiagID); std::string Message = D.getMsgStr().str(); // If this problem has clang-level source location information, report the // issue as being a problem in the source with a note showing the instantiated // code. SourceLocation LocCookie = SourceLocation::getFromRawEncoding(D.getLocCookie()); if (LocCookie.isValid()) Diags.Report(LocCookie, DiagID).AddString(Message); else { // Otherwise, report the backend diagnostic as occurring in the generated // .s file. // If Loc is invalid, we still need to report the diagnostic, it just gets // no location info. FullSourceLoc Loc; Diags.Report(Loc, DiagID).AddString(Message); } // We handled all the possible severities. return true; } bool BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) { if (D.getSeverity() != llvm::DS_Warning) // For now, the only support we have for StackSize diagnostic is warning. // We do not know how to format other severities. return false; if (const Decl *ND = Gen->GetDeclForMangledName(D.getFunction().getName())) { // FIXME: Shouldn't need to truncate to uint32_t Diags.Report(ND->getASTContext().getFullLoc(ND->getLocation()), diag::warn_fe_frame_larger_than) << static_cast(D.getStackSize()) << Decl::castToDeclContext(ND); return true; } return false; } const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc( const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo, StringRef &Filename, unsigned &Line, unsigned &Column) const { SourceManager &SourceMgr = Context->getSourceManager(); FileManager &FileMgr = SourceMgr.getFileManager(); SourceLocation DILoc; if (D.isLocationAvailable()) { D.getLocation(&Filename, &Line, &Column); const FileEntry *FE = FileMgr.getFile(Filename); if (FE && Line > 0) { // If -gcolumn-info was not used, Column will be 0. This upsets the // source manager, so pass 1 if Column is not set. DILoc = SourceMgr.translateFileLineCol(FE, Line, Column ? Column : 1); } BadDebugInfo = DILoc.isInvalid(); } // If a location isn't available, try to approximate it using the associated // function definition. We use the definition's right brace to differentiate // from diagnostics that genuinely relate to the function itself. FullSourceLoc Loc(DILoc, SourceMgr); if (Loc.isInvalid()) if (const Decl *FD = Gen->GetDeclForMangledName(D.getFunction().getName())) Loc = FD->getASTContext().getFullLoc(FD->getLocation()); if (DILoc.isInvalid() && D.isLocationAvailable()) // If we were not able to translate the file:line:col information // back to a SourceLocation, at least emit a note stating that // we could not translate this location. This can happen in the // case of #line directives. Diags.Report(Loc, diag::note_fe_backend_invalid_loc) << Filename << Line << Column; return Loc; } void BackendConsumer::UnsupportedDiagHandler( const llvm::DiagnosticInfoUnsupported &D) { // We only support errors. assert(D.getSeverity() == llvm::DS_Error); StringRef Filename; unsigned Line, Column; bool BadDebugInfo = false; FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str(); if (BadDebugInfo) // If we were not able to translate the file:line:col information // back to a SourceLocation, at least emit a note stating that // we could not translate this location. This can happen in the // case of #line directives. Diags.Report(Loc, diag::note_fe_backend_invalid_loc) << Filename << Line << Column; } void BackendConsumer::EmitOptimizationMessage( const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID) { // We only support warnings and remarks. assert(D.getSeverity() == llvm::DS_Remark || D.getSeverity() == llvm::DS_Warning); StringRef Filename; unsigned Line, Column; bool BadDebugInfo = false; FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); std::string Msg; raw_string_ostream MsgStream(Msg); MsgStream << D.getMsg(); if (D.getHotness()) MsgStream << " (hotness: " << *D.getHotness() << ")"; Diags.Report(Loc, DiagID) << AddFlagValue(D.getPassName()) << MsgStream.str(); if (BadDebugInfo) // If we were not able to translate the file:line:col information // back to a SourceLocation, at least emit a note stating that // we could not translate this location. This can happen in the // case of #line directives. Diags.Report(Loc, diag::note_fe_backend_invalid_loc) << Filename << Line << Column; } void BackendConsumer::OptimizationRemarkHandler( const llvm::DiagnosticInfoOptimizationBase &D) { // Without hotness information, don't show noisy remarks. if (D.isVerbose() && !D.getHotness()) return; if (D.isPassed()) { // Optimization remarks are active only if the -Rpass flag has a regular // expression that matches the name of the pass name in \p D. if (CodeGenOpts.OptimizationRemarkPattern && CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName())) EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark); } else if (D.isMissed()) { // Missed optimization remarks are active only if the -Rpass-missed // flag has a regular expression that matches the name of the pass // name in \p D. if (CodeGenOpts.OptimizationRemarkMissedPattern && CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName())) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_missed); } else { assert(D.isAnalysis() && "Unknown remark type"); bool ShouldAlwaysPrint = false; if (auto *ORA = dyn_cast(&D)) ShouldAlwaysPrint = ORA->shouldAlwaysPrint(); if (ShouldAlwaysPrint || (CodeGenOpts.OptimizationRemarkAnalysisPattern && CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis); } } void BackendConsumer::OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisFPCommute &D) { // Optimization analysis remarks are active if the pass name is set to // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a // regular expression that matches the name of the pass name in \p D. if (D.shouldAlwaysPrint() || (CodeGenOpts.OptimizationRemarkAnalysisPattern && CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis_fpcommute); } void BackendConsumer::OptimizationRemarkHandler( const llvm::OptimizationRemarkAnalysisAliasing &D) { // Optimization analysis remarks are active if the pass name is set to // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a // regular expression that matches the name of the pass name in \p D. if (D.shouldAlwaysPrint() || (CodeGenOpts.OptimizationRemarkAnalysisPattern && CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis_aliasing); } void BackendConsumer::OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D) { EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure); } /// This function is invoked when the backend needs /// to report something to the user. void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { unsigned DiagID = diag::err_fe_inline_asm; llvm::DiagnosticSeverity Severity = DI.getSeverity(); // Get the diagnostic ID based. switch (DI.getKind()) { case llvm::DK_InlineAsm: if (InlineAsmDiagHandler(cast(DI))) return; ComputeDiagID(Severity, inline_asm, DiagID); break; case llvm::DK_StackSize: if (StackSizeDiagHandler(cast(DI))) return; ComputeDiagID(Severity, backend_frame_larger_than, DiagID); break; case DK_Linker: assert(CurLinkModule); // FIXME: stop eating the warnings and notes. if (Severity != DS_Error) return; DiagID = diag::err_fe_cannot_link_module; break; case llvm::DK_OptimizationRemark: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_OptimizationRemarkMissed: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_OptimizationRemarkAnalysis: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_OptimizationRemarkAnalysisFPCommute: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_OptimizationRemarkAnalysisAliasing: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_MachineOptimizationRemark: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_MachineOptimizationRemarkMissed: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_MachineOptimizationRemarkAnalysis: // Optimization remarks are always handled completely by this // handler. There is no generic way of emitting them. OptimizationRemarkHandler(cast(DI)); return; case llvm::DK_OptimizationFailure: // Optimization failures are always handled completely by this // handler. OptimizationFailureHandler(cast(DI)); return; case llvm::DK_Unsupported: UnsupportedDiagHandler(cast(DI)); return; default: // Plugin IDs are not bound to any value as they are set dynamically. ComputeDiagRemarkID(Severity, backend_plugin, DiagID); break; } std::string MsgStorage; { raw_string_ostream Stream(MsgStorage); DiagnosticPrinterRawOStream DP(Stream); DI.print(DP); } if (DiagID == diag::err_fe_cannot_link_module) { Diags.Report(diag::err_fe_cannot_link_module) << CurLinkModule->getModuleIdentifier() << MsgStorage; return; } // Report the backend message using the usual diagnostic mechanism. FullSourceLoc Loc; Diags.Report(Loc, DiagID).AddString(MsgStorage); } #undef ComputeDiagID CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext) : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext), OwnsVMContext(!_VMContext) {} CodeGenAction::~CodeGenAction() { TheModule.reset(); if (OwnsVMContext) delete VMContext; } bool CodeGenAction::hasIRSupport() const { return true; } void CodeGenAction::EndSourceFileAction() { // If the consumer creation failed, do nothing. if (!getCompilerInstance().hasASTConsumer()) return; // Steal the module from the consumer. TheModule = BEConsumer->takeModule(); } std::unique_ptr CodeGenAction::takeModule() { return std::move(TheModule); } llvm::LLVMContext *CodeGenAction::takeLLVMContext() { OwnsVMContext = false; return VMContext; } static std::unique_ptr GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) { switch (Action) { case Backend_EmitAssembly: return CI.createDefaultOutputFile(false, InFile, "s"); case Backend_EmitLL: return CI.createDefaultOutputFile(false, InFile, "ll"); case Backend_EmitBC: return CI.createDefaultOutputFile(true, InFile, "bc"); case Backend_EmitNothing: return nullptr; case Backend_EmitMCNull: return CI.createNullOutputFile(); case Backend_EmitObj: return CI.createDefaultOutputFile(true, InFile, "o"); } llvm_unreachable("Invalid action!"); } std::unique_ptr CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { BackendAction BA = static_cast(Act); std::unique_ptr OS = CI.takeOutputStream(); if (!OS) OS = GetOutputStream(CI, InFile, BA); if (BA != Backend_EmitNothing && !OS) return nullptr; // Load bitcode modules to link with, if we need to. if (LinkModules.empty()) for (const CodeGenOptions::BitcodeFileToLink &F : CI.getCodeGenOpts().LinkBitcodeFiles) { auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename); if (!BCBuf) { CI.getDiagnostics().Report(diag::err_cannot_open_file) << F.Filename << BCBuf.getError().message(); LinkModules.clear(); return nullptr; } Expected> ModuleOrErr = getOwningLazyBitcodeModule(std::move(*BCBuf), *VMContext); if (!ModuleOrErr) { handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) { CI.getDiagnostics().Report(diag::err_cannot_open_file) << F.Filename << EIB.message(); }); LinkModules.clear(); return nullptr; } LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs, F.Internalize, F.LinkFlags}); } CoverageSourceInfo *CoverageInfo = nullptr; // Add the preprocessor callback only when the coverage mapping is generated. if (CI.getCodeGenOpts().CoverageMapping) { CoverageInfo = new CoverageSourceInfo; CI.getPreprocessor().addPPCallbacks( std::unique_ptr(CoverageInfo)); } std::unique_ptr Result(new BackendConsumer( BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile, std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo)); BEConsumer = Result.get(); // Enable generating macro debug info only when debug info is not disabled and // also macro debug info is enabled. if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo && CI.getCodeGenOpts().MacroDebugInfo) { std::unique_ptr Callbacks = llvm::make_unique(BEConsumer->getCodeGenerator(), CI.getPreprocessor()); CI.getPreprocessor().addPPCallbacks(std::move(Callbacks)); } return std::move(Result); } static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM, void *Context, unsigned LocCookie) { SM.print(nullptr, llvm::errs()); auto Diags = static_cast(Context); unsigned DiagID; switch (SM.getKind()) { case llvm::SourceMgr::DK_Error: DiagID = diag::err_fe_inline_asm; break; case llvm::SourceMgr::DK_Warning: DiagID = diag::warn_fe_inline_asm; break; case llvm::SourceMgr::DK_Note: DiagID = diag::note_fe_inline_asm; break; case llvm::SourceMgr::DK_Remark: llvm_unreachable("remarks unexpected"); } Diags->Report(DiagID).AddString("cannot compile inline asm"); } std::unique_ptr CodeGenAction::loadModule(MemoryBufferRef MBRef) { CompilerInstance &CI = getCompilerInstance(); SourceManager &SM = CI.getSourceManager(); // For ThinLTO backend invocations, ensure that the context // merges types based on ODR identifiers. We also need to read // the correct module out of a multi-module bitcode file. if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) { VMContext->enableDebugTypeODRUniquing(); auto DiagErrors = [&](Error E) -> std::unique_ptr { unsigned DiagID = CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { CI.getDiagnostics().Report(DiagID) << EIB.message(); }); return {}; }; Expected> BMsOrErr = getBitcodeModuleList(MBRef); if (!BMsOrErr) return DiagErrors(BMsOrErr.takeError()); BitcodeModule *Bm = FindThinLTOModule(*BMsOrErr); // We have nothing to do if the file contains no ThinLTO module. This is // possible if ThinLTO compilation was not able to split module. Content of // the file was already processed by indexing and will be passed to the // linker using merged object file. if (!Bm) { auto M = llvm::make_unique("empty", *VMContext); M->setTargetTriple(CI.getTargetOpts().Triple); return M; } Expected> MOrErr = Bm->parseModule(*VMContext); if (!MOrErr) return DiagErrors(MOrErr.takeError()); return std::move(*MOrErr); } llvm::SMDiagnostic Err; if (std::unique_ptr M = parseIR(MBRef, Err, *VMContext)) return M; // Translate from the diagnostic info to the SourceManager location if // available. // TODO: Unify this with ConvertBackendLocation() SourceLocation Loc; if (Err.getLineNo() > 0) { assert(Err.getColumnNo() >= 0); Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(), Err.getColumnNo() + 1); } // Strip off a leading diagnostic code if there is one. StringRef Msg = Err.getMessage(); if (Msg.startswith("error: ")) Msg = Msg.substr(7); unsigned DiagID = CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); CI.getDiagnostics().Report(Loc, DiagID) << Msg; return {}; } void CodeGenAction::ExecuteAction() { // If this is an IR file, we have to treat it specially. if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) { BackendAction BA = static_cast(Act); CompilerInstance &CI = getCompilerInstance(); std::unique_ptr OS = GetOutputStream(CI, getCurrentFile(), BA); if (BA != Backend_EmitNothing && !OS) return; bool Invalid; SourceManager &SM = CI.getSourceManager(); FileID FID = SM.getMainFileID(); llvm::MemoryBuffer *MainFile = SM.getBuffer(FID, &Invalid); if (Invalid) return; TheModule = loadModule(*MainFile); if (!TheModule) return; const TargetOptions &TargetOpts = CI.getTargetOpts(); if (TheModule->getTargetTriple() != TargetOpts.Triple) { CI.getDiagnostics().Report(SourceLocation(), diag::warn_fe_override_module) << TargetOpts.Triple; TheModule->setTargetTriple(TargetOpts.Triple); } EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), MainFile->getMemBufferRef()); LLVMContext &Ctx = TheModule->getContext(); Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler, &CI.getDiagnostics()); EmitBackendOutput(CI.getDiagnostics(), CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(), CI.getTarget().getDataLayout(), TheModule.get(), BA, std::move(OS)); return; } // Otherwise follow the normal AST path. this->ASTFrontendAction::ExecuteAction(); } // void EmitAssemblyAction::anchor() { } EmitAssemblyAction::EmitAssemblyAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitAssembly, _VMContext) {} void EmitBCAction::anchor() { } EmitBCAction::EmitBCAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitBC, _VMContext) {} void EmitLLVMAction::anchor() { } EmitLLVMAction::EmitLLVMAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitLL, _VMContext) {} void EmitLLVMOnlyAction::anchor() { } EmitLLVMOnlyAction::EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitNothing, _VMContext) {} void EmitCodeGenOnlyAction::anchor() { } EmitCodeGenOnlyAction::EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitMCNull, _VMContext) {} void EmitObjAction::anchor() { } EmitObjAction::EmitObjAction(llvm::LLVMContext *_VMContext) : CodeGenAction(Backend_EmitObj, _VMContext) {} diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h index 345fa4d0c193..0e8317e5b9d9 100644 --- a/lib/Headers/unwind.h +++ b/lib/Headers/unwind.h @@ -1,337 +1,341 @@ /*===---- unwind.h - Stack unwinding ----------------------------------------=== * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * *===-----------------------------------------------------------------------=== */ /* See "Data Definitions for libgcc_s" in the Linux Standard Base.*/ #ifndef __CLANG_UNWIND_H #define __CLANG_UNWIND_H #if defined(__APPLE__) && __has_include_next() /* Darwin (from 11.x on) provide an unwind.h. If that's available, * use it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE, * so define that around the include.*/ # ifndef _GNU_SOURCE # define _SHOULD_UNDEFINE_GNU_SOURCE # define _GNU_SOURCE # endif // libunwind's unwind.h reflects the current visibility. However, Mozilla // builds with -fvisibility=hidden and relies on gcc's unwind.h to reset the // visibility to default and export its contents. gcc also allows users to // override its override by #defining HIDE_EXPORTS (but note, this only obeys // the user's -fvisibility setting; it doesn't hide any exports on its own). We // imitate gcc's header here: # ifdef HIDE_EXPORTS # include_next # else # pragma GCC visibility push(default) # include_next # pragma GCC visibility pop # endif # ifdef _SHOULD_UNDEFINE_GNU_SOURCE # undef _GNU_SOURCE # undef _SHOULD_UNDEFINE_GNU_SOURCE # endif #else #include #ifdef __cplusplus extern "C" { #endif /* It is a bit strange for a header to play with the visibility of the symbols it declares, but this matches gcc's behavior and some programs depend on it */ #ifndef HIDE_EXPORTS #pragma GCC visibility push(default) #endif typedef uintptr_t _Unwind_Word; typedef intptr_t _Unwind_Sword; typedef uintptr_t _Unwind_Ptr; typedef uintptr_t _Unwind_Internal_Ptr; typedef uint64_t _Unwind_Exception_Class; typedef intptr_t _sleb128_t; typedef uintptr_t _uleb128_t; struct _Unwind_Context; #if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) struct _Unwind_Control_Block; typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ #else struct _Unwind_Exception; typedef struct _Unwind_Exception _Unwind_Exception; #endif typedef enum { _URC_NO_REASON = 0, #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) _URC_OK = 0, /* used by ARM EHABI */ #endif _URC_FOREIGN_EXCEPTION_CAUGHT = 1, _URC_FATAL_PHASE2_ERROR = 2, _URC_FATAL_PHASE1_ERROR = 3, _URC_NORMAL_STOP = 4, _URC_END_OF_STACK = 5, _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8, #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ !defined(__ARM_DWARF_EH__) _URC_FAILURE = 9 /* used by ARM EHABI */ #endif } _Unwind_Reason_Code; typedef enum { _UA_SEARCH_PHASE = 1, _UA_CLEANUP_PHASE = 2, _UA_HANDLER_FRAME = 4, _UA_FORCE_UNWIND = 8, _UA_END_OF_STACK = 16 /* gcc extension to C++ ABI */ } _Unwind_Action; typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, _Unwind_Exception *); #if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) typedef struct _Unwind_Control_Block _Unwind_Control_Block; typedef uint32_t _Unwind_EHT_Header; struct _Unwind_Control_Block { uint64_t exception_class; void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); /* unwinder cache (private fields for the unwinder's use) */ struct { uint32_t reserved1; /* forced unwind stop function, 0 if not forced */ uint32_t reserved2; /* personality routine */ uint32_t reserved3; /* callsite */ uint32_t reserved4; /* forced unwind stop argument */ uint32_t reserved5; } unwinder_cache; /* propagation barrier cache (valid after phase 1) */ struct { uint32_t sp; uint32_t bitpattern[5]; } barrier_cache; /* cleanup cache (preserved over cleanup) */ struct { uint32_t bitpattern[4]; } cleanup_cache; /* personality cache (for personality's benefit) */ struct { uint32_t fnstart; /* function start address */ _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ uint32_t additional; /* additional data */ uint32_t reserved1; } pr_cache; long long int : 0; /* force alignment of next item to 8-byte boundary */ } __attribute__((__aligned__(8))); #else struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; +#if !defined (__USING_SJLJ_EXCEPTIONS__) && defined (__SEH__) + _Unwind_Word private_[6]; +#else _Unwind_Word private_1; _Unwind_Word private_2; +#endif /* The Itanium ABI requires that _Unwind_Exception objects are "double-word * aligned". GCC has interpreted this to mean "use the maximum useful * alignment for the target"; so do we. */ } __attribute__((__aligned__)); #endif typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action, _Unwind_Exception_Class, _Unwind_Exception *, struct _Unwind_Context *, void *); typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, _Unwind_Action, _Unwind_Exception_Class, _Unwind_Exception *, struct _Unwind_Context *); typedef _Unwind_Personality_Fn __personality_routine; typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *); #if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__)) typedef enum { _UVRSC_CORE = 0, /* integer register */ _UVRSC_VFP = 1, /* vfp */ _UVRSC_WMMXD = 3, /* Intel WMMX data register */ _UVRSC_WMMXC = 4 /* Intel WMMX control register */ } _Unwind_VRS_RegClass; typedef enum { _UVRSD_UINT32 = 0, _UVRSD_VFPX = 1, _UVRSD_UINT64 = 3, _UVRSD_FLOAT = 4, _UVRSD_DOUBLE = 5 } _Unwind_VRS_DataRepresentation; typedef enum { _UVRSR_OK = 0, _UVRSR_NOT_IMPLEMENTED = 1, _UVRSR_FAILED = 2 } _Unwind_VRS_Result; typedef uint32_t _Unwind_State; #define _US_VIRTUAL_UNWIND_FRAME ((_Unwind_State)0) #define _US_UNWIND_FRAME_STARTING ((_Unwind_State)1) #define _US_UNWIND_FRAME_RESUME ((_Unwind_State)2) #define _US_ACTION_MASK ((_Unwind_State)3) #define _US_FORCE_UNWIND ((_Unwind_State)8) _Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context, _Unwind_VRS_RegClass __regclass, uint32_t __regno, _Unwind_VRS_DataRepresentation __representation, void *__valuep); _Unwind_VRS_Result _Unwind_VRS_Set(struct _Unwind_Context *__context, _Unwind_VRS_RegClass __regclass, uint32_t __regno, _Unwind_VRS_DataRepresentation __representation, void *__valuep); static __inline__ _Unwind_Word _Unwind_GetGR(struct _Unwind_Context *__context, int __index) { _Unwind_Word __value; _Unwind_VRS_Get(__context, _UVRSC_CORE, __index, _UVRSD_UINT32, &__value); return __value; } static __inline__ void _Unwind_SetGR(struct _Unwind_Context *__context, int __index, _Unwind_Word __value) { _Unwind_VRS_Set(__context, _UVRSC_CORE, __index, _UVRSD_UINT32, &__value); } static __inline__ _Unwind_Word _Unwind_GetIP(struct _Unwind_Context *__context) { _Unwind_Word __ip = _Unwind_GetGR(__context, 15); return __ip & ~(_Unwind_Word)(0x1); /* Remove thumb mode bit. */ } static __inline__ void _Unwind_SetIP(struct _Unwind_Context *__context, _Unwind_Word __value) { _Unwind_Word __thumb_mode_bit = _Unwind_GetGR(__context, 15) & 0x1; _Unwind_SetGR(__context, 15, __value | __thumb_mode_bit); } #else _Unwind_Word _Unwind_GetGR(struct _Unwind_Context *, int); void _Unwind_SetGR(struct _Unwind_Context *, int, _Unwind_Word); _Unwind_Word _Unwind_GetIP(struct _Unwind_Context *); void _Unwind_SetIP(struct _Unwind_Context *, _Unwind_Word); #endif _Unwind_Word _Unwind_GetIPInfo(struct _Unwind_Context *, int *); _Unwind_Word _Unwind_GetCFA(struct _Unwind_Context *); _Unwind_Word _Unwind_GetBSP(struct _Unwind_Context *); void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *); _Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *); /* DWARF EH functions; currently not available on Darwin/ARM */ #if !defined(__APPLE__) || !defined(__arm__) _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *); _Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, void *); void _Unwind_DeleteException(_Unwind_Exception *); void _Unwind_Resume(_Unwind_Exception *); _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *); #endif _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); /* setjmp(3)/longjmp(3) stuff */ typedef struct SjLj_Function_Context *_Unwind_FunctionContext_t; void _Unwind_SjLj_Register(_Unwind_FunctionContext_t); void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t); _Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception *); _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn, void *); void _Unwind_SjLj_Resume(_Unwind_Exception *); _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *); void *_Unwind_FindEnclosingFunction(void *); #ifdef __APPLE__ _Unwind_Ptr _Unwind_GetDataRelBase(struct _Unwind_Context *) __attribute__((__unavailable__)); _Unwind_Ptr _Unwind_GetTextRelBase(struct _Unwind_Context *) __attribute__((__unavailable__)); /* Darwin-specific functions */ void __register_frame(const void *); void __deregister_frame(const void *); struct dwarf_eh_bases { uintptr_t tbase; uintptr_t dbase; uintptr_t func; }; void *_Unwind_Find_FDE(const void *, struct dwarf_eh_bases *); void __register_frame_info_bases(const void *, void *, void *, void *) __attribute__((__unavailable__)); void __register_frame_info(const void *, void *) __attribute__((__unavailable__)); void __register_frame_info_table_bases(const void *, void*, void *, void *) __attribute__((__unavailable__)); void __register_frame_info_table(const void *, void *) __attribute__((__unavailable__)); void __register_frame_table(const void *) __attribute__((__unavailable__)); void __deregister_frame_info(const void *) __attribute__((__unavailable__)); void __deregister_frame_info_bases(const void *)__attribute__((__unavailable__)); #else _Unwind_Ptr _Unwind_GetDataRelBase(struct _Unwind_Context *); _Unwind_Ptr _Unwind_GetTextRelBase(struct _Unwind_Context *); #endif #ifndef HIDE_EXPORTS #pragma GCC visibility pop #endif #ifdef __cplusplus } #endif #endif #endif /* __CLANG_UNWIND_H */ diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a1168fa34d56..7a8f2d3f4702 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1,7916 +1,7922 @@ //===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// Implements semantic analysis for C++ expressions. /// //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace sema; /// Handle the result of the special case name lookup for inheriting /// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as /// constructor names in member using declarations, even if 'X' is not the /// name of the corresponding type. ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name) { NestedNameSpecifier *NNS = SS.getScopeRep(); // Convert the nested-name-specifier into a type. QualType Type; switch (NNS->getKind()) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: Type = QualType(NNS->getAsType(), 0); break; case NestedNameSpecifier::Identifier: // Strip off the last layer of the nested-name-specifier and build a // typename type for it. assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), NNS->getAsIdentifier()); break; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); } // This reference to the type is located entirely at the location of the // final identifier in the qualified-id. return CreateParsedType(Type, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } ParsedType Sema::getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, bool EnteringContext) { CXXRecordDecl *CurClass = getCurrentClass(S, &SS); assert(CurClass && &II == CurClass->getIdentifier() && "not a constructor name"); // When naming a constructor as a member of a dependent context (eg, in a // friend declaration or an inherited constructor declaration), form an // unresolved "typename" type. if (CurClass->isDependentContext() && !EnteringContext) { QualType T = Context.getDependentNameType(ETK_None, SS.getScopeRep(), &II); return ParsedType::make(T); } if (SS.isNotEmpty() && RequireCompleteDeclContext(SS, CurClass)) return ParsedType(); // Find the injected-class-name declaration. Note that we make no attempt to // diagnose cases where the injected-class-name is shadowed: the only // declaration that can validly shadow the injected-class-name is a // non-static data member, and if the class contains both a non-static data // member and a constructor then it is ill-formed (we check that in // CheckCompletedCXXClass). CXXRecordDecl *InjectedClassName = nullptr; for (NamedDecl *ND : CurClass->lookup(&II)) { auto *RD = dyn_cast(ND); if (RD && RD->isInjectedClassName()) { InjectedClassName = RD; break; } } - if (!InjectedClassName && CurClass->isInvalidDecl()) + if (!InjectedClassName) { + if (!CurClass->isInvalidDecl()) { + // FIXME: RequireCompleteDeclContext doesn't check dependent contexts + // properly. Work around it here for now. + Diag(SS.getLastQualifierNameLoc(), + diag::err_incomplete_nested_name_spec) << CurClass << SS.getRange(); + } return ParsedType(); - assert(InjectedClassName && "couldn't find injected class name"); + } QualType T = Context.getTypeDeclType(InjectedClassName); DiagnoseUseOfDecl(InjectedClassName, NameLoc); MarkAnyDeclReferenced(NameLoc, InjectedClassName, /*OdrUse=*/false); return ParsedType::make(T); } ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. // FIXME: This area of the standard is very messy, and the current // wording is rather unclear about which scopes we search for the // destructor name; see core issues 399 and 555. Issue 399 in // particular shows where the current description of destructor name // lookup is completely out of line with existing practice, e.g., // this appears to be ill-formed: // // namespace N { // template struct S { // ~S(); // }; // } // // void f(N::S* s) { // s->N::S::~S(); // } // // See also PR6358 and PR6359. // For this reason, we're currently only doing the C++03 version of this // code; the C++0x version has to wait until we get a proper spec. QualType SearchType; DeclContext *LookupCtx = nullptr; bool isDependent = false; bool LookInScope = false; if (SS.isInvalid()) return nullptr; // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and // we know what type we're looking for. if (ObjectTypePtr) SearchType = GetTypeFromParser(ObjectTypePtr); if (SS.isSet()) { NestedNameSpecifier *NNS = SS.getScopeRep(); bool AlreadySearched = false; bool LookAtPrefix = true; // C++11 [basic.lookup.qual]p6: // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. Similarly, in a qualified-id of the form: // // nested-name-specifier[opt] class-name :: ~ class-name // // the second class-name is looked up in the same scope as the first. // // Here, we determine whether the code below is permitted to look at the // prefix of the nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { AlreadySearched = true; LookupCtx = DC; isDependent = false; } else if (DC && isa(DC)) { LookAtPrefix = false; LookInScope = true; } // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = nullptr; if (AlreadySearched) { // Nothing left to do. } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { CXXScopeSpec PrefixSS; PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); LookupCtx = computeDeclContext(PrefixSS, EnteringContext); isDependent = isDependentScopeSpecifier(PrefixSS); } else if (ObjectTypePtr) { LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); } else { LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up // in the context of the entire postfix-expression. If the type T // of the object expression is of a class type C, the type-name is // also looked up in the scope of class C. At least one of the // lookups shall find a name that refers to (possibly // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; } else { // Perform lookup into the current scope (only). LookInScope = true; } TypeDecl *NonMatchingTypeDecl = nullptr; LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); for (unsigned Step = 0; Step != 2; ++Step) { // Look for the name first in the computed lookup context (if we // have one) and, if that fails to find a match, in the scope (if // we're allowed to look there). Found.clear(); if (Step == 0 && LookupCtx) { if (RequireCompleteDeclContext(SS, LookupCtx)) return nullptr; LookupQualifiedName(Found, LookupCtx); } else if (Step == 1 && LookInScope && S) { LookupName(Found, S); } else { continue; } // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) return nullptr; if (TypeDecl *Type = Found.getAsSingle()) { QualType T = Context.getTypeDeclType(Type); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { // We found our type! return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } if (!SearchType.isNull()) NonMatchingTypeDecl = Type; } // If the name that we found is a class template name, and it is // the same name as the template name in the last part of the // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle()) { QualType MemberOfType; if (SS.isSet()) { if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { // Figure out the type of the context, if it has one. if (CXXRecordDecl *Record = dyn_cast(Ctx)) MemberOfType = Context.getTypeDeclType(Record); } } if (MemberOfType.isNull()) MemberOfType = SearchType; if (MemberOfType.isNull()) continue; // We're referring into a class template specialization. If the // class template we found is the same as the template being // specialized, we found what we are looking for. if (const RecordType *Record = MemberOfType->getAs()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Record->getDecl())) { if (Spec->getSpecializedTemplate()->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); } continue; } // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't // know which template is being specialized, that it at least // has the same name. if (const TemplateSpecializationType *SpecType = MemberOfType->getAs()) { TemplateName SpecName = SpecType->getTemplateName(); // The class template we found is the same template being // specialized. if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } // The class template we found has the same name as the // (dependent) template name being specialized. if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } } } } if (isDependent) { // We didn't find our type, but that's okay: it's dependent // anyway. // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), SS.getWithLocInContext(Context), II, NameLoc); return ParsedType::make(T); } if (NonMatchingTypeDecl) { QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); Diag(NameLoc, diag::err_destructor_expr_type_mismatch) << T << SearchType; Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) << T; } else if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) << &II; else { SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, diag::err_destructor_class_name); if (S) { const DeclContext *Ctx = S->getEntity(); if (const CXXRecordDecl *Class = dyn_cast_or_null(Ctx)) DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), Class->getNameAsString()); } } return nullptr; } ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error) return nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return nullptr; } assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. QualType SearchType = GetTypeFromParser(ObjectType); if (!SearchType.isNull() && !SearchType->isDependentType() && !Context.hasSameUnqualifiedType(T, SearchType)) { Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; } return ParsedType::make(T); } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Name) { assert(Name.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId); if (!SS.isValid()) return false; switch (SS.getScopeRep()->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: // Per C++11 [over.literal]p2, literal operators can only be declared at // namespace scope. Therefore, this unqualified-id cannot name anything. // Reject it early, because we have no AST representation for this in the // case where the scope is dependent. Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace) << SS.getScopeRep(); return true; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: return false; } llvm_unreachable("unknown nested name specifier kind"); } /// Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { // C++ [expr.typeid]p4: // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), Quals); if (T->getAs() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); if (T->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } /// Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { bool WasEvaluated = false; if (E && !E->isTypeDependent()) { if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); } QualType T = E->getType(); if (const RecordType *RecordT = T->getAs()) { CXXRecordDecl *RecordD = cast(RecordT->getDecl()); // C++ [expr.typeid]p3: // [...] If the type of the expression is a class type, the class // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isGLValue()) { // The subexpression is potentially evaluated; switch the context // and recheck the subexpression. ExprResult Result = TransformToPotentiallyEvaluated(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); WasEvaluated = true; } } // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly // cv-qualified type, the result of the typeid expression refers to a // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).get(); } } if (E->getType()->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << E->getType()); else if (!inTemplateInstantiation() && E->HasSideEffects(Context, WasEvaluated)) { // The expression operand for typeid is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(E->getExprLoc(), WasEvaluated ? diag::warn_side_effects_typeid : diag::warn_side_effects_unevaluated_context); } return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // OpenCL C++ 1.0 s2.9: typeid is not supported. if (getLangOpts().OpenCLCPlusPlus) { return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) << "typeid"); } // Find the std::type_info type. if (!getStdNamespace()) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); if (!CXXTypeInfoDecl) { IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, getStdNamespace()); CXXTypeInfoDecl = R.getAsSingle(); // Microsoft's typeinfo doesn't have type_info in std but in the global // namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153. if (!CXXTypeInfoDecl && LangOpts.MSVCCompat) { LookupQualifiedName(R, Context.getTranslationUnitDecl()); CXXTypeInfoDecl = R.getAsSingle(); } if (!CXXTypeInfoDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); } if (!getLangOpts().RTTI) { return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti)); } QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to /// a single GUID. static void getUuidAttrOfType(Sema &SemaRef, QualType QT, llvm::SmallSetVector &UuidAttrs) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); if (QT->isPointerType() || QT->isReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); const auto *TD = Ty->getAsTagDecl(); if (!TD) return; if (const auto *Uuid = TD->getMostRecentDecl()->getAttr()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. if (const auto *CTSD = dyn_cast(TD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; if (TA.getKind() == TemplateArgument::Type) getUuidAttrOfType(SemaRef, TA.getAsType(), UuidAttrs); else if (TA.getKind() == TemplateArgument::Declaration) getUuidAttrOfType(SemaRef, TA.getAsDecl()->getType(), UuidAttrs); if (UuidForTA) UuidAttrs.insert(UuidForTA); } } } /// Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { StringRef UuidStr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { StringRef UuidStr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { UuidStr = "00000000-0000-0000-0000-000000000000"; } else { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // If MSVCGuidDecl has not been cached, do the lookup. if (!MSVCGuidDecl) { IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); LookupQualifiedName(R, Context.getTranslationUnitDecl()); MSVCGuidDecl = R.getAsSingle(); if (!MSVCGuidDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); } QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw_true || Kind == tok::kw_false) && "Unknown C++ Boolean value!"); return new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); } /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { return new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc); } /// ActOnCXXThrow - Parse throw expressions. ExprResult Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { bool IsThrownVarInScope = false; if (Ex) { // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or catch- // clause parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object if (DeclRefExpr *DRE = dyn_cast(Ex->IgnoreParens())) if (VarDecl *Var = dyn_cast(DRE->getDecl())) { if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) { for( ; S; S = S->getParent()) { if (S->isDeclScope(Var)) { IsThrownVarInScope = true; break; } if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | Scope::TryScope)) break; } } } } return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); } ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc) && (!getLangOpts().OpenMPIsDevice || !getLangOpts().OpenMPHostCXXExceptions || isInOpenMPTargetExecutionDirective() || isInOpenMPDeclareTargetContext())) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) << "throw" << CurrentCUDATarget(); if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; if (Ex && !Ex->isTypeDependent()) { QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or // catch-clause // parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object const VarDecl *NRVOVariable = nullptr; if (IsThrownVarInScope) NRVOVariable = getCopyElisionCandidate(QualType(), Ex, CES_Strict); InitializedEntity Entity = InitializedEntity::InitializeException( OpLoc, ExceptionObjectTy, /*NRVO=*/NRVOVariable != nullptr); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); if (Res.isInvalid()) return ExprError(); Ex = Res.get(); } return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } static void collectPublicBases(CXXRecordDecl *RD, llvm::DenseMap &SubobjectsSeen, llvm::SmallPtrSetImpl &VBases, llvm::SetVector &PublicSubobjectsSeen, bool ParentIsPublic) { for (const CXXBaseSpecifier &BS : RD->bases()) { CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); bool NewSubobject; // Virtual bases constitute the same subobject. Non-virtual bases are // always distinct subobjects. if (BS.isVirtual()) NewSubobject = VBases.insert(BaseDecl).second; else NewSubobject = true; if (NewSubobject) ++SubobjectsSeen[BaseDecl]; // Only add subobjects which have public access throughout the entire chain. bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; if (PublicPath) PublicSubobjectsSeen.insert(BaseDecl); // Recurse on to each base subobject. collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, PublicPath); } } static void getUnambiguousPublicSubobjects( CXXRecordDecl *RD, llvm::SmallVectorImpl &Objects) { llvm::DenseMap SubobjectsSeen; llvm::SmallSet VBases; llvm::SetVector PublicSubobjectsSeen; SubobjectsSeen[RD] = 1; PublicSubobjectsSeen.insert(RD); collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, /*ParentIsPublic=*/true); for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { // Skip ambiguous objects. if (SubobjectsSeen[PublicSubobject] > 1) continue; Objects.push_back(PublicSubobject); } } /// CheckCXXThrowOperand - Validate the operand of a throw. bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ExceptionObjectTy, Expr *E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = ExceptionObjectTy; bool isPointer = false; if (const PointerType* Ptr = Ty->getAs()) { Ty = Ptr->getPointeeType(); isPointer = true; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, isPointer ? diag::err_throw_incomplete_ptr : diag::err_throw_incomplete, E->getSourceRange())) return true; if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return true; } // If the exception has class type, we need additional handling. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (!RD) return false; // If we are throwing a polymorphic class type or pointer thereof, // exception handling will make use of the vtable. MarkVTableUsed(ThrowLoc, RD); // If a pointer is thrown, the referenced object will not be destroyed. if (isPointer) return false; // If the class has a destructor, we must be able to call it. if (!RD->hasIrrelevantDestructor()) { if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return true; } } // The MSVC ABI creates a list of all types which can catch the exception // object. This list also references the appropriate copy constructor to call // if the object is caught by value and has a non-trivial copy constructor. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { // We are only interested in the public, unambiguous bases contained within // the exception object. Bases which are ambiguous or otherwise // inaccessible are not catchable types. llvm::SmallVector UnambiguousPublicSubobjects; getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { // Attempt to lookup the copy constructor. Various pieces of machinery // will spring into action, like template instantiation, which means this // cannot be a simple walk of the class's decls. Instead, we must perform // lookup and overload resolution. CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); if (!CD) continue; // Mark the constructor referenced as it is used by this throw expression. MarkFunctionReferenced(E->getExprLoc(), CD); // Skip this copy constructor if it is trivial, we don't need to record it // in the catchable type data. if (CD->isTrivial()) continue; // The copy constructor is non-trivial, create a mapping from this class // type to this constructor. // N.B. The selection of copy constructor is not sensitive to this // particular throw-site. Lookup will be performed at the catch-site to // ensure that the copy constructor is, in fact, accessible (via // friendship or any other means). Context.addCopyConstructorForExceptionObject(Subobject, CD); // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I))) return true; } } } return false; } static QualType adjustCVQualifiersForCXXThisWithinLambda( ArrayRef FunctionScopes, QualType ThisTy, DeclContext *CurSemaContext, ASTContext &ASTCtx) { QualType ClassType = ThisTy->getPointeeType(); LambdaScopeInfo *CurLSI = nullptr; DeclContext *CurDC = CurSemaContext; // Iterate through the stack of lambdas starting from the innermost lambda to // the outermost lambda, checking if '*this' is ever captured by copy - since // that could change the cv-qualifiers of the '*this' object. // The object referred to by '*this' starts out with the cv-qualifiers of its // member function. We then start with the innermost lambda and iterate // outward checking to see if any lambda performs a by-copy capture of '*this' // - and if so, any nested lambda must respect the 'constness' of that // capturing lamdbda's call operator. // // Since the FunctionScopeInfo stack is representative of the lexical // nesting of the lambda expressions during initial parsing (and is the best // place for querying information about captures about lambdas that are // partially processed) and perhaps during instantiation of function templates // that contain lambda expressions that need to be transformed BUT not // necessarily during instantiation of a nested generic lambda's function call // operator (which might even be instantiated at the end of the TU) - at which // time the DeclContext tree is mature enough to query capture information // reliably - we use a two pronged approach to walk through all the lexically // enclosing lambda expressions: // // 1) Climb down the FunctionScopeInfo stack as long as each item represents // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is lexically // enclosed by the call-operator of the LSI below it on the stack (while // tracking the enclosing DC for step 2 if needed). Note the topmost LSI on // the stack represents the innermost lambda. // // 2) If we run out of enclosing LSI's, check if the enclosing DeclContext // represents a lambda's call operator. If it does, we must be instantiating // a generic lambda's call operator (represented by the Current LSI, and // should be the only scenario where an inconsistency between the LSI and the // DeclContext should occur), so climb out the DeclContexts if they // represent lambdas, while querying the corresponding closure types // regarding capture information. // 1) Climb down the function scope info stack. for (int I = FunctionScopes.size(); I-- && isa(FunctionScopes[I]) && (!CurLSI || !CurLSI->Lambda || CurLSI->Lambda->getDeclContext() == cast(FunctionScopes[I])->CallOperator); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast(FunctionScopes[I]); if (!CurLSI->isCXXThisCaptured()) continue; auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (CurLSI->CallOperator->isConst()) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } } // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can // happen during instantiation of its nested generic lambda call operator) if (isLambdaCallOperator(CurDC)) { assert(CurLSI && "While computing 'this' capture-type for a generic " "lambda, we must have a corresponding LambdaScopeInfo"); assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) && "While computing 'this' capture-type for a generic lambda, when we " "run out of enclosing LSI's, yet the enclosing DC is a " "lambda-call-operator we must be (i.e. Current LSI) in a generic " "lambda call oeprator"); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); auto IsThisCaptured = [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { IsConst = false; IsByCopy = false; for (auto &&C : Closure->captures()) { if (C.capturesThis()) { if (C.getCaptureKind() == LCK_StarThis) IsByCopy = true; if (Closure->getLambdaCallOperator()->isConst()) IsConst = true; return true; } } return false; }; bool IsByCopyCapture = false; bool IsConstCapture = false; CXXRecordDecl *Closure = cast(CurDC->getParent()); while (Closure && IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) { if (IsByCopyCapture) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (IsConstCapture) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } Closure = isLambdaCallOperator(Closure->getParent()) ? cast(Closure->getParent()->getParent()) : nullptr; } } return ASTCtx.getPointerType(ClassType); } QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); QualType ThisTy = CXXThisTypeOverride; if (CXXMethodDecl *method = dyn_cast(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(Context); } if (ThisTy.isNull() && isLambdaCallOperator(CurContext) && inTemplateInstantiation()) { assert(isa(DC) && "Trying to get 'this' type from static method?"); // This is a lambda call operator that is being instantiated as a default // initializer. DC must point to the enclosing class type, so we can recover // the 'this' type from it. QualType ClassTy = Context.getTypeDeclType(cast(DC)); // There are no cv-qualifiers for 'this' within default initializers, // per [expr.prim.general]p4. ThisTy = Context.getPointerType(ClassTy); } // If we are within a lambda's call operator, the cv-qualifiers of 'this' // might need to be adjusted if the lambda or any of its enclosing lambda's // captures '*this' by copy. if (!ThisTy.isNull() && isLambdaCallOperator(CurContext)) return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy, CurContext, Context); return ThisTy; } Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, bool Enabled) : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) { if (!Enabled || !ContextDecl) return; CXXRecordDecl *Record = nullptr; if (ClassTemplateDecl *Template = dyn_cast(ContextDecl)) Record = Template->getTemplatedDecl(); else Record = cast(ContextDecl); // We care only for CVR qualifiers here, so cut everything else. CXXThisTypeQuals &= Qualifiers::FastMask; S.CXXThisTypeOverride = S.Context.getPointerType( S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); this->Enabled = true; } Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { if (Enabled) { S.CXXThisTypeOverride = OldCXXThisTypeOverride; } } static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, QualType ThisTy, SourceLocation Loc, const bool ByCopy) { QualType AdjustedThisTy = ThisTy; // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). QualType CaptureThisFieldTy = ThisTy; if (ByCopy) { // If we are capturing the object referred to by '*this' by copy, ignore any // cv qualifiers inherited from the type of the member function for the type // of the closure-type's corresponding data member and any use of 'this'. CaptureThisFieldTy = ThisTy->getPointeeType(); CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask); AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy); } FieldDecl *Field = FieldDecl::Create( Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy, Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); Expr *This = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/ true); if (ByCopy) { Expr *StarThis = S.CreateBuiltinUnaryOp(Loc, UO_Deref, This).get(); InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture( nullptr, CaptureThisFieldTy, Loc); InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); InitializationSequence Init(S, Entity, InitKind, StarThis); ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis); if (ER.isInvalid()) return nullptr; return ER.get(); } return This; } bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); const int MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // Check that we can capture the *enclosing object* (referred to by '*this') // by the capturing-entity/closure (lambda/block/etc) at // MaxFunctionScopesIndex-deep on the FunctionScopes stack. // Note: The *enclosing object* can only be captured by-value by a // closure that is a lambda, using the explicit notation: // [*this] { ... }. // Every other capture of the *enclosing object* results in its by-reference // capture. // For a closure 'L' (at MaxFunctionScopesIndex in the FunctionScopes // stack), we can capture the *enclosing object* only if: // - 'L' has an explicit byref or byval capture of the *enclosing object* // - or, 'L' has an implicit capture. // AND // -- there is no enclosing closure // -- or, there is some enclosing closure 'E' that has already captured the // *enclosing object*, and every intervening closure (if any) between 'E' // and 'L' can implicitly capture the *enclosing object*. // -- or, every enclosing closure can implicitly capture the // *enclosing object* unsigned NumCapturingClosures = 0; for (int idx = MaxFunctionScopesIndex; idx >= 0; idx--) { if (CapturingScopeInfo *CSI = dyn_cast(FunctionScopes[idx])) { if (CSI->CXXThisCaptureIndex != 0) { // 'this' is already being captured; there isn't anything more to do. CSI->Captures[CSI->CXXThisCaptureIndex - 1].markUsed(BuildAndDiagnose); break; } LambdaScopeInfo *LSI = dyn_cast(CSI); if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) { // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || (Explicit && idx == MaxFunctionScopesIndex)) { // Regarding (Explicit && idx == MaxFunctionScopesIndex): only the first // iteration through can be an explicit capture, all enclosing closures, // if any, must perform implicit captures. // This closure can capture 'this'; continue looking upwards. NumCapturingClosures++; continue; } // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } break; } if (!BuildAndDiagnose) return false; // If we got here, then the closure at MaxFunctionScopesIndex on the // FunctionScopes stack, can capture the *enclosing object*, so capture it // (including implicit by-reference captures in any enclosing closures). // In the loop below, respect the ByCopy flag only for the closure requesting // the capture (i.e. first iteration through the loop below). Ignore it for // all enclosing closure's up to NumCapturingClosures (since they must be // implicitly capturing the *enclosing object* by reference (see loop // above)). assert((!ByCopy || dyn_cast(FunctionScopes[MaxFunctionScopesIndex])) && "Only a lambda can capture the enclosing object (referred to by " "*this) by copy"); // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. QualType ThisTy = getCurrentThisType(); for (int idx = MaxFunctionScopesIndex; NumCapturingClosures; --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast(FunctionScopes[idx]); Expr *ThisExpr = nullptr; if (LambdaScopeInfo *LSI = dyn_cast(CSI)) { // For lambda expressions, build a field and an initializing expression, // and capture the *enclosing object* by copy only if this is the first // iteration. ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc, ByCopy && idx == MaxFunctionScopesIndex); } else if (CapturedRegionScopeInfo *RSI = dyn_cast(FunctionScopes[idx])) ThisExpr = captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc, false/*ByCopy*/); bool isNested = NumCapturingClosures > 1; CSI->addThisCapture(isNested, Loc, ThisExpr, ByCopy); } return false; } ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. QualType ThisTy = getCurrentThisType(); if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); CheckCXXThisCapture(Loc); return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false); } bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { // If we're outside the body of a member function, then we'll have a specified // type for 'this'. if (CXXThisTypeOverride.isNull()) return false; // Determine whether we're looking into a class that's currently being // defined. CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); return Class && Class->isBeingDefined(); } /// Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenOrBraceLoc, MultiExprArg exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization) { if (!TypeRep) return ExprError(); TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs, RParenOrBraceLoc, ListInitialization); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without // checking for embedded typos. if (!Result.isInvalid() && Result.get()->isInstantiationDependent() && !Result.get()->isTypeDependent()) Result = CorrectDelayedTyposInExpr(Result.get()); return Result; } ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { // FIXME: CXXUnresolvedConstructExpr does not model list-initialization // directly. We work around this by dropping the locations of the braces. SourceRange Locs = ListInitialization ? SourceRange() : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); return CXXUnresolvedConstructExpr::Create(Context, TInfo, Locs.getBegin(), Exprs, Locs.getEnd()); } assert((!ListInitialization || (Exprs.size() == 1 && isa(Exprs[0]))) && "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization ? InitializationKind::CreateDirectList( TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) : InitializationKind::CreateDirect(TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) : InitializationKind::CreateValue(TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc); // C++1z [expr.type.conv]p1: // If the type is a placeholder for a deduced class type, [...perform class // template argument deduction...] DeducedType *Deduced = Ty->getContainedDeducedType(); if (Deduced && isa(Deduced)) { Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, Kind, Exprs); if (Ty.isNull()) return ExprError(); Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } // C++ [expr.type.conv]p1: // If the expression list is a parenthesized single expression, the type // conversion expression is equivalent (in definedness, and if defined in // meaning) to the corresponding cast expression. if (Exprs.size() == 1 && !ListInitialization && !isa(Exprs[0])) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg, RParenOrBraceLoc); } // For an expression of the form T(), T shall not be an array type. QualType ElemTy = Ty; if (Ty->isArrayType()) { if (!ListInitialization) return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange); ElemTy = Context.getBaseElementType(Ty); } // There doesn't seem to be an explicit rule against this but sanity demands // we only construct objects with object types. if (Ty->isFunctionType()) return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type) << Ty << FullRange); // C++17 [expr.type.conv]p2: // If the type is cv void and the initializer is (), the expression is a // prvalue of the specified type that performs no initialization. if (!Ty->isVoidType() && RequireCompleteType(TyBeginLoc, ElemTy, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); // Otherwise, the expression is a prvalue of the specified type whose // result object is direct-initialized (11.6) with the initializer. InitializationSequence InitSeq(*this, Entity, Kind, Exprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); if (Result.isInvalid()) return Result; Expr *Inner = Result.get(); if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null(Inner)) Inner = BTE->getSubExpr(); if (!isa(Inner) && !isa(Inner)) { // If we created a CXXTemporaryObjectExpr, that node also represents the // functional cast. Otherwise, create an explicit cast to represent // the syntactic form of a functional-style cast that was used here. // // FIXME: Creating a CXXFunctionalCastExpr around a CXXConstructExpr // would give a more consistent AST representation than using a // CXXTemporaryObjectExpr. It's also weird that the functional cast // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); SourceRange Locs = ListInitialization ? SourceRange() : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); Result = CXXFunctionalCastExpr::Create( Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp, Result.get(), /*Path=*/nullptr, Locs.getBegin(), Locs.getEnd()); } return Result; } /// Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { if (CXXMethodDecl *Method = dyn_cast(FD)) return Method->isUsualDeallocationFunction(); if (FD->getOverloadedOperator() != OO_Delete && FD->getOverloadedOperator() != OO_Array_Delete) return false; unsigned UsualParams = 1; if (S.getLangOpts().SizedDeallocation && UsualParams < FD->getNumParams() && S.Context.hasSameUnqualifiedType( FD->getParamDecl(UsualParams)->getType(), S.Context.getSizeType())) ++UsualParams; if (S.getLangOpts().AlignedAllocation && UsualParams < FD->getNumParams() && S.Context.hasSameUnqualifiedType( FD->getParamDecl(UsualParams)->getType(), S.Context.getTypeDeclType(S.getStdAlignValT()))) ++UsualParams; return UsualParams == FD->getNumParams(); } namespace { struct UsualDeallocFnInfo { UsualDeallocFnInfo() : Found(), FD(nullptr) {} UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) : Found(Found), FD(dyn_cast(Found->getUnderlyingDecl())), Destroying(false), HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { // A function template declaration is never a usual deallocation function. if (!FD) return; unsigned NumBaseParams = 1; if (FD->isDestroyingOperatorDelete()) { Destroying = true; ++NumBaseParams; } if (FD->getNumParams() == NumBaseParams + 2) HasAlignValT = HasSizeT = true; else if (FD->getNumParams() == NumBaseParams + 1) { HasSizeT = FD->getParamDecl(NumBaseParams)->getType()->isIntegerType(); HasAlignValT = !HasSizeT; } // In CUDA, determine how much we'd like / dislike to call this. if (S.getLangOpts().CUDA) if (auto *Caller = dyn_cast(S.CurContext)) CUDAPref = S.IdentifyCUDAPreference(Caller, FD); } explicit operator bool() const { return FD; } bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { // C++ P0722: // A destroying operator delete is preferred over a non-destroying // operator delete. if (Destroying != Other.Destroying) return Destroying; // C++17 [expr.delete]p10: // If the type has new-extended alignment, a function with a parameter // of type std::align_val_t is preferred; otherwise a function without // such a parameter is preferred if (HasAlignValT != Other.HasAlignValT) return HasAlignValT == WantAlign; if (HasSizeT != Other.HasSizeT) return HasSizeT == WantSize; // Use CUDA call preference as a tiebreaker. return CUDAPref > Other.CUDAPref; } DeclAccessPair Found; FunctionDecl *FD; bool Destroying, HasSizeT, HasAlignValT; Sema::CUDAFunctionPreference CUDAPref; }; } /// Determine whether a type has new-extended alignment. This may be called when /// the type is incomplete (for a delete-expression with an incomplete pointee /// type), in which case it will conservatively return false if the alignment is /// not known. static bool hasNewExtendedAlignment(Sema &S, QualType AllocType) { return S.getLangOpts().AlignedAllocation && S.getASTContext().getTypeAlignIfKnown(AllocType) > S.getASTContext().getTargetInfo().getNewAlign(); } /// Select the correct "usual" deallocation function to use from a selection of /// deallocation functions (either global or class-scope). static UsualDeallocFnInfo resolveDeallocationOverload( Sema &S, LookupResult &R, bool WantSize, bool WantAlign, llvm::SmallVectorImpl *BestFns = nullptr) { UsualDeallocFnInfo Best; for (auto I = R.begin(), E = R.end(); I != E; ++I) { UsualDeallocFnInfo Info(S, I.getPair()); if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) || Info.CUDAPref == Sema::CFP_Never) continue; if (!Best) { Best = Info; if (BestFns) BestFns->push_back(Info); continue; } if (Best.isBetterThan(Info, WantSize, WantAlign)) continue; // If more than one preferred function is found, all non-preferred // functions are eliminated from further consideration. if (BestFns && Info.isBetterThan(Best, WantSize, WantAlign)) BestFns->clear(); Best = Info; if (BestFns) BestFns->push_back(Info); } return Best; } /// Determine whether a given type is a class for which 'delete[]' would call /// a member 'operator delete[]' with a 'size_t' parameter. This implies that /// we need to store the array size (even if the type is /// trivially-destructible). static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, QualType allocType) { const RecordType *record = allocType->getBaseElementTypeUnsafe()->getAs(); if (!record) return false; // Try to find an operator delete[] in class scope. DeclarationName deleteName = S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(ops, record->getDecl()); // We're just doing this for information. ops.suppressDiagnostics(); // Very likely: there's no operator delete[]. if (ops.empty()) return false; // If it's ambiguous, it should be illegal to call operator delete[] // on this thing, so it doesn't matter if we allocate extra space or not. if (ops.isAmbiguous()) return false; // C++17 [expr.delete]p10: // If the deallocation functions have class scope, the one without a // parameter of type std::size_t is selected. auto Best = resolveDeallocationOverload( S, ops, /*WantSize*/false, /*WantAlign*/hasNewExtendedAlignment(S, allocType)); return Best && Best.HasSizeT; } /// Parsed a C++ 'new' expression (C++ 5.3.4). /// /// E.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// /// \param StartLoc The first location of the expression. /// \param UseGlobal True if 'new' was prefixed with '::'. /// \param PlacementLParen Opening paren of the placement arguments. /// \param PlacementArgs Placement new arguments. /// \param PlacementRParen Closing paren of the placement arguments. /// \param TypeIdParens If the type is in parens, the source range. /// \param D The type to be allocated, as well as array dimensions. /// \param Initializer The initializing expression or initializer-list, or null /// if there is none. ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { Expr *ArraySize = nullptr; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (D.getDeclSpec().hasAutoTypeSpec()) return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) << D.getSourceRange()); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast(Chunk.Arr.NumElts); D.DropFirstTypeObject(); } // Every dimension shall be of constant size. if (ArraySize) { for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) break; DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; if (Expr *NumElts = (Expr *)Array.NumElts) { if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { if (getLangOpts().CPlusPlus14) { // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator // shall be a converted constant expression (5.19) of type std::size_t // and shall evaluate to a strictly positive value. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); assert(IntWidth && "Builtin type of size 0?"); llvm::APSInt Value(IntWidth); Array.NumElts = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value, CCEK_NewExpr) .get(); } else { Array.NumElts = VerifyIntegerConstantExpression(NumElts, nullptr, diag::err_new_array_nonconst) .get(); } if (!Array.NumElts) return ExprError(); } } } } TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/nullptr); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); SourceRange DirectInitRange; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) DirectInitRange = List->getSourceRange(); return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, PlacementLParen, PlacementArgs, PlacementRParen, TypeIdParens, AllocType, TInfo, ArraySize, DirectInitRange, Initializer); } static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, Expr *Init) { if (!Init) return true; if (ParenListExpr *PLE = dyn_cast(Init)) return PLE->getNumExprs() == 0; if (isa(Init)) return true; else if (CXXConstructExpr *CCE = dyn_cast(Init)) return !CCE->isListInitialization() && CCE->getConstructor()->isDefaultConstructor(); else if (Style == CXXNewExpr::ListInit) { assert(isa(Init) && "Shouldn't create list CXXConstructExprs for arrays."); return true; } return false; } // Emit a diagnostic if an aligned allocation/deallocation function that is not // implemented in the standard library is selected. static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, SourceLocation Loc, bool IsDelete, Sema &S) { if (!S.getLangOpts().AlignedAllocationUnavailable) return; // Return if there is a definition. if (FD.isDefined()) return; bool IsAligned = false; if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( S.getASTContext().getTargetInfo().getPlatformName()); S.Diag(Loc, diag::warn_aligned_allocation_unavailable) << IsDelete << FD.getType().getAsString() << OSName << alignedAllocMinVersion(T.getOS()).getAsString(); S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); } } ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceRange DirectInitRange, Expr *Initializer) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); SourceLocation StartLoc = Range.getBegin(); CXXNewExpr::InitializationStyle initStyle; if (DirectInitRange.isValid()) { assert(Initializer && "Have parens but no initializer."); initStyle = CXXNewExpr::CallInit; } else if (Initializer && isa(Initializer)) initStyle = CXXNewExpr::ListInit; else { assert((!Initializer || isa(Initializer) || isa(Initializer)) && "Initializer expression that cannot have been implicitly created."); initStyle = CXXNewExpr::NoInit; } Expr **Inits = &Initializer; unsigned NumInits = Initializer ? 1 : 0; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) { assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init"); Inits = List->getExprs(); NumInits = List->getNumExprs(); } // C++11 [expr.new]p15: // A new-expression that creates an object of type T initializes that // object as follows: InitializationKind Kind // - If the new-initializer is omitted, the object is default- // initialized (8.5); if no initialization is performed, // the object has indeterminate value = initStyle == CXXNewExpr::NoInit ? InitializationKind::CreateDefault(TypeRange.getBegin()) // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. : initStyle == CXXNewExpr::ListInit ? InitializationKind::CreateDirectList(TypeRange.getBegin(), Initializer->getLocStart(), Initializer->getLocEnd()) : InitializationKind::CreateDirect(TypeRange.getBegin(), DirectInitRange.getBegin(), DirectInitRange.getEnd()); // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. auto *Deduced = AllocType->getContainedDeducedType(); if (Deduced && isa(Deduced)) { if (ArraySize) return ExprError(Diag(ArraySize->getExprLoc(), diag::err_deduced_class_template_compound_type) << /*array*/ 2 << ArraySize->getSourceRange()); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); AllocType = DeduceTemplateSpecializationFromInitializer( AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits)); if (AllocType.isNull()) return ExprError(); } else if (Deduced) { bool Braced = (initStyle == CXXNewExpr::ListInit); if (NumInits == 1) { if (auto p = dyn_cast_or_null(Inits[0])) { Inits = p->getInits(); NumInits = p->getNumInits(); Braced = true; } } if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); if (NumInits > 1) { Expr *FirstBad = Inits[1]; return ExprError(Diag(FirstBad->getLocStart(), diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } if (Braced && !getLangOpts().CPlusPlus17) Diag(Initializer->getLocStart(), diag::ext_auto_new_list_init) << AllocType << TypeRange; Expr *Deduce = Inits[0]; QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); if (DeducedType.isNull()) return ExprError(); AllocType = DeducedType; } // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { if (const ConstantArrayType *Array = Context.getAsConstantArrayType(AllocType)) { ArraySize = IntegerLiteral::Create(Context, Array->getSize(), Context.getSizeType(), TypeRange.getEnd()); AllocType = Array->getElementType(); } } if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && AllocType->isObjCLifetimeType()) { AllocType = Context.getLifetimeQualifiedType(AllocType, AllocType->getObjCARCImplicitLifetime()); } QualType ResultType = Context.getPointerType(AllocType); if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(ArraySize); if (result.isInvalid()) return ExprError(); ArraySize = result.get(); } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped // enumeration type, or a class type for which a single non-explicit // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. llvm::Optional KnownArraySize; if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), AA_Converting); if (!ConvertedSize.isInvalid() && ArraySize->getType()->getAs()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) << ArraySize->getType() << 0 << "'size_t'"; } else { class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: Expr *ArraySize; public: SizeConvertDiagnoser(Expr *ArraySize) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), ArraySize(ArraySize) {} SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_not_integral) << S.getLangOpts().CPlusPlus11 << T; } SemaDiagnosticBuilder diagnoseIncomplete( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_incomplete_type) << T << ArraySize->getSourceRange(); } SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; } SemaDiagnosticBuilder noteAmbiguous( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_array_size_conversion : diag::ext_array_size_conversion) << T << ConvTy->isEnumeralType() << ConvTy; } } SizeDiagnoser(ArraySize); ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize, SizeDiagnoser); } if (ConvertedSize.isInvalid()) return ExprError(); ArraySize = ConvertedSize.get(); QualType SizeType = ArraySize->getType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); // C++98 [expr.new]p7: // The expression in a direct-new-declarator shall have integral type // with a non-negative value. // // Let's see if this is a constant < 0. If so, we reject it out of hand, // per CWG1464. Otherwise, if it's not a constant, we must have an // unparenthesized array type. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. // FIXME: Per CWG1464, we are required to check the value prior to // converting to size_t. This will never find a negative array size in // C++14 onwards, because Value is always unsigned here! if (ArraySize->isIntegerConstantExpr(Value, Context)) { if (Value.isSigned() && Value.isNegative()) { return ExprError(Diag(ArraySize->getLocStart(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) return ExprError(Diag(ArraySize->getLocStart(), diag::err_array_too_large) << Value.toString(10) << ArraySize->getSourceRange()); } KnownArraySize = Value.getZExtValue(); } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst) << ArraySize->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); TypeIdParens = SourceRange(); } } // Note that we do *not* convert the argument in any way. It can // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; unsigned Alignment = AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType); unsigned NewAlignment = Context.getTargetInfo().getNewAlign(); bool PassAlignment = getLangOpts().AlignedAllocation && Alignment > NewAlignment; AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope, AllocType, ArraySize, PassAlignment, PlacementArgs, OperatorNew, OperatorDelete)) return ExprError(); // If this is an array allocation, compute whether the usual array // deallocation function for the type has a size_t parameter. bool UsualArrayDeleteWantsSize = false; if (ArraySize && !AllocType->isDependentType()) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); SmallVector AllPlaceArgs; if (OperatorNew) { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; // We've already converted the placement args, just fill in any default // arguments. Skip the first parameter because we don't have a corresponding // argument. Skip the second parameter too if we're passing in the // alignment; we've already filled it in. if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, PassAlignment ? 2 : 1, PlacementArgs, AllPlaceArgs, CallType)) return ExprError(); if (!AllPlaceArgs.empty()) PlacementArgs = AllPlaceArgs; // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); // FIXME: Missing call to CheckFunctionCall or equivalent // Warn if the type is over-aligned and is being allocated by (unaligned) // global operator new. if (PlacementArgs.empty() && !PassAlignment && (OperatorNew->isImplicit() || (OperatorNew->getLocStart().isValid() && getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { if (Alignment > NewAlignment) Diag(StartLoc, diag::warn_overaligned_type) << AllocType << unsigned(Alignment / Context.getCharWidth()) << unsigned(NewAlignment / Context.getCharWidth()); } } // Array 'new' can't have any initializers except empty parentheses. // Initializer lists are also allowed, in C++11. Rely on the parser for the // dialect distinction. if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) { SourceRange InitRange(Inits[0]->getLocStart(), Inits[NumInits - 1]->getLocEnd()); Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } // If we can perform the initialization, and we've not already done so, // do it now. if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments( llvm::makeArrayRef(Inits, NumInits))) { // The type we initialize is the complete type, including the array bound. QualType InitType; if (KnownArraySize) InitType = Context.getConstantArrayType( AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), *KnownArraySize), ArrayType::Normal, 0); else if (ArraySize) InitType = Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0); else InitType = AllocType; InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) return ExprError(); // FullInit is our initializer; strip off CXXBindTemporaryExprs, because // we don't want the initialized object to be destructed. // FIXME: We should not create these in the first place. if (CXXBindTemporaryExpr *Binder = dyn_cast_or_null(FullInit.get())) FullInit = Binder->getSubExpr(); Initializer = FullInit.get(); } // Mark the new and delete operators as referenced. if (OperatorNew) { if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this); } if (OperatorDelete) { if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this); } // C++0x [expr.new]p17: // If the new expression creates an array of objects of class type, // access and ambiguity control are done for the destructor. QualType BaseAllocType = Context.getBaseElementType(AllocType); if (ArraySize && !BaseAllocType->isDependentType()) { if (const RecordType *BaseRecordType = BaseAllocType->getAs()) { if (CXXDestructorDecl *dtor = LookupDestructor( cast(BaseRecordType->getDecl()))) { MarkFunctionReferenced(StartLoc, dtor); CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); if (DiagnoseUseOfDecl(dtor, StartLoc)) return ExprError(); } } } return new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, PassAlignment, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange); } /// Checks that a type is suitable as the allocated type /// in a new-expression. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 0 << R; else if (AllocType->isReferenceType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 1 << R; else if (!AllocType->isDependentType() && RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; else if (AllocType.getAddressSpace() != LangAS::Default && !getLangOpts().OpenCLCPlusPlus) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); else if (getLangOpts().ObjCAutoRefCount) { if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { QualType BaseAllocType = Context.getBaseElementType(AT); if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None && BaseAllocType->isObjCLifetimeType()) return Diag(Loc, diag::err_arc_new_array_without_ownership) << BaseAllocType; } } return false; } static bool resolveAllocationOverload( Sema &S, LookupResult &R, SourceRange Range, SmallVectorImpl &Args, bool &PassAlignment, FunctionDecl *&Operator, OverloadCandidateSet *AlignedCandidates, Expr *AlignArg, bool Diagnose) { OverloadCandidateSet Candidates(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. NamedDecl *D = (*Alloc)->getUnderlyingDecl(); if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, Candidates, /*SuppressUserConversions=*/false); continue; } FunctionDecl *Fn = cast(D); S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, /*SuppressUserConversions=*/false); } // Do the resolution. OverloadCandidateSet::iterator Best; switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(), Best->FoundDecl) == Sema::AR_inaccessible) return true; Operator = FnDecl; return false; } case OR_No_Viable_Function: // C++17 [expr.new]p13: // If no matching function is found and the allocated object type has // new-extended alignment, the alignment argument is removed from the // argument list, and overload resolution is performed again. if (PassAlignment) { PassAlignment = false; AlignArg = Args[1]; Args.erase(Args.begin() + 1); return resolveAllocationOverload(S, R, Range, Args, PassAlignment, Operator, &Candidates, AlignArg, Diagnose); } // MSVC will fall back on trying to find a matching global operator new // if operator new[] cannot be found. Also, MSVC will leak by not // generating a call to operator delete or operator delete[], but we // will not replicate that bug. // FIXME: Find out how this interacts with the std::align_val_t fallback // once MSVC implements it. if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New && S.Context.getLangOpts().MSVCCompat) { R.clear(); R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New)); S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); // FIXME: This will give bad diagnostics pointing at the wrong functions. return resolveAllocationOverload(S, R, Range, Args, PassAlignment, Operator, /*Candidates=*/nullptr, /*AlignArg=*/nullptr, Diagnose); } if (Diagnose) { S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) << R.getLookupName() << Range; // If we have aligned candidates, only note the align_val_t candidates // from AlignedCandidates and the non-align_val_t candidates from // Candidates. if (AlignedCandidates) { auto IsAligned = [](OverloadCandidate &C) { return C.Function->getNumParams() > 1 && C.Function->getParamDecl(1)->getType()->isAlignValT(); }; auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; // This was an overaligned allocation, so list the aligned candidates // first. Args.insert(Args.begin() + 1, AlignArg); AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsAligned); Args.erase(Args.begin() + 1); Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsUnaligned); } else { Candidates.NoteCandidates(S, OCD_AllCandidates, Args); } } return true; case OR_Ambiguous: if (Diagnose) { S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName() << Range; Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); } return true; case OR_Deleted: { if (Diagnose) { S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) << Best->Function->isDeleted() << R.getLookupName() << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; Candidates.NoteCandidates(S, OCD_AllCandidates, Args); } return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope, QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete, bool Diagnose) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 // 1) If looking in AFS_Global scope for allocation functions, only look in // the global scope. Else, if AFS_Class, only look in the scope of the // allocated class. If AFS_Both, look in both. // 2) If an array size is given, look for operator new[], else look for // operator new. // 3) The first argument is always size_t. Append the arguments from the // placement form. SmallVector AllocArgs; AllocArgs.reserve((PassAlignment ? 2 : 1) + PlaceArgs.size()); // We don't care about the actual value of these arguments. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? // FIXME: Using a dummy value will interact poorly with attribute enable_if. IntegerLiteral Size(Context, llvm::APInt::getNullValue( Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); AllocArgs.push_back(&Size); QualType AlignValT = Context.VoidTy; if (PassAlignment) { DeclareGlobalNewDelete(); AlignValT = Context.getTypeDeclType(getStdAlignValT()); } CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation()); if (PassAlignment) AllocArgs.push_back(&Align); AllocArgs.insert(AllocArgs.end(), PlaceArgs.begin(), PlaceArgs.end()); // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array // type, the allocation function's name is operator new[] and the // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); QualType AllocElemType = Context.getBaseElementType(AllocType); // Find the allocation function. { LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName); // C++1z [expr.new]p9: // If the new-expression begins with a unary :: operator, the allocation // function's name is looked up in the global scope. Otherwise, if the // allocated type is a class type T or array thereof, the allocation // function's name is looked up in the scope of T. if (AllocElemType->isRecordType() && NewScope != AFS_Global) LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl()); // We can see ambiguity here if the allocation function is found in // multiple base classes. if (R.isAmbiguous()) return true; // If this lookup fails to find the name, or if the allocated type is not // a class type, the allocation function's name is looked up in the // global scope. if (R.empty()) { if (NewScope == AFS_Class) return true; LookupQualifiedName(R, Context.getTranslationUnitDecl()); } if (getLangOpts().OpenCLCPlusPlus && R.empty()) { Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new"; return true; } assert(!R.empty() && "implicitly declared allocation functions not found"); assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); // We do our own custom access checks below. R.suppressDiagnostics(); if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment, OperatorNew, /*Candidates=*/nullptr, /*AlignArg=*/nullptr, Diagnose)) return true; } // We don't need an operator delete if we're running under -fno-exceptions. if (!getLangOpts().Exceptions) { OperatorDelete = nullptr; return false; } // Note, the name of OperatorNew might have been changed from array to // non-array by resolveAllocationOverload. DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( OperatorNew->getDeclName().getCXXOverloadedOperator() == OO_Array_New ? OO_Array_Delete : OO_Delete); // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) { CXXRecordDecl *RD = cast(AllocElemType->getAs()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) return true; // FIXME: clean up expressions? bool FoundGlobalDelete = FoundDelete.empty(); if (FoundDelete.empty()) { if (DeleteScope == AFS_Class) return true; DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); } FoundDelete.suppressDiagnostics(); SmallVector, 2> Matches; // Whether we're looking for a placement operator delete is dictated // by whether we selected a placement operator new, not by whether // we had explicit placement arguments. This matters for things like // struct A { void *operator new(size_t, int = 0); ... }; // A *a = new A() // // We don't have any definition for what a "placement allocation function" // is, but we assume it's any allocation function whose // parameter-declaration-clause is anything other than (size_t). // // FIXME: Should (size_t, std::align_val_t) also be considered non-placement? // This affects whether an exception from the constructor of an overaligned // type uses the sized or non-sized form of aligned operator delete. bool isPlacementNew = !PlaceArgs.empty() || OperatorNew->param_size() != 1 || OperatorNew->isVariadic(); if (isPlacementNew) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. QualType ExpectedFunctionType; { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); SmallVector ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumParams(); I < N; ++I) ArgTypes.push_back(Proto->getParamType(I)); FunctionProtoType::ExtProtoInfo EPI; // FIXME: This is not part of the standard's rule. EPI.Variadic = Proto->isVariadic(); ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI); } for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; if (FunctionTemplateDecl *FnTmpl = dyn_cast((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn, Info)) continue; } else Fn = cast((*D)->getUnderlyingDecl()); if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(), ExpectedFunctionType, /*AdjustExcpetionSpec*/true), ExpectedFunctionType)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast(CurContext), Matches); } else { // C++1y [expr.new]p22: // For a non-placement allocation function, the normal deallocation // function lookup is used // // Per [expr.delete]p10, this lookup prefers a member operator delete // without a size_t argument, but prefers a non-member operator delete // with a size_t where possible (which it always is in this case). llvm::SmallVector BestDeallocFns; UsualDeallocFnInfo Selected = resolveDeallocationOverload( *this, FoundDelete, /*WantSize*/ FoundGlobalDelete, /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType), &BestDeallocFns); if (Selected) Matches.push_back(std::make_pair(Selected.Found, Selected.FD)); else { // If we failed to select an operator, all remaining functions are viable // but ambiguous. for (auto Fn : BestDeallocFns) Matches.push_back(std::make_pair(Fn.Found, Fn.FD)); } } // C++ [expr.new]p20: // [...] If the lookup finds a single matching deallocation // function, that function will be called; otherwise, no // deallocation function will be called. if (Matches.size() == 1) { OperatorDelete = Matches[0].second; // C++1z [expr.new]p23: // If the lookup finds a usual deallocation function (3.7.4.2) // with a parameter of type std::size_t and that function, considered // as a placement deallocation function, would have been // selected as a match for the allocation function, the program // is ill-formed. if (getLangOpts().CPlusPlus11 && isPlacementNew && isNonPlacementDeallocationFunction(*this, OperatorDelete)) { UsualDeallocFnInfo Info(*this, DeclAccessPair::make(OperatorDelete, AS_public)); // Core issue, per mail to core reflector, 2016-10-09: // If this is a member operator delete, and there is a corresponding // non-sized member operator delete, this isn't /really/ a sized // deallocation function, it just happens to have a size_t parameter. bool IsSizedDelete = Info.HasSizeT; if (IsSizedDelete && !FoundGlobalDelete) { auto NonSizedDelete = resolveDeallocationOverload(*this, FoundDelete, /*WantSize*/false, /*WantAlign*/Info.HasAlignValT); if (NonSizedDelete && !NonSizedDelete.HasSizeT && NonSizedDelete.HasAlignValT == Info.HasAlignValT) IsSizedDelete = false; } if (IsSizedDelete) { SourceRange R = PlaceArgs.empty() ? SourceRange() : SourceRange(PlaceArgs.front()->getLocStart(), PlaceArgs.back()->getLocEnd()); Diag(StartLoc, diag::err_placement_new_non_placement_delete) << R; if (!OperatorDelete->isImplicit()) Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; } } CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), Matches[0].first); } else if (!Matches.empty()) { // We found multiple suitable operators. Per [expr.new]p20, that means we // call no 'operator delete' function, but we should at least warn the user. // FIXME: Suppress this warning if the construction cannot throw. Diag(StartLoc, diag::warn_ambiguous_suitable_delete_function_found) << DeleteName << AllocElemType; for (auto &Match : Matches) Diag(Match.second->getLocation(), diag::note_member_declared_here) << DeleteName; } return false; } /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code /// // C++03: /// void* operator new(std::size_t) throw(std::bad_alloc); /// void* operator new[](std::size_t) throw(std::bad_alloc); /// void operator delete(void *) throw(); /// void operator delete[](void *) throw(); /// // C++11: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// // C++1y: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// void operator delete(void *, std::size_t) noexcept; /// void operator delete[](void *, std::size_t) noexcept; /// @endcode /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \. void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; // OpenCL C++ 1.0 s2.9: the implicitly declared new and delete operators // are not supported. if (getLangOpts().OpenCLCPlusPlus) return; // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are // implicitly declared in global scope in each translation unit of a // program // // C++03: // void* operator new(std::size_t) throw(std::bad_alloc); // void* operator new[](std::size_t) throw(std::bad_alloc); // void operator delete(void*) throw(); // void operator delete[](void*) throw(); // C++11: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // C++1y: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // void operator delete(void*, std::size_t) noexcept; // void operator delete[](void*, std::size_t) noexcept; // // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. // // Here, we need to refer to std::bad_alloc, so we will implicitly declare // "std" or "bad_alloc" as necessary to form the exception specification. // However, we do not make these implicit declarations visible to name // lookup. if (!StdBadAlloc && !getLangOpts().CPlusPlus11) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), nullptr); getStdBadAlloc()->setImplicit(true); } if (!StdAlignValT && getLangOpts().AlignedAllocation) { // The "std::align_val_t" enum class has not yet been declared, so build it // implicitly. auto *AlignValT = EnumDecl::Create( Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); AlignValT->setIntegerType(Context.getSizeType()); AlignValT->setPromotionType(Context.getSizeType()); AlignValT->setImplicit(true); StdAlignValT = AlignValT; } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); auto DeclareGlobalAllocationFunctions = [&](OverloadedOperatorKind Kind, QualType Return, QualType Param) { llvm::SmallVector Params; Params.push_back(Param); // Create up to four variants of the function (sized/aligned). bool HasSizedVariant = getLangOpts().SizedDeallocation && (Kind == OO_Delete || Kind == OO_Array_Delete); bool HasAlignedVariant = getLangOpts().AlignedAllocation; int NumSizeVariants = (HasSizedVariant ? 2 : 1); int NumAlignVariants = (HasAlignedVariant ? 2 : 1); for (int Sized = 0; Sized < NumSizeVariants; ++Sized) { if (Sized) Params.push_back(SizeT); for (int Aligned = 0; Aligned < NumAlignVariants; ++Aligned) { if (Aligned) Params.push_back(Context.getTypeDeclType(getStdAlignValT())); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(Kind), Return, Params); if (Aligned) Params.pop_back(); } } }; DeclareGlobalAllocationFunctions(OO_New, VoidPtr, SizeT); DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); } /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef Params) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Only look at non-template functions, as it is the predefined, // non-templated allocation function we are trying to declare here. if (FunctionDecl *Func = dyn_cast(*Alloc)) { if (Func->getNumParams() == Params.size()) { llvm::SmallVector FuncParams; for (auto *P : Func->parameters()) FuncParams.push_back( Context.getCanonicalType(P->getType().getUnqualifiedType())); if (llvm::makeArrayRef(FuncParams) == Params) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. Func->setVisibleDespiteOwningModule(); return; } } } } FunctionProtoType::ExtProtoInfo EPI; QualType BadAllocType; bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { if (!getLangOpts().CPlusPlus11) { BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); assert(StdBadAlloc && "Must have std::bad_alloc declared"); EPI.ExceptionSpec.Type = EST_Dynamic; EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } } else { EPI.ExceptionSpec = getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } auto CreateAllocationFunctionDecl = [&](Attr *ExtraAttr) { QualType FnType = Context.getFunctionType(Return, Params, EPI); FunctionDecl *Alloc = FunctionDecl::Create( Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, FnType, /*TInfo=*/nullptr, SC_None, false, true); Alloc->setImplicit(); // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); // Implicit sized deallocation functions always have default visibility. Alloc->addAttr( VisibilityAttr::CreateImplicit(Context, VisibilityAttr::Default)); llvm::SmallVector ParamDecls; for (QualType T : Params) { ParamDecls.push_back(ParmVarDecl::Create( Context, Alloc, SourceLocation(), SourceLocation(), nullptr, T, /*TInfo=*/nullptr, SC_None, nullptr)); ParamDecls.back()->setImplicit(); } Alloc->setParams(ParamDecls); if (ExtraAttr) Alloc->addAttr(ExtraAttr); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); }; if (!LangOpts.CUDA) CreateAllocationFunctionDecl(nullptr); else { // Host and device get their own declaration so each can be // defined or re-declared independently. CreateAllocationFunctionDecl(CUDAHostAttr::CreateImplicit(Context)); CreateAllocationFunctionDecl(CUDADeviceAttr::CreateImplicit(Context)); } } FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, bool Overaligned, DeclarationName Name) { DeclareGlobalNewDelete(); LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); // FIXME: It's possible for this to result in ambiguity, through a // user-declared variadic operator delete or the enable_if attribute. We // should probably not consider those cases to be usual deallocation // functions. But for now we just make an arbitrary choice in that case. auto Result = resolveDeallocationOverload(*this, FoundDelete, CanProvideSize, Overaligned); assert(Result.FD && "operator delete missing from global scope?"); return Result.FD; } FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc, CXXRecordDecl *RD) { DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); FunctionDecl *OperatorDelete = nullptr; if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) return nullptr; if (OperatorDelete) return OperatorDelete; // If there's no class-specific operator delete, look up the global // non-array delete. return FindUsualDeallocationFunction( Loc, true, hasNewExtendedAlignment(*this, Context.getRecordType(RD)), Name); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl *&Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); if (Found.isAmbiguous()) return true; Found.suppressDiagnostics(); bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD)); // C++17 [expr.delete]p10: // If the deallocation functions have class scope, the one without a // parameter of type std::size_t is selected. llvm::SmallVector Matches; resolveDeallocationOverload(*this, Found, /*WantSize*/ false, /*WantAlign*/ Overaligned, &Matches); // If we could find an overload, use it. if (Matches.size() == 1) { Operator = cast(Matches[0].FD); // FIXME: DiagnoseUseOfDecl? if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); NoteDeletedFunction(Operator); } return true; } if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), Matches[0].Found, Diagnose) == AR_inaccessible) return true; return false; } // We found multiple suitable operators; complain about the ambiguity. // FIXME: The standard doesn't say to do this; it appears that the intent // is that this should never happen. if (!Matches.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; for (auto &Match : Matches) Diag(Match.FD->getLocation(), diag::note_member_declared_here) << Name; } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; for (NamedDecl *D : Found) Diag(D->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; } Operator = nullptr; return false; } namespace { /// Checks whether delete-expression, and new-expression used for /// initializing deletee have the same array form. class MismatchingNewDeleteDetector { public: enum MismatchResult { /// Indicates that there is no mismatch or a mismatch cannot be proven. NoMismatch, /// Indicates that variable is initialized with mismatching form of \a new. VarInitMismatches, /// Indicates that member is initialized with mismatching form of \a new. MemberInitMismatches, /// Indicates that 1 or more constructors' definitions could not been /// analyzed, and they will be checked again at the end of translation unit. AnalyzeLater }; /// \param EndOfTU True, if this is the final analysis at the end of /// translation unit. False, if this is the initial analysis at the point /// delete-expression was encountered. explicit MismatchingNewDeleteDetector(bool EndOfTU) : Field(nullptr), IsArrayForm(false), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} /// Checks whether pointee of a delete-expression is initialized with /// matching form of new-expression. /// /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the /// point where delete-expression is encountered, then a warning will be /// issued immediately. If return value is \c AnalyzeLater at the point where /// delete-expression is seen, then member will be analyzed at the end of /// translation unit. \c AnalyzeLater is returned iff at least one constructor /// couldn't be analyzed. If at least one constructor initializes the member /// with matching type of new, the return value is \c NoMismatch. MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); /// Analyzes a class member. /// \param Field Class member to analyze. /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); FieldDecl *Field; /// List of mismatching new-expressions used for initialization of the pointee llvm::SmallVector NewExprs; /// Indicates whether delete-expression was in array form. bool IsArrayForm; private: const bool EndOfTU; /// Indicates that there is at least one constructor without body. bool HasUndefinedConstructors; /// Returns \c CXXNewExpr from given initialization expression. /// \param E Expression used for initializing pointee in delete-expression. /// E can be a single-element \c InitListExpr consisting of new-expression. const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); /// Returns whether member is initialized with mismatching form of /// \c new either by the member initializer or in-class initialization. /// /// If bodies of all constructors are not visible at the end of translation /// unit or at least one constructor initializes member with the matching /// form of \c new, mismatch cannot be proven, and this function will return /// \c NoMismatch. MismatchResult analyzeMemberExpr(const MemberExpr *ME); /// Returns whether variable is initialized with mismatching form of /// \c new. /// /// If variable is initialized with matching form of \c new or variable is not /// initialized with a \c new expression, this function will return true. /// If variable is initialized with mismatching form of \c new, returns false. /// \param D Variable to analyze. bool hasMatchingVarInit(const DeclRefExpr *D); /// Checks whether the constructor initializes pointee with mismatching /// form of \c new. /// /// Returns true, if member is initialized with matching form of \c new in /// member initializer list. Returns false, if member is initialized with the /// matching form of \c new in this constructor's initializer or given /// constructor isn't defined at the point where delete-expression is seen, or /// member isn't initialized by the constructor. bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); /// Checks whether member is initialized with matching form of /// \c new in member initializer list. bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); /// Checks whether member is initialized with mismatching form of \c new by /// in-class initializer. MismatchResult analyzeInClassInitializer(); }; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE) { NewExprs.clear(); assert(DE && "Expected delete-expression"); IsArrayForm = DE->isArrayForm(); const Expr *E = DE->getArgument()->IgnoreParenImpCasts(); if (const MemberExpr *ME = dyn_cast(E)) { return analyzeMemberExpr(ME); } else if (const DeclRefExpr *D = dyn_cast(E)) { if (!hasMatchingVarInit(D)) return VarInitMismatches; } return NoMismatch; } const CXXNewExpr * MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E) { assert(E != nullptr && "Expected a valid initializer expression"); E = E->IgnoreParenImpCasts(); if (const InitListExpr *ILE = dyn_cast(E)) { if (ILE->getNumInits() == 1) E = dyn_cast(ILE->getInit(0)->IgnoreParenImpCasts()); } return dyn_cast_or_null(E); } bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit( const CXXCtorInitializer *CI) { const CXXNewExpr *NE = nullptr; if (Field == CI->getMember() && (NE = getNewExprFromInitListOrExpr(CI->getInit()))) { if (NE->isArray() == IsArrayForm) return true; else NewExprs.push_back(NE); } return false; } bool MismatchingNewDeleteDetector::hasMatchingNewInCtor( const CXXConstructorDecl *CD) { if (CD->isImplicit()) return false; const FunctionDecl *Definition = CD; if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition)) { HasUndefinedConstructors = true; return EndOfTU; } for (const auto *CI : cast(Definition)->inits()) { if (hasMatchingNewInCtorInit(CI)) return true; } return false; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeInClassInitializer() { assert(Field != nullptr && "This should be called only for members"); const Expr *InitExpr = Field->getInClassInitializer(); if (!InitExpr) return EndOfTU ? NoMismatch : AnalyzeLater; if (const CXXNewExpr *NE = getNewExprFromInitListOrExpr(InitExpr)) { if (NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); return MemberInitMismatches; } } return NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field, bool DeleteWasArrayForm) { assert(Field != nullptr && "Analysis requires a valid class member."); this->Field = Field; IsArrayForm = DeleteWasArrayForm; const CXXRecordDecl *RD = cast(Field->getParent()); for (const auto *CD : RD->ctors()) { if (hasMatchingNewInCtor(CD)) return NoMismatch; } if (HasUndefinedConstructors) return EndOfTU ? NoMismatch : AnalyzeLater; if (!NewExprs.empty()) return MemberInitMismatches; return Field->hasInClassInitializer() ? analyzeInClassInitializer() : NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) { assert(ME != nullptr && "Expected a member expression"); if (FieldDecl *F = dyn_cast(ME->getMemberDecl())) return analyzeField(F, IsArrayForm); return NoMismatch; } bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr *D) { const CXXNewExpr *NE = nullptr; if (const VarDecl *VD = dyn_cast(D->getDecl())) { if (VD->hasInit() && (NE = getNewExprFromInitListOrExpr(VD->getInit())) && NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); } } return NewExprs.empty(); } static void DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc, const MismatchingNewDeleteDetector &Detector) { SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc); FixItHint H; if (!Detector.IsArrayForm) H = FixItHint::CreateInsertion(EndOfDelete, "[]"); else { SourceLocation RSquare = Lexer::findLocationAfterToken( DeleteLoc, tok::l_square, SemaRef.getSourceManager(), SemaRef.getLangOpts(), true); if (RSquare.isValid()) H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare)); } SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new) << Detector.IsArrayForm << H; for (const auto *NE : Detector.NewExprs) SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here) << Detector.IsArrayForm; } void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) { if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) return; MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false); switch (Detector.analyzeDeleteExpr(DE)) { case MismatchingNewDeleteDetector::VarInitMismatches: case MismatchingNewDeleteDetector::MemberInitMismatches: { DiagnoseMismatchedNewDelete(*this, DE->getLocStart(), Detector); break; } case MismatchingNewDeleteDetector::AnalyzeLater: { DeleteExprs[Detector.Field].push_back( std::make_pair(DE->getLocStart(), DE->isArrayForm())); break; } case MismatchingNewDeleteDetector::NoMismatch: break; } } void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm) { MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true); switch (Detector.analyzeField(Field, DeleteWasArrayForm)) { case MismatchingNewDeleteDetector::VarInitMismatches: llvm_unreachable("This analysis should have been done for class members."); case MismatchingNewDeleteDetector::AnalyzeLater: llvm_unreachable("Analysis cannot be postponed any point beyond end of " "translation unit."); case MismatchingNewDeleteDetector::MemberInitMismatches: DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector); break; case MismatchingNewDeleteDetector::NoMismatch: break; } } /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode ExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *ExE) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single // non-explicit conversion function to a pointer type. The result has type // void. // // DR599 amends "pointer type" to "pointer to object type" in both cases. ExprResult Ex = ExE; FunctionDecl *OperatorDelete = nullptr; bool ArrayFormAsWritten = ArrayForm; bool UsualArrayDeleteWantsSize = false; if (!Ex.get()->isTypeDependent()) { // Perform lvalue-to-rvalue cast, if needed. Ex = DefaultLvalueConversion(Ex.get()); if (Ex.isInvalid()) return ExprError(); QualType Type = Ex.get()->getType(); class DeleteConverter : public ContextualImplicitConverter { public: DeleteConverter() : ContextualImplicitConverter(false, true) {} bool match(QualType ConvType) override { // FIXME: If we have an operator T* and an operator void*, we must pick // the operator T*. if (const PointerType *ConvPtrType = ConvType->getAs()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) return true; return false; } SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_operand) << T; } SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T; } SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T; } SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { llvm_unreachable("conversion functions are permitted"); } } Converter; Ex = PerformContextualImplicitConversion(StartLoc, Ex.get(), Converter); if (Ex.isInvalid()) return ExprError(); Type = Ex.get()->getType(); if (!Converter.match(Type)) // FIXME: PerformContextualImplicitConversion should return ExprError // itself in this case. return ExprError(); QualType Pointee = Type->getAs()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); if (Pointee.getAddressSpace() != LangAS::Default && !getLangOpts().OpenCLCPlusPlus) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() << Pointee.getQualifiers().getAddressSpaceAttributePrintValue(); CXXRecordDecl *PointeeRD = nullptr; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { // FIXME: This can result in errors if the definition was imported from a // module but is hidden. if (!RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex.get())) { if (const RecordType *RT = PointeeElem->getAs()) PointeeRD = cast(RT->getDecl()); } } if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) << Type << Ex.get()->getSourceRange() << FixItHint::CreateInsertion(getLocForEndOfToken(StartLoc), "[]"); ArrayForm = true; } DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); if (PointeeRD) { if (!UseGlobal && FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the // usual operator delete[] has a size_t parameter. if (ArrayForm) { // If the user specifically asked to use the global allocator, // we'll need to do the lookup into the class. if (UseGlobal) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); // Otherwise, the usual operator delete[] should be the // function we just found. else if (OperatorDelete && isa(OperatorDelete)) UsualArrayDeleteWantsSize = UsualDeallocFnInfo(*this, DeclAccessPair::make(OperatorDelete, AS_public)) .HasSizeT; } if (!PointeeRD->hasIrrelevantDestructor()) if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkFunctionReferenced(StartLoc, const_cast(Dtor)); if (DiagnoseUseOfDecl(Dtor, StartLoc)) return ExprError(); } CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc, /*IsDelete=*/true, /*CallCanBeVirtual=*/true, /*WarnOnNonAbstractTypes=*/!ArrayForm, SourceLocation()); } if (!OperatorDelete) { if (getLangOpts().OpenCLCPlusPlus) { Diag(StartLoc, diag::err_openclcxx_not_supported) << "default delete"; return ExprError(); } bool IsComplete = isCompleteType(StartLoc, Pointee); bool CanProvideSize = IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize || Pointee.isDestructedType()); bool Overaligned = hasNewExtendedAlignment(*this, Pointee); // Look for a global declaration. OperatorDelete = FindUsualDeallocationFunction(StartLoc, CanProvideSize, Overaligned, DeleteName); } MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of destructor if we're going to call it. // Note that this is required even for a virtual delete. bool IsVirtualDelete = false; if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); IsVirtualDelete = Dtor->isVirtual(); } } diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this); // Convert the operand to the type of the first parameter of operator // delete. This is only necessary if we selected a destroying operator // delete that we are going to call (non-virtually); converting to void* // is trivial and left to AST consumers to handle. QualType ParamType = OperatorDelete->getParamDecl(0)->getType(); if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) { Qualifiers Qs = Pointee.getQualifiers(); if (Qs.hasCVRQualifiers()) { // Qualifiers are irrelevant to this conversion; we're only looking // for access and ambiguity. Qs.removeCVRQualifiers(); QualType Unqual = Context.getPointerType( Context.getQualifiedType(Pointee.getUnqualifiedType(), Qs)); Ex = ImpCastExprToType(Ex.get(), Unqual, CK_NoOp); } Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing); if (Ex.isInvalid()) return ExprError(); } } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten, UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc); AnalyzeDeleteExprMismatch(Result); return Result; } static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, bool IsDelete, FunctionDecl *&Operator) { DeclarationName NewName = S.Context.DeclarationNames.getCXXOperatorName( IsDelete ? OO_Delete : OO_New); LookupResult R(S, NewName, TheCall->getLocStart(), Sema::LookupOrdinaryName); S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); assert(!R.empty() && "implicitly declared allocation functions not found"); assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); // We do our own custom access checks below. R.suppressDiagnostics(); SmallVector Args(TheCall->arg_begin(), TheCall->arg_end()); OverloadCandidateSet Candidates(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end(); FnOvl != FnOvlEnd; ++FnOvl) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. NamedDecl *D = (*FnOvl)->getUnderlyingDecl(); if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, Candidates, /*SuppressUserConversions=*/false); continue; } FunctionDecl *Fn = cast(D); S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, /*SuppressUserConversions=*/false); } SourceRange Range = TheCall->getSourceRange(); // Do the resolution. OverloadCandidateSet::iterator Best; switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; assert(R.getNamingClass() == nullptr && "class members should not be considered"); if (!FnDecl->isReplaceableGlobalAllocationFunction()) { S.Diag(R.getNameLoc(), diag::err_builtin_operator_new_delete_not_usual) << (IsDelete ? 1 : 0) << Range; S.Diag(FnDecl->getLocation(), diag::note_non_usual_function_declared_here) << R.getLookupName() << FnDecl->getSourceRange(); return true; } Operator = FnDecl; return false; } case OR_No_Viable_Function: S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) << R.getLookupName() << Range; Candidates.NoteCandidates(S, OCD_AllCandidates, Args); return true; case OR_Ambiguous: S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName() << Range; Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); return true; case OR_Deleted: { S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) << Best->Function->isDeleted() << R.getLookupName() << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; Candidates.NoteCandidates(S, OCD_AllCandidates, Args); return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } ExprResult Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, bool IsDelete) { CallExpr *TheCall = cast(TheCallResult.get()); if (!getLangOpts().CPlusPlus) { Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) << (IsDelete ? "__builtin_operator_delete" : "__builtin_operator_new") << "C++"; return ExprError(); } // CodeGen assumes it can find the global new and delete to call, // so ensure that they are declared. DeclareGlobalNewDelete(); FunctionDecl *OperatorNewOrDelete = nullptr; if (resolveBuiltinNewDeleteOverload(*this, TheCall, IsDelete, OperatorNewOrDelete)) return ExprError(); assert(OperatorNewOrDelete && "should be found"); TheCall->setType(OperatorNewOrDelete->getReturnType()); for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { QualType ParamTy = OperatorNewOrDelete->getParamDecl(i)->getType(); InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, ParamTy, false); ExprResult Arg = PerformCopyInitialization( Entity, TheCall->getArg(i)->getLocStart(), TheCall->getArg(i)); if (Arg.isInvalid()) return ExprError(); TheCall->setArg(i, Arg.get()); } auto Callee = dyn_cast(TheCall->getCallee()); assert(Callee && Callee->getCastKind() == CK_BuiltinFnToFnPtr && "Callee expected to be implicit cast to a builtin function pointer"); Callee->setType(OperatorNewOrDelete->getType()); return TheCallResult; } void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext()) return; // C++ [expr.delete]p3: // In the first alternative (delete object), if the static type of the // object to be deleted is different from its dynamic type, the static // type shall be a base class of the dynamic type of the object to be // deleted and the static type shall have a virtual destructor or the // behavior is undefined. // const CXXRecordDecl *PointeeRD = dtor->getParent(); // Note: a final class cannot be derived from, no issue there if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr()) return; // If the superclass is in a system header, there's nothing that can be done. // The `delete` (where we emit the warning) can be in a system header, // what matters for this warning is where the deleted type is defined. if (getSourceManager().isInSystemHeader(PointeeRD->getLocation())) return; QualType ClassType = dtor->getThisType(Context)->getPointeeType(); if (PointeeRD->isAbstract()) { // If the class is abstract, we warn by default, because we're // sure the code has undefined behavior. Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } else if (WarnOnNonAbstractTypes) { // Otherwise, if this is not an array delete, it's a bit suspect, // but not necessarily wrong. Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } if (!IsDelete) { std::string TypeStr; ClassType.getAsStringInternal(TypeStr, getPrintingPolicy()); Diag(DtorLoc, diag::note_delete_non_virtual) << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::"); } } Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { ExprResult E = CheckConditionVariable(cast(ConditionVar), StmtLoc, CK); if (E.isInvalid()) return ConditionError(); return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc), CK == ConditionKind::ConstexprIf); } /// Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { if (ConditionVar->isInvalidDecl()) return ExprError(); QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); ExprResult Condition = DeclRefExpr::Create( Context, NestedNameSpecifierLoc(), SourceLocation(), ConditionVar, /*enclosing*/ false, ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType(), VK_LValue); MarkDeclRefReferenced(cast(Condition.get())); switch (CK) { case ConditionKind::Boolean: return CheckBooleanCondition(StmtLoc, Condition.get()); case ConditionKind::ConstexprIf: return CheckBooleanCondition(StmtLoc, Condition.get(), true); case ConditionKind::Switch: return CheckSwitchCondition(StmtLoc, Condition.get()); } llvm_unreachable("unexpected condition kind"); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) { // C++ 6.4p4: // The value of a condition that is an initialized declaration in a statement // other than a switch statement is the value of the declared variable // implicitly converted to type bool. If that conversion is ill-formed, the // program is ill-formed. // The value of a condition that is an expression is the value of the // expression, implicitly converted to bool. // // FIXME: Return this value to the caller so they don't need to recompute it. llvm::APSInt Value(/*BitWidth*/1); return (IsConstexpr && !CondExpr->isValueDependent()) ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, CCEK_ConstexprIf) : PerformContextuallyConvertToBool(CondExpr); } /// Helper function to determine whether this is the (deprecated) C++ /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast(From)) From = Cast->getSubExpr(); // A string literal (2.13.4) that is not a wide string literal can // be converted to an rvalue of type "pointer to char"; a wide // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast(From->IgnoreParens())) if (const PointerType *ToPtrType = ToType->getAs()) if (const BuiltinType *ToPointeeType = ToPtrType->getPointeeType()->getAs()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). if (!ToPtrType->getPointeeType().hasQualifiers()) { switch (StrLit->getKind()) { case StringLiteral::UTF8: case StringLiteral::UTF16: case StringLiteral::UTF32: // We don't allow UTF literals to be implicitly converted break; case StringLiteral::Ascii: return (ToPointeeType->getKind() == BuiltinType::Char_U || ToPointeeType->getKind() == BuiltinType::Char_S); case StringLiteral::Wide: return Context.typesAreCompatible(Context.getWideCharType(), QualType(ToPointeeType, 0)); } } } return false; } static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, CXXMethodDecl *Method, DeclAccessPair FoundDecl, bool HadMultipleCandidates, Expr *From) { switch (Kind) { default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { CXXConstructorDecl *Constructor = cast(Method); SmallVector ConstructorArgs; if (S.RequireNonAbstractType(CastLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) return ExprError(); S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl, InitializedEntity::InitializeTemporary(Ty)); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); ExprResult Result = S.BuildCXXConstructExpr( CastLoc, Ty, FoundDecl, cast(Method), ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); return S.MaybeBindToTemporary(Result.getAs()); } case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); // Create an implicit call expr that calls it. CXXConversionDecl *Conv = cast(Method); ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv, HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); // Record usage of conversion in an implicit cast. Result = ImplicitCastExpr::Create(S.Context, Result.get()->getType(), CK_UserDefinedConversion, Result.get(), nullptr, Result.get()->getValueKind()); return S.MaybeBindToTemporary(Result.get()); } } } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns the converted /// expression. Action is the kind of conversion we're performing, /// used in the error message. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, CheckedConversionKind CCK) { // C++ [over.match.oper]p7: [...] operands of class type are converted [...] if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType()) return From; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, Action, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); break; } case ImplicitConversionSequence::UserDefinedConversion: { FunctionDecl *FD = ICS.UserDefined.ConversionFunction; CastKind CastKind; QualType BeforeToType; assert(FD && "no conversion function for user-defined conversion seq"); if (const CXXConversionDecl *Conv = dyn_cast(FD)) { CastKind = CK_UserDefinedConversion; // If the user-defined conversion is specified by a conversion function, // the initial standard conversion sequence converts the source type to // the implicit object parameter of the conversion function. BeforeToType = Context.getTagDeclType(Conv->getParent()); } else { const CXXConstructorDecl *Ctor = cast(FD); CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the // initial standard conversion sequence converts the source type to // the type required by the argument of the constructor BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); } } // Watch out for ellipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { ExprResult Res = PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); } ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), CastKind, cast(FD), ICS.UserDefined.FoundConversionFunction, ICS.UserDefined.HadMultipleCandidates, From); if (CastArg.isInvalid()) return ExprError(); From = CastArg.get(); // C++ [over.match.oper]p7: // [...] the second standard conversion sequence of a user-defined // conversion sequence is not applied. if (CCK == CCK_ForBuiltinOverloadedOp) return From; return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, CCK); } case ImplicitConversionSequence::AmbiguousConversion: ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: bool Diagnosed = DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, From->getType(), From, Action); assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } // Everything went well. return From; } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType by following the standard /// conversion sequence SCS. Returns the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK) { bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); if (SCS.Second == ICK_Derived_To_Base) { SmallVector ConstructorArgs; if (CompleteConstructorCall(cast(SCS.CopyConstructor), From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, ConstructorArgs, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, From, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } // Resolve overloaded function references. if (Context.hasSameType(FromType, Context.OverloadTy)) { DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true, Found); if (!Fn) return ExprError(); if (DiagnoseUseOfDecl(Fn, From->getLocStart())) return ExprError(); From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); } // If we're converting to an atomic type, first convert to the corresponding // non-atomic type. QualType ToAtomicType; if (const AtomicType *ToAtomic = ToType->getAs()) { ToAtomicType = ToType; ToType = ToAtomic->getValueType(); } QualType InitialFromType = FromType; // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: if (const AtomicType *FromAtomic = FromType->getAs()) { FromType = FromAtomic->getValueType().getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_AtomicToNonAtomic, From, /*BasePath=*/nullptr, VK_RValue); } break; case ICK_Lvalue_To_Rvalue: { assert(From->getObjectKind() != OK_ObjCProperty); ExprResult FromRes = DefaultLvalueConversion(From); assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!"); From = FromRes.get(); FromType = From->getType(); break; } case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; default: llvm_unreachable("Improper first standard conversion"); } // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: // C++ [except.spec]p5: // [For] assignment to and initialization of pointers to functions, // pointers to member functions, and references to functions: the // target entity shall allow at least the exceptions allowed by the // source value in the assignment or initialization. switch (Action) { case AA_Assigning: case AA_Initializing: // Note, function argument passing and returning are initialization. case AA_Passing: case AA_Returning: case AA_Sending: case AA_Passing_CFAudited: if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); break; case AA_Casting: case AA_Converting: // Casts and implicit conversions are not initialization, so are not // checked for exception specification mismatches. break; } // Nothing else to do. break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { assert(FromType->castAs()->getDecl()->isFixed() && SCS.Second == ICK_Integral_Promotion && "only enums with fixed underlying type can promote to bool"); From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Complex_Promotion: case ICK_Complex_Conversion: { QualType FromEl = From->getType()->getAs()->getElementType(); QualType ToEl = ToType->getAs()->getElementType(); CastKind CK; if (FromEl->isRealFloatingType()) { if (ToEl->isRealFloatingType()) CK = CK_FloatingComplexCast; else CK = CK_FloatingComplexToIntegralComplex; } else if (ToEl->isRealFloatingType()) { CK = CK_IntegralComplexToFloatingComplex; } else { CK = CK_IntegralComplexCast; } From = ImpCastExprToType(From, ToType, CK, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); else From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Compatible_Conversion: From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Writeback_Conversion: case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions if (Action == AA_Initializing || Action == AA_Assigning) Diag(From->getLocStart(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action << From->getSourceRange() << 0; else Diag(From->getLocStart(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange() << 0; if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { if (Action == AA_Initializing) Diag(From->getLocStart(), diag::err_arc_weak_unavailable_assign); else Diag(From->getLocStart(), diag::err_arc_convesion_of_weak_unavailable) << (Action == AA_Casting) << From->getType() << ToType << From->getSourceRange(); } CastKind Kind; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); // Make sure we extend blocks if necessary. // FIXME: doing this here is really ugly. if (Kind == CK_BlockPointerToObjCPointerCast) { ExprResult E = From; (void) PrepareCastToObjCObjectPointer(E); From = E.get(); } if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) CheckObjCConversion(SourceRange(), ToType, From, CCK); From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Pointer_Member: { CastKind Kind; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); // We may not have been able to figure out what this member pointer resolved // to up until this exact point. Attempt to lock-in it's inheritance model. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)isCompleteType(From->getExprLoc(), From->getType()); (void)isCompleteType(From->getExprLoc(), ToType); } From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Boolean_Conversion: // Perform half-to-boolean conversion via float. if (From->getType()->isHalfType()) { From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get(); FromType = Context.FloatTy; } From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Derived_To_Base: { CXXCastPath BasePath; if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), From->getSourceRange(), &BasePath, CStyle)) return ExprError(); From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_DerivedToBase, From->getValueKind(), &BasePath, CCK).get(); break; } case ICK_Vector_Conversion: From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Vector_Splat: { // Vector splat from any arithmetic type to a vector. Expr *Elem = prepareVectorSplat(ToType, From).get(); From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Complex_Real: // Case 1. x -> _Complex y if (const ComplexType *ToComplex = ToType->getAs()) { QualType ElType = ToComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // x -> y if (Context.hasSameUnqualifiedType(ElType, From->getType())) { // do nothing } else if (From->getType()->isRealFloatingType()) { From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).get(); } else { assert(From->getType()->isIntegerType()); From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).get(); } // y -> _Complex y From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingRealToComplex : CK_IntegralRealToComplex).get(); // Case 2. _Complex x -> y } else { const ComplexType *FromComplex = From->getType()->getAs(); assert(FromComplex); QualType ElType = FromComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal : CK_IntegralComplexToReal, VK_RValue, /*BasePath=*/nullptr, CCK).get(); // x -> y if (Context.hasSameUnqualifiedType(ElType, ToType)) { // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } } break; case ICK_Block_Pointer_Conversion: { From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_TransparentUnionConversion: { ExprResult FromRes = From; Sema::AssignConvertType ConvTy = CheckTransparentUnionArgumentConstraints(ToType, FromRes); if (FromRes.isInvalid()) return ExprError(); From = FromRes.get(); assert ((ConvTy == Sema::Compatible) && "Improper transparent union conversion"); (void)ConvTy; break; } case ICK_Zero_Event_Conversion: From = ImpCastExprToType(From, ToType, CK_ZeroToOCLEvent, From->getValueKind()).get(); break; case ICK_Zero_Queue_Conversion: From = ImpCastExprToType(From, ToType, CK_ZeroToOCLQueue, From->getValueKind()).get(); break; case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: case ICK_Function_Conversion: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: case ICK_Incompatible_Pointer_Conversion: llvm_unreachable("Improper second standard conversion"); } switch (SCS.Third) { case ICK_Identity: // Nothing to do. break; case ICK_Function_Conversion: // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? From->getValueKind() : VK_RValue; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK_NoOp, VK, /*BasePath=*/nullptr, CCK).get(); if (SCS.DeprecatedStringLiteralToCharPtr && !getLangOpts().WritableStrings) { Diag(From->getLocStart(), getLangOpts().CPlusPlus11 ? diag::ext_deprecated_string_literal_conversion : diag::warn_deprecated_string_literal_conversion) << ToType.getNonReferenceType(); } break; } default: llvm_unreachable("Improper third standard conversion"); } // If this conversion sequence involved a scalar -> atomic conversion, perform // that conversion now. if (!ToAtomicType.isNull()) { assert(Context.hasSameType( ToAtomicType->castAs()->getValueType(), From->getType())); From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic, VK_RValue, nullptr, CCK).get(); } // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. if (!isCast(CCK)) diagnoseNullableToNonnullConversion(ToType, InitialFromType, From->getLocStart()); return From; } /// Check the completeness of a type in a unary type trait. /// /// If the particular type trait requires a complete type, tries to complete /// it. If completing the type fails, a diagnostic is emitted and false /// returned. If completing the type succeeds or no completion was required, /// returns true. static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, SourceLocation Loc, QualType ArgTy) { // C++0x [meta.unary.prop]p3: // For all of the class templates X declared in this Clause, instantiating // that template with a template argument that is a class template // specialization may result in the implicit instantiation of the template // argument if and only if the semantics of X require that the argument // must be a complete type. // We apply this rule to all the type trait expressions used to implement // these class templates. We also try to follow any GCC documented behavior // in these expressions to ensure portability of standard libraries. switch (UTT) { default: llvm_unreachable("not a UTT"); // is_complete_type somewhat obviously cannot require a complete type. case UTT_IsCompleteType: // Fall-through // These traits are modeled on the type predicates in C++0x // [meta.unary.cat] and [meta.unary.comp]. They are not specified as // requiring a complete type, as whether or not they return true cannot be // impacted by the completeness of the type. case UTT_IsVoid: case UTT_IsIntegral: case UTT_IsFloatingPoint: case UTT_IsArray: case UTT_IsPointer: case UTT_IsLvalueReference: case UTT_IsRvalueReference: case UTT_IsMemberFunctionPointer: case UTT_IsMemberObjectPointer: case UTT_IsEnum: case UTT_IsUnion: case UTT_IsClass: case UTT_IsFunction: case UTT_IsReference: case UTT_IsArithmetic: case UTT_IsFundamental: case UTT_IsObject: case UTT_IsScalar: case UTT_IsCompound: case UTT_IsMemberPointer: // Fall-through // These traits are modeled on type predicates in C++0x [meta.unary.prop] // which requires some of its traits to have the complete type. However, // the completeness of the type cannot impact these traits' semantics, and // so they don't require it. This matches the comments on these traits in // Table 49. case UTT_IsConst: case UTT_IsVolatile: case UTT_IsSigned: case UTT_IsUnsigned: // This type trait always returns false, checking the type is moot. case UTT_IsInterfaceClass: return true; // C++14 [meta.unary.prop]: // If T is a non-union class type, T shall be a complete type. case UTT_IsEmpty: case UTT_IsPolymorphic: case UTT_IsAbstract: if (const auto *RD = ArgTy->getAsCXXRecordDecl()) if (!RD->isUnion()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++14 [meta.unary.prop]: // If T is a class type, T shall be a complete type. case UTT_IsFinal: case UTT_IsSealed: if (ArgTy->getAsCXXRecordDecl()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++1z [meta.unary.prop]: // remove_all_extents_t shall be a complete type or cv void. case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: // Per the GCC type traits documentation, T shall be a complete type, cv void, // or an array of unknown bound. But GCC actually imposes the same constraints // as above. case UTT_HasNothrowAssign: case UTT_HasNothrowMoveAssign: case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: case UTT_HasTrivialMoveAssign: case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialMoveConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); LLVM_FALLTHROUGH; // C++1z [meta.unary.prop]: // T shall be a complete type, cv void, or an array of unknown bound. case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); } } static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, bool (CXXRecordDecl::*HasTrivial)() const, bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { CXXRecordDecl *RD = cast(RT->getDecl()); if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) return true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op); DeclarationNameInfo NameInfo(Name, KeyLoc); LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName); if (Self.LookupQualifiedName(Res, RD)) { bool FoundOperator = false; Res.suppressDiagnostics(); for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); Op != OpEnd; ++Op) { if (isa(*Op)) continue; CXXMethodDecl *Operator = cast(*Op); if((Operator->*IsDesiredOp)()) { FoundOperator = true; const FunctionProtoType *CPT = Operator->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; } } return FoundOperator; } return false; } static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, SourceLocation KeyLoc, QualType T) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); ASTContext &C = Self.Context; switch(UTT) { default: llvm_unreachable("not a UTT"); // Type trait expressions corresponding to the primary type category // predicates in C++0x [meta.unary.cat]. case UTT_IsVoid: return T->isVoidType(); case UTT_IsIntegral: return T->isIntegralType(C); case UTT_IsFloatingPoint: return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); case UTT_IsPointer: return T->isPointerType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: return T->isRValueReferenceType(); case UTT_IsMemberFunctionPointer: return T->isMemberFunctionPointerType(); case UTT_IsMemberObjectPointer: return T->isMemberDataPointerType(); case UTT_IsEnum: return T->isEnumeralType(); case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: return T->isClassType() || T->isStructureType() || T->isInterfaceType(); case UTT_IsFunction: return T->isFunctionType(); // Type trait expressions which correspond to the convenient composition // predicates in C++0x [meta.unary.comp]. case UTT_IsReference: return T->isReferenceType(); case UTT_IsArithmetic: return T->isArithmeticType() && !T->isEnumeralType(); case UTT_IsFundamental: return T->isFundamentalType(); case UTT_IsObject: return T->isObjectType(); case UTT_IsScalar: // Note: semantic analysis depends on Objective-C lifetime types to be // considered scalar types. However, such types do not actually behave // like scalar types at run time (since they may require retain/release // operations), so we report them as non-scalar. if (T->isObjCLifetimeType()) { switch (T.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; } } return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); case UTT_IsMemberPointer: return T->isMemberPointerType(); // Type trait expressions which correspond to the type property predicates // in C++0x [meta.unary.prop]. case UTT_IsConst: return T.isConstQualified(); case UTT_IsVolatile: return T.isVolatileQualified(); case UTT_IsTrivial: return T.isTrivialType(C); case UTT_IsTriviallyCopyable: return T.isTriviallyCopyableType(C); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: return T.isPODType(C); case UTT_IsLiteral: return T->isLiteralType(C); case UTT_IsEmpty: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isEmpty(); return false; case UTT_IsPolymorphic: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isPolymorphic(); return false; case UTT_IsAbstract: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isAbstract(); return false; case UTT_IsAggregate: // Report vector extensions and complex types as aggregates because they // support aggregate initialization. GCC mirrors this behavior for vectors // but not _Complex. return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() || T->isAnyComplexType(); // __is_interface_class only returns true when CL is invoked in /CLR mode and // even then only when it is used with the 'interface struct ...' syntax // Clang doesn't support /CLR which makes this type trait moot. case UTT_IsInterfaceClass: return false; case UTT_IsFinal: case UTT_IsSealed: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasAttr(); return false; case UTT_IsSigned: return T->isSignedIntegerType(); case UTT_IsUnsigned: return T->isUnsignedIntegerType(); // Type trait expressions which query classes regarding their construction, // destruction, and copying. Rather than being based directly on the // related type predicates in the standard, they are specified by both // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those // specifications. // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index // // Note that these builtins do not behave as documented in g++: if a class // has both a trivial and a non-trivial special member of a particular kind, // they return false! For now, we emulate this behavior. // FIXME: This appears to be a g++ bug: more complex cases reveal that it // does not correctly compute triviality in the presence of multiple special // members of the same kind. Revisit this once the g++ bug is fixed. case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default // constructor ([class.ctor]) then the trait is true, else it is false. if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor(); return false; case UTT_HasTrivialMoveConstructor: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_trivially_move_constructible (20.9.4.3). if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true or type is a reference type then // the trait is true, else if type is a cv class or union type // with a trivial copy constructor ([class.copy]) then the trait // is true, else it is false. if (T.isPODType(C) || T->isReferenceType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor(); return false; case UTT_HasTrivialMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically it is used as the logic // behind std::is_trivially_move_assignable (20.9.4.3) if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment(); return false; case UTT_HasTrivialAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __is_pod (type) is true then the // trait is true, else if type is a cv class or union type with // a trivial copy assignment ([class.copy]) then the trait is // true, else it is false. // Note: the const and reference restrictions are interesting, // given that const and reference members don't prevent a class // from having a trivial copy assignment operator (but do cause // errors if the copy assignment operator is actually used, q.v. // [class.copy]p12). if (T.isConstQualified()) return false; if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment(); return false; case UTT_IsDestructible: case UTT_IsTriviallyDestructible: case UTT_IsNothrowDestructible: // C++14 [meta.unary.prop]: // For reference types, is_destructible::value is true. if (T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; // C++14 [meta.unary.prop]: // For incomplete types and function types, is_destructible::value is // false. if (T->isIncompleteType() || T->isFunctionType()) return false; // A type that requires destruction (via a non-trivial destructor or ARC // lifetime semantics) is not trivially-destructible. if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType()) return false; // C++14 [meta.unary.prop]: // For object types and given U equal to remove_all_extents_t, if the // expression std::declval().~U() is well-formed when treated as an // unevaluated operand (Clause 5), then is_destructible::value is true if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { CXXDestructorDecl *Destructor = Self.LookupDestructor(RD); if (!Destructor) return false; // C++14 [dcl.fct.def.delete]p2: // A program that refers to a deleted function implicitly or // explicitly, other than to declare it, is ill-formed. if (Destructor->isDeleted()) return false; if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) return false; if (UTT == UTT_IsNothrowDestructible) { const FunctionProtoType *CPT = Destructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; } } return true; case UTT_HasTrivialDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __is_pod (type) is true or type is a reference type // then the trait is true, else if type is a cv class or union // type (or array thereof) with a trivial destructor // ([class.dtor]) then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDestructor(); return false; // TODO: Propagate nothrowness for implicitly declared special members. case UTT_HasNothrowAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __has_trivial_assign (type) // is true then the trait is true, else if type is a cv class // or union type with copy assignment operators that are known // not to throw an exception then the trait is true, else it is // false. if (C.getBaseElementType(T).isConstQualified()) return false; if (T->isReferenceType()) return false; if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (const RecordType *RT = T->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialCopyAssignment, &CXXRecordDecl::hasNonTrivialCopyAssignment, &CXXMethodDecl::isCopyAssignmentOperator); return false; case UTT_HasNothrowMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_nothrow_move_assignable (20.9.4.3). if (T.isPODType(C)) return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialMoveAssignment, &CXXRecordDecl::hasNonTrivialMoveAssignment, &CXXMethodDecl::isMoveAssignmentOperator); return false; case UTT_HasNothrowCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __has_trivial_copy (type) is true then the trait is true, else // if type is a cv class or union type with copy constructors that are // known not to throw an exception then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { if (RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor()) return true; bool FoundConstructor = false; unsigned FoundTQs; for (const auto *ND : Self.LookupConstructors(RD)) { // A template constructor is never a copy constructor. // FIXME: However, it may actually be selected at the actual overload // resolution point. if (isa(ND->getUnderlyingDecl())) continue; // UsingDecl itself is not a constructor if (isa(ND)) continue; auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow() || CPT->getNumParams() > 1) return false; } } return FoundConstructor; } return false; case UTT_HasNothrowConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __has_trivial_constructor (type) is true then the trait is // true, else if type is a cv class or union type (or array // thereof) with a default constructor that is known not to // throw an exception then the trait is true, else it is false. if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { if (RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor()) return true; bool FoundConstructor = false; for (const auto *ND : Self.LookupConstructors(RD)) { // FIXME: In C++0x, a constructor template can be a default constructor. if (isa(ND->getUnderlyingDecl())) continue; // UsingDecl itself is not a constructor if (isa(ND)) continue; auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow() || CPT->getNumParams() > 0) return false; } } return FoundConstructor; } return false; case UTT_HasVirtualDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is a class type with a virtual destructor ([class.dtor]) // then the trait is true, else it is false. if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) return Destructor->isVirtual(); return false; // These type trait expressions are modeled on the specifications for the // Embarcadero C++0x type trait functions: // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index case UTT_IsCompleteType: // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_): // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); case UTT_HasUniqueObjectRepresentations: return C.hasUniqueObjectRepresentations(T); } } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc); static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); // Evaluate BTT_ReferenceBindsToTemporary alongside the IsConstructible // traits to avoid duplication. if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary) return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), Args[1]->getType(), RParenLoc); switch (Kind) { case clang::BTT_ReferenceBindsToTemporary: case clang::TT_IsConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { // C++11 [meta.unary.prop]: // is_trivially_constructible is defined as: // // is_constructible::value is true and the variable // definition for is_constructible, as defined below, is known to call // no operation that is not trivial. // // The predicate condition for a template specialization // is_constructible shall be satisfied if and only if the // following variable definition would be well-formed for some invented // variable t: // // T t(create()...); assert(!Args.empty()); // Precondition: T and all types in the parameter pack Args shall be // complete types, (possibly cv-qualified) void, or arrays of // unknown bound. for (const auto *TSI : Args) { QualType ArgTy = TSI->getType(); if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; if (S.RequireCompleteType(KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } // Make sure the first argument is not incomplete nor a function type. QualType T = Args[0]->getType(); if (T->isIncompleteType() || T->isFunctionType()) return false; // Make sure the first argument is not an abstract type. CXXRecordDecl *RD = T->getAsCXXRecordDecl(); if (RD && RD->isAbstract()) return false; SmallVector OpaqueArgExprs; SmallVector ArgExprs; ArgExprs.reserve(Args.size() - 1); for (unsigned I = 1, N = Args.size(); I != N; ++I) { QualType ArgTy = Args[I]->getType(); if (ArgTy->isObjectType() || ArgTy->isFunctionType()) ArgTy = S.Context.getRValueReferenceType(ArgTy); OpaqueArgExprs.push_back( OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(), ArgTy.getNonLValueExprType(S.Context), Expr::getValueKindForType(ArgTy))); } for (Expr &E : OpaqueArgExprs) ArgExprs.push_back(&E); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); InitializationSequence Init(S, To, InitKind, ArgExprs); if (Init.Failed()) return false; ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; if (Kind == clang::TT_IsConstructible) return true; if (Kind == clang::BTT_ReferenceBindsToTemporary) { if (!T->isReferenceType()) return false; return !Init.isDirectReferenceBinding(); } if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; if (Kind == clang::TT_IsTriviallyConstructible) { // Under Objective-C ARC and Weak, if the destination has non-trivial // Objective-C lifetime, this is a non-trivial construction. if (T.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; // The initialization succeeded; now make sure there are no non-trivial // calls. return !Result.get()->hasNonTrivialCall(S.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a TT"); } return false; } ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { QualType ResultType = Context.getLogicalOperationType(); if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( *this, Kind, KWLoc, Args[0]->getType())) return ExprError(); bool Dependent = false; for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (Args[I]->getType()->isDependentType()) { Dependent = true; break; } } bool Result = false; if (!Dependent) Result = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc); return TypeTraitExpr::Create(Context, ResultType, KWLoc, Kind, Args, RParenLoc, Result); } ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { SmallVector ConvertedArgs; ConvertedArgs.reserve(Args.size()); for (unsigned I = 0, N = Args.size(); I != N; ++I) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(Args[I], &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); ConvertedArgs.push_back(TInfo); } return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc) { assert(!LhsT->isDependentType() && !RhsT->isDependentType() && "Cannot evaluate traits of dependent types"); switch(BTT) { case BTT_IsBaseOf: { // C++0x [meta.rel]p2 // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. const RecordType *lhsRecord = LhsT->getAs(); const RecordType *rhsRecord = RhsT->getAs(); if (!rhsRecord || !lhsRecord) { const ObjCObjectType *LHSObjTy = LhsT->getAs(); const ObjCObjectType *RHSObjTy = RhsT->getAs(); if (!LHSObjTy || !RHSObjTy) return false; ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); if (!BaseInterface || !DerivedInterface) return false; if (Self.RequireCompleteType( KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); } assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) == (lhsRecord == rhsRecord)); if (lhsRecord == rhsRecord) return !lhsRecord->getDecl()->isUnion(); // C++0x [meta.rel]p2: // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. if (Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; return cast(rhsRecord->getDecl()) ->isDerivedFrom(cast(lhsRecord->getDecl())); } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); case BTT_TypeCompatible: { // GCC ignores cv-qualifiers on arrays for this builtin. Qualifiers LhsQuals, RhsQuals; QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals); QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals); return Self.Context.typesAreCompatible(Lhs, Rhs); } case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: // Given the following function prototype: // // template // typename add_rvalue_reference::type create(); // // the predicate condition for a template specialization // is_convertible shall be satisfied if and only if // the return expression in the following code would be // well-formed, including any implicit conversions to the return // type of the function: // // To test() { // return create(); // } // // Access checking is performed as if in a context unrelated to To and // From. Only the validity of the immediate context of the expression // of the return-statement (including conversions to the return type) // is considered. // // We model the initialization as a copy-initialization of a temporary // of the appropriate type, which for this expression is identical to the // return statement (since NRVO doesn't apply). // Functions aren't allowed to return function or array types. if (RhsT->isFunctionType() || RhsT->isArrayType()) return false; // A return statement in a void function must have void type. if (RhsT->isVoidType()) return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) return false; // Compute the result of add_rvalue_reference. if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); // Build a fake source and destination for initialization. InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, FromPtr); if (Init.Failed()) return false; ExprResult Result = Init.Perform(Self, To, Kind, FromPtr); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } case BTT_IsAssignable: case BTT_IsNothrowAssignable: case BTT_IsTriviallyAssignable: { // C++11 [meta.unary.prop]p3: // is_trivially_assignable is defined as: // is_assignable::value is true and the assignment, as defined by // is_assignable, is known to call no operation that is not trivial // // is_assignable is defined as: // The expression declval() = declval() is well-formed when // treated as an unevaluated operand (Clause 5). // // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. if (LhsT->isVoidType() || RhsT->isVoidType()) return false; // Build expressions that emulate the effect of declval() and // declval(). if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); if (RhsT->isObjectType() || RhsT->isFunctionType()) RhsT = Self.Context.getRValueReferenceType(RhsT); OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(RhsT)); // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; if (BTT == BTT_IsAssignable) return true; if (BTT == BTT_IsNothrowAssignable) return Self.canThrow(Result.get()) == CT_Cannot; if (BTT == BTT_IsTriviallyAssignable) { // Under Objective-C ARC and Weak, if the destination has non-trivial // Objective-C lifetime, this is a non-trivial assignment. if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; return !Result.get()->hasNonTrivialCall(Self.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a BTT"); } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType Ty, Expr* DimExpr, SourceLocation RParen) { TypeSourceInfo *TSInfo; QualType T = GetTypeFromParser(Ty, &TSInfo); if (!TSInfo) TSInfo = Context.getTrivialTypeSourceInfo(T); return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen); } static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, QualType T, Expr *DimExpr, SourceLocation KeyLoc) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); switch(ATT) { case ATT_ArrayRank: if (T->isArrayType()) { unsigned Dim = 0; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { ++Dim; T = AT->getElementType(); } return Dim; } return 0; case ATT_ArrayExtent: { llvm::APSInt Value; uint64_t Dim; if (Self.VerifyIntegerConstantExpression(DimExpr, &Value, diag::err_dimension_expr_not_constant_integer, false).isInvalid()) return 0; if (Value.isSigned() && Value.isNegative()) { Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) << DimExpr->getSourceRange(); return 0; } Dim = Value.getLimitedValue(); if (T->isArrayType()) { unsigned D = 0; bool Matched = false; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { if (Dim == D) { Matched = true; break; } ++D; T = AT->getElementType(); } if (Matched && T->isArrayType()) { if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T)) return CAT->getSize().getLimitedValue(); } } return 0; } } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr* DimExpr, SourceLocation RParen) { QualType T = TSInfo->getType(); // FIXME: This should likely be tracked as an APInt to remove any host // assumptions about the width of size_t on the target. uint64_t Value = 0; if (!T->isDependentType()) Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc); // While the specification for these traits from the Embarcadero C++ // compiler's documentation says the return type is 'unsigned int', Clang // returns 'size_t'. On Windows, the primary platform for the Embarcadero // compiler, there is no difference. On several other platforms this is an // important distinction. return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr, RParen, Context.getSizeType()); } ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { // If error parsing the expression, ignore. if (!Queried) return ExprError(); ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen); return Result; } static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { switch (ET) { case ET_IsLValueExpr: return E->isLValue(); case ET_IsRValueExpr: return E->isRValue(); } llvm_unreachable("Expression trait not covered by switch"); } ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { if (Queried->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (Queried->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(Queried); if (PE.isInvalid()) return ExprError(); return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen); } bool Value = EvaluateExpressionTrait(ET, Queried); return new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy); } QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { assert(!LHS.get()->getType()->isPlaceholderType() && !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); // The LHS undergoes lvalue conversions if this is ->*, and undergoes the // temporary materialization conversion otherwise. if (isIndirect) LHS = DefaultLvalueConversion(LHS.get()); else if (LHS.get()->isRValue()) LHS = TemporaryMaterializationConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); // The RHS always undergoes lvalue conversions. RHS = DefaultLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RHSType = RHS.get()->getType(); const MemberPointerType *MemPtr = RHSType->getAs(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RHSType << RHS.get()->getSourceRange(); return QualType(); } QualType Class(MemPtr->getClass(), 0); // Note: C++ [expr.mptr.oper]p2-3 says that the class type into which the // member pointer points must be completely-defined. However, there is no // reason for this semantic distinction, and the rule is not enforced by // other compilers. Therefore, we do not check this property, as it is // likely to be considered a defect. // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] QualType LHSType = LHS.get()->getType(); if (isIndirect) { if (const PointerType *Ptr = LHSType->getAs()) LHSType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LHSType << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } if (!Context.hasSameUnqualifiedType(Class, LHSType)) { // If we want to check the hierarchy, we need a complete type. if (RequireCompleteType(Loc, LHSType, diag::err_bad_memptr_lhs, OpSpelling, (int)isIndirect)) { return QualType(); } if (!IsDerivedFrom(Loc, LHSType, Class)) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect << LHS.get()->getType(); return QualType(); } CXXCastPath BasePath; if (CheckDerivedToBaseConversion(LHSType, Class, Loc, SourceRange(LHS.get()->getLocStart(), RHS.get()->getLocEnd()), &BasePath)) return QualType(); // Cast LHS to type of use. QualType UseType = Context.getQualifiedType(Class, LHSType.getQualifiers()); if (isIndirect) UseType = Context.getPointerType(UseType); ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind(); LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK, &BasePath); } if (isa(RHS.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; return QualType(); } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is // ill-formed if the second operand is a pointer to member function with // ref-qualifier &. In a ->* expression or in a .* expression whose object // expression is an lvalue, the program is ill-formed if the second operand // is a pointer to member function with ref-qualifier &&. if (const FunctionProtoType *Proto = Result->getAs()) { switch (Proto->getRefQualifier()) { case RQ_None: // Do nothing break; case RQ_LValue: if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { // C++2a allows functions with ref-qualifier & if their cv-qualifier-seq // is (exactly) 'const'. if (Proto->isConst() && !Proto->isVolatile()) Diag(Loc, getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : diag::ext_pointer_to_const_ref_member_on_rvalue); else Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 1 << LHS.get()->getSourceRange(); } break; case RQ_RValue: if (isIndirect || !LHS.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 0 << LHS.get()->getSourceRange(); break; } } // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its // first operand. The result of a .* expression whose second // operand is a pointer to a member function is a prvalue. The // result of an ->* expression is an lvalue if its second operand // is a pointer to data member and a prvalue otherwise. if (Result->isFunctionType()) { VK = VK_RValue; return Context.BoundMemberTy; } else if (isIndirect) { VK = VK_LValue; } else { VK = LHS.get()->getValueKind(); } return Result; } /// Try to convert a type to another according to C++11 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be /// converted to each other. This function does the conversion in one direction. /// It returns true if the program is ill-formed and has already been diagnosed /// as such. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, bool &HaveConversion, QualType &ToType) { HaveConversion = false; ToType = To->getType(); InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); // C++11 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: // -- If E2 is an lvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to type "lvalue reference to T2", subject to the // constraint that in the conversion the reference must bind directly to // an lvalue. // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. if (To->isLValue() || To->isXValue()) { QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) : Self.Context.getRValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs(); const RecordType *TRec = TTy->getAs(); bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(QuestionLoc, FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(QuestionLoc, TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } } return false; } // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. TTy = TTy.getNonLValueExprType(Self.Context); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); return false; } /// Try to find a common type for two according to C++0x 5.16p5. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc, OverloadCandidateSet::CSK_Operator); Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, CandidateSet); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: { // We found a match. Perform the conversions on the arguments and move on. ExprResult LHSRes = Self.PerformImplicitConversion( LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0], Sema::AA_Converting); if (LHSRes.isInvalid()) break; LHS = LHSRes; ExprResult RHSRes = Self.PerformImplicitConversion( RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1], Sema::AA_Converting); if (RHSRes.isInvalid()) break; RHS = RHSRes; if (Best->Function) Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; } case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is a pointer type. In this case, the user most // likely forgot to take the address of the other expression. if (Self.DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return true; Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return true; case OR_Ambiguous: Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // FIXME: Print the possible common types by printing the return types of // the viable candidates. break; case OR_Deleted: llvm_unreachable("Conditional operator has only built-in overloads"); } return true; } /// Perform an "extended" implicit conversion as returned by /// TryClassUnification. static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(), SourceLocation()); Expr *Arg = E.get(); InitializationSequence InitSeq(Self, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; E = Result; return false; } /// Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. // // FIXME; GCC's vector extension permits the use of a?b:c where the type of // a is that of a integer vector with the same number of elements and // size as the vectors of b and c. If one of either b or c is a scalar // it is implicitly converted to match the type of the vector. // Otherwise the expression is ill-formed. If both b and c are scalars, // then b and c are checked and converted to the type of a if possible. // Unlike the OpenCL ?: operator, the expression is evaluated as // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). if (!Cond.get()->isTypeDependent()) { ExprResult CondRes = CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) return QualType(); Cond = CondRes; } // Assume r-value. VK = VK_RValue; OK = OK_Ordinary; // Either of the arguments dependent? if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent()) return Context.DependentTy; // C++11 [expr.cond]p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS.get()->getType(); QualType RTy = RHS.get()->getType(); bool LVoid = LTy->isVoidType(); bool RVoid = RTy->isVoidType(); if (LVoid || RVoid) { // ... one of the following shall hold: // -- The second or the third operand (but not both) is a (possibly // parenthesized) throw-expression; the result is of the type // and value category of the other. bool LThrow = isa(LHS.get()->IgnoreParenImpCasts()); bool RThrow = isa(RHS.get()->IgnoreParenImpCasts()); if (LThrow != RThrow) { Expr *NonThrow = LThrow ? RHS.get() : LHS.get(); VK = NonThrow->getValueKind(); // DR (no number yet): the result is a bit-field if the // non-throw-expression operand is a bit-field. OK = NonThrow->getObjectKind(); return NonThrow->getType(); } // -- Both the second and third operands have type void; the result is of // type void and is a prvalue. if (LVoid && RVoid) return Context.VoidTy; // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1) << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // Neither is void. // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and // either has (cv) class type [...] an attempt is made to convert each of // those operands to the type of the other. if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { // These return true if a single direction is already ambiguous. QualType L2RType, R2LType; bool HaveL2R, HaveR2L; if (TryClassUnification(*this, LHS.get(), RHS.get(), QuestionLoc, HaveL2R, L2RType)) return QualType(); if (TryClassUnification(*this, RHS.get(), LHS.get(), QuestionLoc, HaveR2L, R2LType)) return QualType(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // If exactly one conversion is possible, that conversion is applied to // the chosen operand and the converted operands are used in place of the // original operands for the remainder of this section. if (HaveL2R) { if (ConvertForConditional(*this, LHS, L2RType) || LHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); } else if (HaveR2L) { if (ConvertForConditional(*this, RHS, R2LType) || RHS.isInvalid()) return QualType(); RTy = RHS.get()->getType(); } } // C++11 [expr.cond]p3 // if both are glvalues of the same value category and the same type except // for cv-qualification, an attempt is made to convert each of those // operands to the type of the other. // FIXME: // Resolving a defect in P0012R1: we extend this to cover all cases where // one of the operands is reference-compatible with the other, in order // to support conditionals between functions differing in noexcept. ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { // DerivedToBase was already handled by the class-specific case above. // FIXME: Should we allow ObjC conversions here? bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion; if (CompareReferenceRelationship( QuestionLoc, LTy, RTy, DerivedToBase, ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && // [...] subject to the constraint that the reference must bind // directly [...] !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); } else if (CompareReferenceRelationship( QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && !LHS.get()->refersToBitField() && !LHS.get()->refersToVectorElement()) { LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); LTy = LHS.get()->getType(); } } // C++11 [expr.cond]p4 // If the second and third operands are glvalues of the same value // category and have the same type, the result is of that type and // value category and it is a bit-field if the second or the third // operand is a bit-field, or if both are bit-fields. // We only extend this to bitfields, not to the crazy other kinds of // l-values. bool Same = Context.hasSameType(LTy, RTy); if (Same && LVK == RVK && LVK != VK_RValue && LHS.get()->isOrdinaryOrBitFieldObject() && RHS.get()->isOrdinaryOrBitFieldObject()) { VK = LHS.get()->getValueKind(); if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; // If we have function pointer types, unify them anyway to unify their // exception specifications, if any. if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { Qualifiers Qs = LTy.getQualifiers(); LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, /*ConvertArgs*/false); LTy = Context.getQualifiedType(LTy, Qs); assert(!LTy.isNull() && "failed to find composite pointer type for " "canonically equivalent function ptr types"); assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); } return LTy; } // C++11 [expr.cond]p5 // Otherwise, the result is a prvalue. If the second and third operands // do not have the same type, and either has (cv) class type, ... if (!Same && (LTy->isRecordType() || RTy->isRecordType())) { // ... overload resolution is used to determine the conversions (if any) // to be applied to the operands. If the overload resolution fails, the // program is ill-formed. if (FindConditionalOverload(*this, LHS, RHS, QuestionLoc)) return QualType(); } // C++11 [expr.cond]p6 // Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); RTy = RHS.get()->getType(); // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result // is of that type. If the operands have class type, the result // is a prvalue temporary of the result type, which is // copy-initialized from either the second operand or the third // operand depending on the value of the first operand. if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), LHS); if (LHSCopy.isInvalid()) return QualType(); ExprResult RHSCopy = PerformCopyInitialization(Entity, SourceLocation(), RHS); if (RHSCopy.isInvalid()) return QualType(); LHS = LHSCopy; RHS = RHSCopy; } // If we have function pointer types, unify them anyway to unify their // exception specifications, if any. if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); assert(!LTy.isNull() && "failed to find composite pointer type for " "canonically equivalent function ptr types"); } return LTy; } // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (ResTy.isNull()) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); return ResTy; } // -- The second and third operands have pointer type, or one has pointer // type and the other is a null pointer constant, or both are null // pointer constants, at least one of which is non-integral; pointer // conversions and qualification conversions are performed to bring them // to their composite pointer type. The result is of the composite // pointer type. // -- The second and third operands have pointer to member type, or one has // pointer to member type and the other is a null pointer constant; // pointer to member conversions and qualification conversions are // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS); if (!Composite.isNull()) return Composite; // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; // Check if we are using a null with a non-pointer type. if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } static FunctionProtoType::ExceptionSpecInfo mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl &ExceptionTypeStorage) { ExceptionSpecificationType EST1 = ESI1.Type; ExceptionSpecificationType EST2 = ESI2.Type; // If either of them can throw anything, that is the result. if (EST1 == EST_None) return ESI1; if (EST2 == EST_None) return ESI2; if (EST1 == EST_MSAny) return ESI1; if (EST2 == EST_MSAny) return ESI2; if (EST1 == EST_NoexceptFalse) return ESI1; if (EST2 == EST_NoexceptFalse) return ESI2; // If either of them is non-throwing, the result is the other. if (EST1 == EST_DynamicNone) return ESI2; if (EST2 == EST_DynamicNone) return ESI1; if (EST1 == EST_BasicNoexcept) return ESI2; if (EST2 == EST_BasicNoexcept) return ESI1; if (EST1 == EST_NoexceptTrue) return ESI2; if (EST2 == EST_NoexceptTrue) return ESI1; // If we're left with value-dependent computed noexcept expressions, we're // stuck. Before C++17, we can just drop the exception specification entirely, // since it's not actually part of the canonical type. And this should never // happen in C++17, because it would mean we were computing the composite // pointer type of dependent types, which should never happen. if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { assert(!S.getLangOpts().CPlusPlus17 && "computing composite pointer type of dependent types"); return FunctionProtoType::ExceptionSpecInfo(); } // Switch over the possibilities so that people adding new values know to // update this function. switch (EST1) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: llvm_unreachable("handled above"); case EST_Dynamic: { // This is the fun case: both exception specifications are dynamic. Form // the union of the two lists. assert(EST2 == EST_Dynamic && "other cases should already be handled"); llvm::SmallPtrSet Found; for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) for (QualType E : Exceptions) if (Found.insert(S.Context.getCanonicalType(E)).second) ExceptionTypeStorage.push_back(E); FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); Result.Exceptions = ExceptionTypeStorage; return Result; } case EST_Unevaluated: case EST_Uninstantiated: case EST_Unparsed: llvm_unreachable("shouldn't see unresolved exception specifications here"); } llvm_unreachable("invalid ExceptionSpecificationType"); } /// Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 /// and @p E2 according to C++1z 5p14. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. /// /// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool ConvertArgs) { assert(getLangOpts().CPlusPlus && "This function assumes C++"); // C++1z [expr]p14: // The composite pointer type of two operands p1 and p2 having types T1 // and T2 QualType T1 = E1->getType(), T2 = E2->getType(); // where at least one is a pointer or pointer to member type or // std::nullptr_t is: bool T1IsPointerLike = T1->isAnyPointerType() || T1->isMemberPointerType() || T1->isNullPtrType(); bool T2IsPointerLike = T2->isAnyPointerType() || T2->isMemberPointerType() || T2->isNullPtrType(); if (!T1IsPointerLike && !T2IsPointerLike) return QualType(); // - if both p1 and p2 are null pointer constants, std::nullptr_t; // This can't actually happen, following the standard, but we also use this // to implement the end of [expr.conv], which hits this case. // // - if either p1 or p2 is a null pointer constant, T2 or T1, respectively; if (T1IsPointerLike && E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (ConvertArgs) E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer).get(); return T1; } if (T2IsPointerLike && E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (ConvertArgs) E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer).get(); return T2; } // Now both have to be pointers or member pointers. if (!T1IsPointerLike || !T2IsPointerLike) return QualType(); assert(!T1->isNullPtrType() && !T2->isNullPtrType() && "nullptr_t should be a null pointer constant"); // - if T1 or T2 is "pointer to cv1 void" and the other type is // "pointer to cv2 T", "pointer to cv12 void", where cv12 is // the union of cv1 and cv2; // - if T1 or T2 is "pointer to noexcept function" and the other type is // "pointer to function", where the function types are otherwise the same, // "pointer to function"; // FIXME: This rule is defective: it should also permit removing noexcept // from a pointer to member function. As a Clang extension, we also // permit removing 'noreturn', so we generalize this rule to; // - [Clang] If T1 and T2 are both of type "pointer to function" or // "pointer to member function" and the pointee types can be unified // by a function pointer conversion, that conversion is applied // before checking the following rules. // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), // the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1, // respectively; // - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and // T1 or the cv-combined type of T1 and T2, respectively; // - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and // T2; // // If looked at in the right way, these bullets all do the same thing. // What we do here is, we build the two possible cv-combined types, and try // the conversions in both directions. If only one works, or if the two // composite types are the same, we have succeeded. // FIXME: extended qualifiers? // // Note that this will fail to find a composite pointer type for "pointer // to void" and "pointer to function". We can't actually perform the final // conversion in this case, even though a composite pointer type formally // exists. SmallVector QualifierUnion; SmallVector, 4> MemberOfClass; QualType Composite1 = T1; QualType Composite2 = T2; unsigned NeedConstBefore = 0; while (true) { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(nullptr, nullptr)); continue; } const MemberPointerType *MemPtr1, *MemPtr2; if ((MemPtr1 = Composite1->getAs()) && (MemPtr2 = Composite2->getAs())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), MemPtr2->getClass())); continue; } // FIXME: block pointer types? // Cannot unwrap any more types. break; } // Apply the function pointer conversion to unify the types. We've already // unwrapped down to the function types, and we want to merge rather than // just convert, so do this ourselves rather than calling // IsFunctionConversion. // // FIXME: In order to match the standard wording as closely as possible, we // currently only do this under a single level of pointers. Ideally, we would // allow this in general, and set NeedConstBefore to the relevant depth on // the side(s) where we changed anything. if (QualifierUnion.size() == 1) { if (auto *FPT1 = Composite1->getAs()) { if (auto *FPT2 = Composite2->getAs()) { FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); // The result is noreturn if both operands are. bool Noreturn = EPI1.ExtInfo.getNoReturn() && EPI2.ExtInfo.getNoReturn(); EPI1.ExtInfo = EPI1.ExtInfo.withNoReturn(Noreturn); EPI2.ExtInfo = EPI2.ExtInfo.withNoReturn(Noreturn); // The result is nothrow if both operands are. SmallVector ExceptionTypeStorage; EPI1.ExceptionSpec = EPI2.ExceptionSpec = mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage); Composite1 = Context.getFunctionType(FPT1->getReturnType(), FPT1->getParamTypes(), EPI1); Composite2 = Context.getFunctionType(FPT2->getReturnType(), FPT2->getParamTypes(), EPI2); } } } if (NeedConstBefore) { // Extension: Add 'const' to qualifiers that come before the first qualifier // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. for (unsigned I = 0; I != NeedConstBefore; ++I) if ((QualifierUnion[I] & Qualifiers::Const) == 0) QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; } // Rewrap the composites as pointers or member pointers with the union CVRs. auto MOC = MemberOfClass.rbegin(); for (unsigned CVR : llvm::reverse(QualifierUnion)) { Qualifiers Quals = Qualifiers::fromCVRMask(CVR); auto Classes = *MOC++; if (Classes.first && Classes.second) { // Rebuild member pointer type Composite1 = Context.getMemberPointerType( Context.getQualifiedType(Composite1, Quals), Classes.first); Composite2 = Context.getMemberPointerType( Context.getQualifiedType(Composite2, Quals), Classes.second); } else { // Rebuild pointer type Composite1 = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); Composite2 = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); } } struct Conversion { Sema &S; Expr *&E1, *&E2; QualType Composite; InitializedEntity Entity; InitializationKind Kind; InitializationSequence E1ToC, E2ToC; bool Viable; Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2, QualType Composite) : S(S), E1(E1), E2(E2), Composite(Composite), Entity(InitializedEntity::InitializeTemporary(Composite)), Kind(InitializationKind::CreateCopy(Loc, SourceLocation())), E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2), Viable(E1ToC && E2ToC) {} bool perform() { ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1); if (E1Result.isInvalid()) return true; E1 = E1Result.getAs(); ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2); if (E2Result.isInvalid()) return true; E2 = E2Result.getAs(); return false; } }; // Try to convert to each composite pointer type. Conversion C1(*this, Loc, E1, E2, Composite1); if (C1.Viable && Context.hasSameType(Composite1, Composite2)) { if (ConvertArgs && C1.perform()) return QualType(); return C1.Composite; } Conversion C2(*this, Loc, E1, E2, Composite2); if (C1.Viable == C2.Viable) { // Either Composite1 and Composite2 are viable and are different, or // neither is viable. // FIXME: How both be viable and different? return QualType(); } // Convert to the chosen type. if (ConvertArgs && (C1.Viable ? C1 : C2).perform()) return QualType(); return C1.Viable ? C1.Composite : C2.Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!E) return ExprError(); assert(!isa(E) && "Double-bound temporary?"); // If the result is a glvalue, we shouldn't bind it. if (!E->isRValue()) return E; // In ARC, calls that return a retainable type can return retained, // in which case we have to insert a consuming cast. if (getLangOpts().ObjCAutoRefCount && E->getType()->isObjCRetainableType()) { bool ReturnsRetained; // For actual calls, we compute this by examining the type of the // called value. if (CallExpr *Call = dyn_cast(E)) { Expr *Callee = Call->getCallee()->IgnoreParens(); QualType T = Callee->getType(); if (T == Context.BoundMemberTy) { // Handle pointer-to-members. if (BinaryOperator *BinOp = dyn_cast(Callee)) T = BinOp->getRHS()->getType(); else if (MemberExpr *Mem = dyn_cast(Callee)) T = Mem->getMemberDecl()->getType(); } if (const PointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const BlockPointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const MemberPointerType *MemPtr = T->getAs()) T = MemPtr->getPointeeType(); const FunctionType *FTy = T->getAs(); assert(FTy && "call to value not of function type?"); ReturnsRetained = FTy->getExtInfo().getProducesResult(); // ActOnStmtExpr arranges things so that StmtExprs of retainable // type always produce a +1 object. } else if (isa(E)) { ReturnsRetained = true; // We hit this case with the lambda conversion-to-block optimization; // we don't want any extra casts here. } else if (isa(E) && isa(cast(E)->getSubExpr())) { return E; // For message sends and property references, we try to find an // actual method. FIXME: we should infer retention by selector in // cases where we don't have an actual method. } else { ObjCMethodDecl *D = nullptr; if (ObjCMessageExpr *Send = dyn_cast(E)) { D = Send->getMethodDecl(); } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast(E)) { D = BoxedExpr->getBoxingMethod(); } else if (ObjCArrayLiteral *ArrayLit = dyn_cast(E)) { // Don't do reclaims if we're using the zero-element array // constant. if (ArrayLit->getNumElements() == 0 && Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) return E; D = ArrayLit->getArrayWithObjectsMethod(); } else if (ObjCDictionaryLiteral *DictLit = dyn_cast(E)) { // Don't do reclaims if we're using the zero-element dictionary // constant. if (DictLit->getNumElements() == 0 && Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) return E; D = DictLit->getDictWithObjectsMethod(); } ReturnsRetained = (D && D->hasAttr()); // Don't do reclaims on performSelector calls; despite their // return type, the invoked method doesn't necessarily actually // return an object. if (!ReturnsRetained && D && D->getMethodFamily() == OMF_performSelector) return E; } // Don't reclaim an object of Class type. if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType()) return E; Cleanup.setExprNeedsCleanups(true); CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject : CK_ARCReclaimReturnedObject); return ImplicitCastExpr::Create(Context, E->getType(), ck, E, nullptr, VK_RValue); } if (!getLangOpts().CPlusPlus) return E; // Search for the base element type (cf. ASTContext::getBaseElementType) with // a fast path for the common case that the type is directly a RecordType. const Type *T = Context.getCanonicalType(E->getType().getTypePtr()); const RecordType *RT = nullptr; while (!RT) { switch (T->getTypeClass()) { case Type::Record: RT = cast(T); break; case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: T = cast(T)->getElementType().getTypePtr(); break; default: return E; } } // That should be enough to guarantee that this type is complete, if we're // not processing a decltype expression. CXXRecordDecl *RD = cast(RT->getDecl()); if (RD->isInvalidDecl() || RD->isDependentContext()) return E; bool IsDecltype = ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::EK_Decltype; CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD); if (Destructor) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return ExprError(); // If destructor is trivial, we can avoid the extra copy. if (Destructor->isTrivial()) return E; // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E); if (IsDecltype) ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind); return Bind; } ExprResult Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); return MaybeCreateExprWithCleanups(SubExpr.get()); } Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { assert(SubExpr && "subexpression can't be null!"); CleanupVarDeclMarking(); unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects; assert(ExprCleanupObjects.size() >= FirstCleanup); assert(Cleanup.exprNeedsCleanups() || ExprCleanupObjects.size() == FirstCleanup); if (!Cleanup.exprNeedsCleanups()) return SubExpr; auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, ExprCleanupObjects.size() - FirstCleanup); auto *E = ExprWithCleanups::Create( Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups); DiscardCleanupsInEvaluationContext(); return E; } Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { assert(SubStmt && "sub-statement can't be null!"); CleanupVarDeclMarking(); if (!Cleanup.exprNeedsCleanups()) return SubStmt; // FIXME: In order to attach the temporaries, wrap the statement into // a StmtExpr; currently this is only used for asm statements. // This is hacky, either create a new CXXStmtWithTemporaries statement or // a new AsmStmtWithTemporaries. CompoundStmt *CompStmt = CompoundStmt::Create( Context, SubStmt, SourceLocation(), SourceLocation()); Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation()); return MaybeCreateExprWithCleanups(E); } /// Process the expression contained within a decltype. For such expressions, /// certain semantic checks on temporaries are delayed until this point, and /// are omitted for the 'topmost' call in the decltype expression. If the /// topmost call bound a temporary, strip that temporary off the expression. ExprResult Sema::ActOnDecltypeExpression(Expr *E) { assert(ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::EK_Decltype && "not in a decltype expression"); // C++11 [expr.call]p11: // If a function call is a prvalue of object type, // -- if the function call is either // -- the operand of a decltype-specifier, or // -- the right operand of a comma operator that is the operand of a // decltype-specifier, // a temporary object is not introduced for the prvalue. // Recursively rebuild ParenExprs and comma expressions to strip out the // outermost CXXBindTemporaryExpr, if any. if (ParenExpr *PE = dyn_cast(E)) { ExprResult SubExpr = ActOnDecltypeExpression(PE->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (SubExpr.get() == PE->getSubExpr()) return E; return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.get()); } if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { ExprResult RHS = ActOnDecltypeExpression(BO->getRHS()); if (RHS.isInvalid()) return ExprError(); if (RHS.get() == BO->getRHS()) return E; return new (Context) BinaryOperator( BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); } } CXXBindTemporaryExpr *TopBind = dyn_cast(E); CallExpr *TopCall = TopBind ? dyn_cast(TopBind->getSubExpr()) : nullptr; if (TopCall) E = TopCall; else TopBind = nullptr; // Disable the special decltype handling now. ExprEvalContexts.back().ExprContext = ExpressionEvaluationContextRecord::EK_Other; // In MS mode, don't perform any extra checking of call return types within a // decltype expression. if (getLangOpts().MSVCCompat) return E; // Perform the semantic checks we delayed until this point. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size(); I != N; ++I) { CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I]; if (Call == TopCall) continue; if (CheckCallReturnType(Call->getCallReturnType(Context), Call->getLocStart(), Call, Call->getDirectCallee())) return ExprError(); } // Now all relevant types are complete, check the destructors are accessible // and non-deleted, and annotate them on the temporaries. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size(); I != N; ++I) { CXXBindTemporaryExpr *Bind = ExprEvalContexts.back().DelayedDecltypeBinds[I]; if (Bind == TopBind) continue; CXXTemporary *Temp = Bind->getTemporary(); CXXRecordDecl *RD = Bind->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); CXXDestructorDecl *Destructor = LookupDestructor(RD); Temp->setDestructor(Destructor); MarkFunctionReferenced(Bind->getExprLoc(), Destructor); CheckDestructorAccess(Bind->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << Bind->getType()); if (DiagnoseUseOfDecl(Destructor, Bind->getExprLoc())) return ExprError(); // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } // Possibly strip off the top CXXBindTemporaryExpr. return E; } /// Note a set of 'operator->' functions that were used for a member access. static void noteOperatorArrows(Sema &S, ArrayRef OperatorArrows) { unsigned SkipStart = OperatorArrows.size(), SkipCount = 0; // FIXME: Make this configurable? unsigned Limit = 9; if (OperatorArrows.size() > Limit) { // Produce Limit-1 normal notes and one 'skipping' note. SkipStart = (Limit - 1) / 2 + (Limit - 1) % 2; SkipCount = OperatorArrows.size() - (Limit - 1); } for (unsigned I = 0; I < OperatorArrows.size(); /**/) { if (I == SkipStart) { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrows_suppressed) << SkipCount; I += SkipCount; } else { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrow_here) << OperatorArrows[I]->getCallResultType(); ++I; } } } ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); QualType BaseType = Base->getType(); MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, // the object type is the type that the pointer points to. We might still // have enough information about that type to do something useful. if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } // C++ [over.match.oper]p8: // [...] When operator->returns, the operator-> is applied to the value // returned, with the original second operand. if (OpKind == tok::arrow) { QualType StartingType = BaseType; bool NoArrowOperatorFound = false; bool FirstIteration = true; FunctionDecl *CurFD = dyn_cast(CurContext); // The set of types we've considered so far. llvm::SmallPtrSet CTypes; SmallVector OperatorArrows; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { if (OperatorArrows.size() >= getLangOpts().ArrowDepth) { Diag(OpLoc, diag::err_operator_arrow_depth_exceeded) << StartingType << getLangOpts().ArrowDepth << Base->getSourceRange(); noteOperatorArrows(*this, OperatorArrows); Diag(OpLoc, diag::note_operator_arrow_depth) << getLangOpts().ArrowDepth; return ExprError(); } Result = BuildOverloadedArrowExpr( S, Base, OpLoc, // When in a template specialization and on the first loop iteration, // potentially give the default diagnostic (with the fixit in a // separate note) instead of having the error reported back to here // and giving a diagnostic with a fixit attached to the error itself. (FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization()) ? nullptr : &NoArrowOperatorFound); if (Result.isInvalid()) { if (NoArrowOperatorFound) { if (FirstIteration) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << 1 << Base->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "."); OpKind = tok::period; break; } Diag(OpLoc, diag::err_typecheck_member_reference_arrow) << BaseType << Base->getSourceRange(); CallExpr *CE = dyn_cast(Base); if (Decl *CD = (CE ? CE->getCalleeDecl() : nullptr)) { Diag(CD->getLocStart(), diag::note_member_reference_arrow_from_operator_arrow); } } return ExprError(); } Base = Result.get(); if (CXXOperatorCallExpr *OpCall = dyn_cast(Base)) OperatorArrows.push_back(OpCall->getDirectCallee()); BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); if (!CTypes.insert(CBaseType).second) { Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType; noteOperatorArrows(*this, OperatorArrows); return ExprError(); } FirstIteration = false; } if (OpKind == tok::arrow && (BaseType->isPointerType() || BaseType->isObjCObjectPointerType())) BaseType = BaseType->getPointeeType(); } // Objective-C properties allow "." access on Objective-C pointer types, // so adjust the base type to the object type itself. if (BaseType->isObjCObjectPointerType()) BaseType = BaseType->getPointeeType(); // C++ [basic.lookup.classref]p2: // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete // postfix-expression. // // This also indicates that we could be parsing a pseudo-destructor-name. // Note that Objective-C class and object types can be pseudo-destructor // expressions or normal member (ivar or property) access expressions, and // it's legal for the type to be incomplete if this is a pseudo-destructor // call. We'll do more incomplete-type checks later in the lookup process, // so just skip this check for ObjC types. if (BaseType->isObjCObjectOrInterfaceType()) { ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } else if (!BaseType->isRecordType()) { ObjectType = nullptr; MayBePseudoDestructor = true; return Base; } // The object type must be complete (or dependent), or // C++11 [expr.prim.general]p3: // Unlike the object expression in other contexts, *this is not required to // be of complete type for purposes of class member access (5.2.5) outside // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access)) return ExprError(); // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an // unqualified-id, and the type of the object expression is of a class // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = ParsedType::make(BaseType); return Base; } static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, tok::TokenKind& OpKind, SourceLocation OpLoc) { if (Base->hasPlaceholderType()) { ExprResult result = S.CheckPlaceholderExpr(Base); if (result.isInvalid()) return true; Base = result.get(); } ObjectType = Base->getType(); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. // This scalar type is the object type. // Note that this is rather different from the normal handling for the // arrow operator. if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); } else if (!Base->isTypeDependent()) { // The user wrote "p->" when they probably meant "p."; fix it. S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true << FixItHint::CreateReplacement(OpLoc, "."); if (S.isSFINAEContext()) return true; OpKind = tok::period; } } return false; } /// Check if it's ok to try and recover dot pseudo destructor calls on /// pointer objects. static bool canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, QualType DestructedType) { // If this is a record type, check if its destructor is callable. if (auto *RD = DestructedType->getAsCXXRecordDecl()) { if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); return false; } // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor. return DestructedType->isDependentType() || DestructedType->isScalarType() || DestructedType->isVectorType(); } ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destructed) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); if (!ObjectType->isDependentType() && !ObjectType->isScalarType() && !ObjectType->isVectorType()) { if (getLangOpts().MSVCCompat && ObjectType->isVoidType()) Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange(); else { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); return ExprError(); } } // C++ [expr.pseudo]p2: // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { // Detect dot pseudo destructor calls on pointer objects, e.g.: // Foo *foo; // foo.~Foo(); if (OpKind == tok::period && ObjectType->isPointerType() && Context.hasSameUnqualifiedType(DestructedType, ObjectType->getPointeeType())) { auto Diagnostic = Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << /*IsArrow=*/0 << Base->getSourceRange(); // Issue a fixit only when the destructor is valid. if (canRecoverDotPseudoDestructorCallsOnPointerObjects( *this, DestructedType)) Diagnostic << FixItHint::CreateReplacement(OpLoc, "->"); // Recover by setting the object type to the destructed type and the // operator to '->'. ObjectType = DestructedType; OpKind = tok::arrow; } else { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { // Okay: just pretend that the user provided the correctly-qualified // type. } else { Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); } // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } } // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); ScopeTypeInfo = nullptr; } } Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, SS.getWithLocInContext(Context), ScopeTypeInfo, CCLoc, TildeLoc, Destructed); return Result; } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName) { assert((FirstTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || FirstTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) && "Invalid first type name in pseudo-destructor"); assert((SecondTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || SecondTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) && "Invalid second type name in pseudo-destructor"); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); // Compute the object type that we should use for name lookup purposes. Only // record types and dependent types matter. ParsedType ObjectTypePtrForLookup; if (!SS.isSet()) { if (ObjectType->isRecordType()) ObjectTypePtrForLookup = ParsedType::make(ObjectType); else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = nullptr; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) { ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup, /*IsCtorOrDtorName*/true); if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = nullptr; QualType ScopeType; if (FirstTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) { ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup, /*IsCtorOrDtorName*/true); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T, &ScopeTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by dropping this type. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed); } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS) { QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T); PseudoDestructorTypeStorage Destructed(DestructedTypeInfo); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(), nullptr, SourceLocation(), TildeLoc, Destructed); } ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates) { // Convert the expression to match the conversion function's implicit object // parameter. ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr, FoundDecl, Method); if (Exp.isInvalid()) return true; if (Method->getParent()->isLambda() && Method->getConversionType()->isBlockPointerType()) { // This is a lambda coversion to block pointer; check if the argument // was a LambdaExpr. Expr *SubE = E; CastExpr *CE = dyn_cast(SubE); if (CE && CE->getCastKind() == CK_NoOp) SubE = CE->getSubExpr(); SubE = SubE->IgnoreParens(); if (CXXBindTemporaryExpr *BE = dyn_cast(SubE)) SubE = BE->getSubExpr(); if (isa(SubE)) { // For the conversion to block pointer on a lambda expression, we // construct a special BlockLiteral instead; this doesn't really make // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult BlockExp = BuildBlockForLambdaConversion( Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); if (BlockExp.isInvalid()) Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); return BlockExp; } } MemberExpr *ME = new (Context) MemberExpr( Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(), Context.BoundMemberTy, VK_RValue, OK_Ordinary); if (HadMultipleCandidates) ME->setHadMultipleCandidates(true); MarkMemberReferenced(ME); QualType ResultType = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK, Exp.get()->getLocEnd()); if (CheckFunctionCall(Method, CE, Method->getType()->castAs())) return ExprError(); return CE; } ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { // If the operand is an unresolved lookup expression, the expression is ill- // formed per [over.over]p1, because overloaded function names cannot be used // without arguments except in explicit contexts. ExprResult R = CheckPlaceholderExpr(Operand); if (R.isInvalid()) return R; // The operand may have been modified when checking the placeholder type. Operand = R.get(); if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) { // The expression operand for noexcept is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); } CanThrowResult CanThrow = canThrow(Operand); return new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen); } ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, Expr *Operand, SourceLocation RParen) { return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } static bool IsSpecialDiscardedValue(Expr *E) { // In C++11, discarded-value expressions of a certain form are special, // according to [expr]p10: // The lvalue-to-rvalue conversion (4.1) is applied only if the // expression is an lvalue of volatile-qualified type and it has // one of the following forms: E = E->IgnoreParens(); // - id-expression (5.1.1), if (isa(E)) return true; // - subscripting (5.2.1), if (isa(E)) return true; // - class member access (5.2.5), if (isa(E)) return true; // - indirection (5.3.1), if (UnaryOperator *UO = dyn_cast(E)) if (UO->getOpcode() == UO_Deref) return true; if (BinaryOperator *BO = dyn_cast(E)) { // - pointer-to-member operation (5.5), if (BO->isPtrMemOp()) return true; // - comma expression (5.18) where the right operand is one of the above. if (BO->getOpcode() == BO_Comma) return IsSpecialDiscardedValue(BO->getRHS()); } // - conditional expression (5.16) where both the second and the third // operands are one of the above, or if (ConditionalOperator *CO = dyn_cast(E)) return IsSpecialDiscardedValue(CO->getTrueExpr()) && IsSpecialDiscardedValue(CO->getFalseExpr()); // The related edge case of "*x ?: *x". if (BinaryConditionalOperator *BCO = dyn_cast(E)) { if (OpaqueValueExpr *OVE = dyn_cast(BCO->getTrueExpr())) return IsSpecialDiscardedValue(OVE->getSourceExpr()) && IsSpecialDiscardedValue(BCO->getFalseExpr()); } // Objective-C++ extensions to the rule. if (isa(E) || isa(E)) return true; return false; } /// Perform the conversions required for an expression used in a /// context that ignores the result. ExprResult Sema::IgnoredValueConversions(Expr *E) { if (E->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return E; E = result.get(); } // C99 6.3.2.1: // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). if (E->isRValue()) { // In C, function designators (i.e. expressions of function type) // are r-values, but we still want to do function-to-pointer decay // on them. This is both technically correct and convenient for // some clients. if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType()) return DefaultFunctionArrayConversion(E); return E; } if (getLangOpts().CPlusPlus) { // The C++11 standard defines the notion of a discarded-value expression; // normally, we don't need to do anything to handle it, but if it is a // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. if (getLangOpts().CPlusPlus11 && E->isGLValue() && E->getType().isVolatileQualified() && IsSpecialDiscardedValue(E)) { ExprResult Res = DefaultLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); } // C++1z: // If the expression is a prvalue after this optional conversion, the // temporary materialization conversion is applied. // // We skip this step: IR generation is able to synthesize the storage for // itself in the aggregate case, and adding the extra node to the AST is // just clutter. // FIXME: We don't emit lifetime markers for the temporaries due to this. // FIXME: Do any other AST consumers care about this? return E; } // GCC seems to also exclude expressions of incomplete enum type. if (const EnumType *T = E->getType()->getAs()) { if (!T->getDecl()->isComplete()) { // FIXME: stupid workaround for a codegen bug! E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); return E; } } ExprResult Res = DefaultFunctionArrayLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); if (!E->getType()->isVoidType()) RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_incomplete_type); return E; } // If we can unambiguously determine whether Var can never be used // in a constant expression, return true. // - if the variable and its initializer are non-dependent, then // we can unambiguously check if the variable is a constant expression. // - if the initializer is not value dependent - we can determine whether // it can be used to initialize a constant expression. If Init can not // be used to initialize a constant expression we conclude that Var can // never be a constant expression. // - FXIME: if the initializer is dependent, we can still do some analysis and // identify certain cases unambiguously as non-const by using a Visitor: // - such as those that involve odr-use of a ParmVarDecl, involve a new // delete, lambda-expr, dynamic-cast, reinterpret-cast etc... static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, ASTContext &Context) { if (isa(Var)) return true; const VarDecl *DefVD = nullptr; // If there is no initializer - this can not be a constant expression. if (!Var->getAnyInitializer(DefVD)) return true; assert(DefVD); if (DefVD->isWeak()) return false; EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt(); Expr *Init = cast(Eval->Value); if (Var->getType()->isDependentType() || Init->isValueDependent()) { // FIXME: Teach the constant evaluator to deal with the non-dependent parts // of value-dependent expressions, and use it here to determine whether the // initializer is a potential constant expression. return false; } return !IsVariableAConstantExpression(Var, Context); } /// Check if the current lambda has any potential captures /// that must be captured by any of its enclosing lambdas that are ready to /// capture. If there is a lambda that can capture a nested /// potential-capture, go ahead and do so. Also, check to see if any /// variables are uncaptureable or do not involve an odr-use so do not /// need to be captured. static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { assert(!S.isUnevaluatedContext()); assert(S.CurContext->isDependentContext()); #ifndef NDEBUG DeclContext *DC = S.CurContext; while (DC && isa(DC)) DC = DC->getParent(); assert( CurrentLSI->CallOperator == DC && "The current call operator must be synchronized with Sema's CurContext"); #endif // NDEBUG const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. const unsigned NumPotentialCaptures = CurrentLSI->getNumPotentialVariableCaptures(); for (unsigned I = 0; I != NumPotentialCaptures; ++I) { Expr *VarExpr = nullptr; VarDecl *Var = nullptr; CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr); // If the variable is clearly identified as non-odr-used and the full // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. // For e.g.: // Even though 'x' is not odr-used, it should be captured. // int test() { // const int x = 10; // auto L = [=](auto a) { // (void) +x + a; // }; // } if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) && !IsFullExprInstantiationDependent) continue; // If we have a capture-capable lambda for the variable, go ahead and // capture the variable in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, Var, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S, &FunctionScopeIndexOfCapturableLambda); } const bool IsVarNeverAConstantExpression = VariableCanNeverBeAConstantExpression(Var, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable // can not be used in a constant expression - which means // this variable must be odr-used here, so diagnose a // capture violation early, if the variable is un-captureable. // This is purely for diagnosing errors early. Otherwise, this // error would get diagnosed when the lambda becomes capture ready. QualType CaptureType, DeclRefType; SourceLocation ExprLoc = VarExpr->getExprLoc(); if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/false, CaptureType, DeclRefType, nullptr)) { // We will never be able to capture this variable, and we need // to be able to in any and all instantiations, so diagnose it. S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/true, CaptureType, DeclRefType, nullptr); } } } // Check if 'this' needs to be captured. if (CurrentLSI->hasPotentialThisCapture()) { // If we have a capture-capable lambda for 'this', go ahead and capture // 'this' in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation, /*Explicit*/ false, /*BuildAndDiagnose*/ true, &FunctionScopeIndexOfCapturableLambda); } } // Reset all the potential captures at the end of each full-expression. CurrentLSI->clearPotentialCaptures(); } static ExprResult attemptRecovery(Sema &SemaRef, const TypoCorrectionConsumer &Consumer, const TypoCorrection &TC) { LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), Consumer.getLookupResult().getLookupKind()); const CXXScopeSpec *SS = Consumer.getSS(); CXXScopeSpec NewSS; // Use an approprate CXXScopeSpec for building the expr. if (auto *NNS = TC.getCorrectionSpecifier()) NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); else if (SS && !TC.WillReplaceSpecifier()) NewSS = *SS; if (auto *ND = TC.getFoundDecl()) { R.setLookupName(ND->getDeclName()); R.addDecl(ND); if (ND->isCXXClassMember()) { // Figure out the correct naming class to add to the LookupResult. CXXRecordDecl *Record = nullptr; if (auto *NNS = TC.getCorrectionSpecifier()) Record = NNS->getAsType()->getAsCXXRecordDecl(); if (!Record) Record = dyn_cast(ND->getDeclContext()->getRedeclContext()); if (Record) R.setNamingClass(Record); // Detect and handle the case where the decl might be an implicit // member. bool MightBeImplicitMember; if (!Consumer.isAddressOfOperand()) MightBeImplicitMember = true; else if (!NewSS.isEmpty()) MightBeImplicitMember = false; else if (R.isOverloadedResult()) MightBeImplicitMember = false; else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else MightBeImplicitMember = isa(ND) || isa(ND) || isa(ND); if (MightBeImplicitMember) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, /*TemplateArgs*/ nullptr, /*S*/ nullptr); } else if (auto *Ivar = dyn_cast(ND)) { return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), Ivar->getIdentifier()); } } return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false, /*AcceptInvalidDecl*/ true); } namespace { class FindTypoExprs : public RecursiveASTVisitor { llvm::SmallSetVector &TypoExprs; public: explicit FindTypoExprs(llvm::SmallSetVector &TypoExprs) : TypoExprs(TypoExprs) {} bool VisitTypoExpr(TypoExpr *TE) { TypoExprs.insert(TE); return true; } }; class TransformTypos : public TreeTransform { typedef TreeTransform BaseTransform; VarDecl *InitDecl; // A decl to avoid as a correction because it is in the // process of being initialized. llvm::function_ref ExprFilter; llvm::SmallSetVector TypoExprs, AmbiguousTypoExprs; llvm::SmallDenseMap TransformCache; llvm::SmallDenseMap OverloadResolution; /// Emit diagnostics for all of the TypoExprs encountered. /// If the TypoExprs were successfully corrected, then the diagnostics should /// suggest the corrections. Otherwise the diagnostics will not suggest /// anything (having been passed an empty TypoCorrection). void EmitAllDiagnostics() { for (TypoExpr *TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); if (State.DiagHandler) { TypoCorrection TC = State.Consumer->getCurrentCorrection(); ExprResult Replacement = TransformCache[TE]; // Extract the NamedDecl from the transformed TypoExpr and add it to the // TypoCorrection, replacing the existing decls. This ensures the right // NamedDecl is used in diagnostics e.g. in the case where overload // resolution was used to select one from several possible decls that // had been stored in the TypoCorrection. if (auto *ND = getDeclFromExpr( Replacement.isInvalid() ? nullptr : Replacement.get())) TC.setCorrectionDecl(ND); State.DiagHandler(TC); } SemaRef.clearDelayedTypo(TE); } } /// If corrections for the first TypoExpr have been exhausted for a /// given combination of the other TypoExprs, retry those corrections against /// the next combination of substitutions for the other TypoExprs by advancing /// to the next potential correction of the second TypoExpr. For the second /// and subsequent TypoExprs, if its stream of corrections has been exhausted, /// the stream is reset and the next TypoExpr's stream is advanced by one (a /// TypoExpr's correction stream is advanced by removing the TypoExpr from the /// TransformCache). Returns true if there is still any untried combinations /// of corrections. bool CheckAndAdvanceTypoExprCorrectionStreams() { for (auto TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); TransformCache.erase(TE); if (!State.Consumer->finished()) return true; State.Consumer->resetCorrectionStream(); } return false; } NamedDecl *getDeclFromExpr(Expr *E) { if (auto *OE = dyn_cast_or_null(E)) E = OverloadResolution[OE]; if (!E) return nullptr; if (auto *DRE = dyn_cast(E)) return DRE->getFoundDecl(); if (auto *ME = dyn_cast(E)) return ME->getFoundDecl(); // FIXME: Add any other expr types that could be be seen by the delayed typo // correction TreeTransform for which the corresponding TypoCorrection could // contain multiple decls. return nullptr; } ExprResult TryTransform(Expr *E) { Sema::SFINAETrap Trap(SemaRef); ExprResult Res = TransformExpr(E); if (Trap.hasErrorOccurred() || Res.isInvalid()) return ExprError(); return ExprFilter(Res.get()); } public: TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref Filter) : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig = nullptr) { auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, RParenLoc, ExecConfig); if (auto *OE = dyn_cast(Callee)) { if (Result.isUsable()) { Expr *ResultCall = Result.get(); if (auto *BE = dyn_cast(ResultCall)) ResultCall = BE->getSubExpr(); if (auto *CE = dyn_cast(ResultCall)) OverloadResolution[OE] = CE->getCallee(); } } return Result; } ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } ExprResult Transform(Expr *E) { ExprResult Res; while (true) { Res = TryTransform(E); // Exit if either the transform was valid or if there were no TypoExprs // to transform that still have any untried correction candidates.. if (!Res.isInvalid() || !CheckAndAdvanceTypoExprCorrectionStreams()) break; } // Ensure none of the TypoExprs have multiple typo correction candidates // with the same edit length that pass all the checks and filters. // TODO: Properly handle various permutations of possible corrections when // there is more than one potentially ambiguous typo correction. // Also, disable typo correction while attempting the transform when // handling potentially ambiguous typo corrections as any new TypoExprs will // have been introduced by the application of one of the correction // candidates and add little to no value if corrected. SemaRef.DisableTypoCorrection = true; while (!AmbiguousTypoExprs.empty()) { auto TE = AmbiguousTypoExprs.back(); auto Cached = TransformCache[TE]; auto &State = SemaRef.getTypoExprState(TE); State.Consumer->saveCurrentPosition(); TransformCache.erase(TE); if (!TryTransform(E).isInvalid()) { State.Consumer->resetCorrectionStream(); TransformCache.erase(TE); Res = ExprError(); break; } AmbiguousTypoExprs.remove(TE); State.Consumer->restoreSavedPosition(); TransformCache[TE] = Cached; } SemaRef.DisableTypoCorrection = false; // Ensure that all of the TypoExprs within the current Expr have been found. if (!Res.isUsable()) FindTypoExprs(TypoExprs).TraverseStmt(E); EmitAllDiagnostics(); return Res; } ExprResult TransformTypoExpr(TypoExpr *E) { // If the TypoExpr hasn't been seen before, record it. Otherwise, return the // cached transformation result if there is one and the TypoExpr isn't the // first one that was encountered. auto &CacheEntry = TransformCache[E]; if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) { return CacheEntry; } auto &State = SemaRef.getTypoExprState(E); assert(State.Consumer && "Cannot transform a cleared TypoExpr"); // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { if (InitDecl && TC.getFoundDecl() == InitDecl) continue; // FIXME: If we would typo-correct to an invalid declaration, it's // probably best to just suppress all errors from this typo correction. ExprResult NE = State.RecoveryHandler ? State.RecoveryHandler(SemaRef, E, TC) : attemptRecovery(SemaRef, *State.Consumer, TC); if (!NE.isInvalid()) { // Check whether there may be a second viable correction with the same // edit distance; if so, remember this TypoExpr may have an ambiguous // correction so it can be more thoroughly vetted later. TypoCorrection Next; if ((Next = State.Consumer->peekNextCorrection()) && Next.getEditDistance(false) == TC.getEditDistance(false)) { AmbiguousTypoExprs.insert(E); } else { AmbiguousTypoExprs.remove(E); } assert(!NE.isUnset() && "Typo was transformed into a valid-but-null ExprResult"); return CacheEntry = NE; } } return CacheEntry = ExprError(); } }; } ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, llvm::function_ref Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to // resolve any TypoExpr nodes that might be in the expression. if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && (E->isTypeDependent() || E->isValueDependent() || E->isInstantiationDependent())) { auto TyposResolved = DelayedTypos.size(); auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); } return E; } ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, bool IsConstexpr, bool IsLambdaInitCaptureInitializer) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); // If we are an init-expression in a lambdas init-capture, we should not // diagnose an unexpanded pack now (will be diagnosed once lambda-expr // containing full-expression is done). // template void test(Ts ... t) { // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now. // return a; // }() ...); // } // FIXME: This is a hack. It would be better if we pushed the lambda scope // when we parse the lambda introducer, and teach capturing (but not // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a // corresponding class yet (that is, have LambdaScopeInfo either represent a // lambda where we've entered the introducer but not the body, or represent a // lambda where we've entered the body, depending on where the // parser/instantiation has got to). if (!IsLambdaInitCaptureInitializer && DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); // Top-level expressions default to 'id' when we're in a debugger. if (DiscardedValue && getLangOpts().DebuggerCastResultToId && FullExpr.get()->getType() == Context.UnknownAnyTy) { FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType()); if (FullExpr.isInvalid()) return ExprError(); } if (DiscardedValue) { FullExpr = CheckPlaceholderExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); FullExpr = IgnoredValueConversions(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); } FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); // At the end of this full expression (which could be a deeply nested // lambda), if there is a potential capture within the nested lambda, // have the outer capture-able lambda try and capture it. // Consider the following code: // void f(int, int); // void f(const int&, double); // void foo() { // const int x = 10, y = 20; // auto L = [=](auto a) { // auto M = [=](auto b) { // f(x, b); <-- requires x to be captured by L and M // f(y, a); <-- requires y to be captured by L, but not all Ms // }; // }; // } // FIXME: Also consider what happens for something like this that involves // the gnu-extension statement-expressions or even lambda-init-captures: // void f() { // const int n = 0; // auto L = [&](auto a) { // +n + ({ 0; a; }); // }; // } // // Here, we see +n, and then the full-expression 0; ends, so we don't // capture n (and instead remove it from our list of potential captures), // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. LambdaScopeInfo *const CurrentLSI = getCurLambda(/*IgnoreCapturedRegions=*/true); // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report // for an example of the code that might cause this asynchrony. // By ensuring we are in the context of a lambda's call operator // we can fix the bug (we only need to check whether we need to capture // if we are within a lambda's body); but per the comments in that // PR, a proper fix would entail : // "Alternative suggestion: // - Add to Sema an integer holding the smallest (outermost) scope // index that we are *lexically* within, and save/restore/set to // FunctionScopes.size() in InstantiatingTemplate's // constructor/destructor. // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." DeclContext *DC = CurContext; while (DC && isa(DC)) DC = DC->getParent(); const bool IsInLambdaDeclContext = isLambdaCallOperator(DC); if (IsInLambdaDeclContext && CurrentLSI && CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid()) CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI, *this); return MaybeCreateExprWithCleanups(FullExpr); } StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { if (!FullStmt) return StmtError(); return MaybeCreateStmtWithCleanups(FullStmt); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo) { DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return IER_DoesNotExist; // If the name itself is dependent, then the result is dependent. if (TargetName.isDependentName()) return IER_Dependent; // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); LookupParsedName(R, S, &SS); R.suppressDiagnostics(); switch (R.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: case LookupResult::Ambiguous: return IER_Exists; case LookupResult::NotFound: return IER_DoesNotExist; case LookupResult::NotFoundInCurrentInstantiation: return IER_Dependent; } llvm_unreachable("Invalid LookupResult Kind!"); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); // Check for an unexpanded parameter pack. auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists; if (DiagnoseUnexpandedParameterPack(SS, UPPC) || DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC)) return IER_Error; return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } diff --git a/test/CodeGen/global-blocks-win32.c b/test/CodeGen/global-blocks-win32.c new file mode 100644 index 000000000000..7a66c924b420 --- /dev/null +++ b/test/CodeGen/global-blocks-win32.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fblocks -triple i386-pc-windows-msvc %s -emit-llvm -o - -fblocks | FileCheck %s + + +int (^x)(void) = ^() { return 21; }; + + +// Check that the block literal is emitted with a null isa pointer +// CHECK: @__block_literal_global = internal global { i8**, i32, i32, i8*, %struct.__block_descriptor* } { i8** null, + +// Check that _NSConcreteGlobalBlock has the correct dllimport specifier. +// CHECK: @_NSConcreteGlobalBlock = external dllimport global i8* +// Check that we create an initialiser pointer in the correct section (early library initialisation). +// CHECK: @.block_isa_init_ptr = internal constant void ()* @.block_isa_init, section ".CRT$XCLa" + +// Check that we emit an initialiser for it. +// CHECK: define internal void @.block_isa_init() { +// CHECK: store i8** @_NSConcreteGlobalBlock, i8*** getelementptr inbounds ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }, { i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global, i32 0, i32 0), align 4 + diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index 105605c6e37b..33ea49663491 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -1,88 +1,99 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s typedef int INT; class Foo { Foo(); (Foo)(float) { } explicit Foo(int); // expected-note {{previous declaration is here}} Foo(const Foo&); ((Foo))(INT); // expected-error{{cannot be redeclared}} Foo(Foo foo, int i = 17, int j = 42); // expected-error{{copy constructor must pass its first argument by reference}} static Foo(short, short); // expected-error{{constructor cannot be declared 'static'}} virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}} Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}} int Foo(int, int); // expected-error{{constructor cannot have a return type}} volatile Foo(float); // expected-error{{constructor cannot have a return type}} }; Foo::Foo(const Foo&) { } typedef struct { int version; } Anon; extern const Anon anon; extern "C" const Anon anon2; // PR3188: The extern declaration complained about not having an appropriate // constructor. struct x; extern x a; // A similar case. struct y { y(int); }; extern y b; struct Length { Length l() const { return *this; } }; // struct mmst_reg{ char mmst_reg[10]; }; // PR3948 namespace PR3948 { // PR3948 class a { public: int b(int a()); }; int x(); void y() { a z; z.b(x); } } namespace A { struct S { S(); S(int); void f1(); void f2(); operator int (); ~S(); }; } A::S::S() {} void A::S::f1() {} struct S {}; A::S::S(int) {} void A::S::f2() {} A::S::operator int() { return 1; } A::S::~S() {} +namespace PR38286 { + // FIXME: It'd be nice to give more consistent diagnostics for these cases + // (but they're all failing for somewhat different reasons...). + template struct A; + template A::A() {} // expected-error {{incomplete type 'A' named in nested name specifier}} + /*FIXME: needed to recover properly from previous error*/; + template struct B; + template void B::f() {} // expected-error {{out-of-line definition of 'f' from class 'B'}} + template struct C; + template C::~C() {} // expected-error {{no type named 'C' in 'C'}} +} diff --git a/test/lit.cfg.py b/test/lit.cfg.py index ad30988c1796..c962b41723e5 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -1,188 +1,188 @@ # -*- Python -*- import os import platform import re import subprocess import tempfile import lit.formats import lit.util from lit.llvm import llvm_config from lit.llvm.subst import ToolSubst from lit.llvm.subst import FindTool # Configuration file for the 'lit' test runner. # name: The name of this test suite. config.name = 'Clang' # testFormat: The test format to use to interpret tests. # # For now we require '&&' between commands, until they get globally killed and # the test runner updated. config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs'] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent # directories. config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt', 'debuginfo-tests'] # test_source_root: The root path where tests are located. config.test_source_root = os.path.dirname(__file__) # test_exec_root: The root path where tests should be run. config.test_exec_root = os.path.join(config.clang_obj_root, 'test') llvm_config.use_default_substitutions() llvm_config.use_clang() # Propagate path to symbolizer for ASan/MSan. llvm_config.with_system_environment( ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']) config.substitutions.append(('%PATH%', config.environment['PATH'])) # For each occurrence of a clang tool name, replace it with the full path to # the build directory holding that tool. We explicitly specify the directories # to search to ensure that we get the tools just built and not some random # tools that might happen to be in the user's PATH. tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] tools = [ 'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', ToolSubst('%clang_func_map', command=FindTool( 'clang-func-mapping'), unresolved='ignore'), ] if config.clang_examples: config.available_features.add('examples') tools.append('clang-interpreter') llvm_config.add_tool_substitutions(tools, tool_dirs) config.substitutions.append( ('%hmaptool', "'%s' %s" % (config.python_executable, - os.path.join(config.llvm_tools_dir, 'hmaptool')))) + os.path.join(config.clang_tools_dir, 'hmaptool')))) # Plugins (loadable modules) # TODO: This should be supplied by Makefile or autoconf. if sys.platform in ['win32', 'cygwin']: has_plugins = config.enable_shared else: has_plugins = True if has_plugins and config.llvm_plugin_ext: config.available_features.add('plugins') # Set available features we allow tests to conditionalize on. # if config.clang_default_cxx_stdlib != '': config.available_features.add('default-cxx-stdlib-set') # Enabled/disabled features if config.clang_staticanalyzer: config.available_features.add('staticanalyzer') if config.clang_staticanalyzer_z3 == '1': config.available_features.add('z3') # As of 2011.08, crash-recovery tests still do not pass on FreeBSD. if platform.system() not in ['FreeBSD']: config.available_features.add('crash-recovery') # ANSI escape sequences in non-dumb terminal if platform.system() not in ['Windows']: config.available_features.add('ansi-escape-sequences') # Capability to print utf8 to the terminal. # Windows expects codepage, unless Wide API. if platform.system() not in ['Windows']: config.available_features.add('utf8-capable-terminal') # Support for libgcc runtime. Used to rule out tests that require # clang to run with -rtlib=libgcc. if platform.system() not in ['Darwin', 'Fuchsia']: config.available_features.add('libgcc') # Case-insensitive file system def is_filesystem_case_insensitive(): handle, path = tempfile.mkstemp( prefix='case-test', dir=config.test_exec_root) isInsensitive = os.path.exists( os.path.join( os.path.dirname(path), os.path.basename(path).upper() )) os.close(handle) os.remove(path) return isInsensitive if is_filesystem_case_insensitive(): config.available_features.add('case-insensitive-filesystem') # Tests that require the /dev/fd filesystem. if os.path.exists('/dev/fd/0') and sys.platform not in ['cygwin']: config.available_features.add('dev-fd-fs') # Not set on native MS environment. if not re.match(r'.*-win32$', config.target_triple): config.available_features.add('non-ms-sdk') # Not set on native PS4 environment. if not re.match(r'.*-scei-ps4', config.target_triple): config.available_features.add('non-ps4-sdk') # [PR8833] LLP64-incompatible tests if not re.match(r'^x86_64.*-(win32|mingw32|windows-gnu)$', config.target_triple): config.available_features.add('LP64') # [PR12920] "clang-driver" -- set if gcc driver is not used. if not re.match(r'.*-(cygwin)$', config.target_triple): config.available_features.add('clang-driver') # [PR18856] Depends to remove opened file. On win32, a file could be removed # only if all handles were closed. if platform.system() not in ['Windows']: config.available_features.add('can-remove-opened-file') def calculate_arch_features(arch_string): features = [] for arch in arch_string.split(): features.append(arch.lower() + '-registered-target') return features llvm_config.feature_config( [('--assertion-mode', {'ON': 'asserts'}), ('--cxxflags', {r'-D_GLIBCXX_DEBUG\b': 'libstdcxx-safe-mode'}), ('--targets-built', calculate_arch_features) ]) if lit.util.which('xmllint'): config.available_features.add('xmllint') if config.enable_backtrace: config.available_features.add('backtrace') # Check if we should allow outputs to console. run_console_tests = int(lit_config.params.get('enable_console', '0')) if run_console_tests != 0: config.available_features.add('console') lit.util.usePlatformSdkOnDarwin(config, lit_config) macOSSDKVersion = lit.util.findPlatformSdkVersionOnMacOS(config, lit_config) if macOSSDKVersion is not None: config.available_features.add('macos-sdk-' + macOSSDKVersion) diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index cdeb451911dc..8362a52b76db 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -1,13960 +1,13960 @@ Clang - C++ Defect Report Status

C++ Defect Report Support in Clang

-

Last updated: $Date: 2018-07-27 06:41:37 +0200 (Fri, 27 Jul 2018) $

+

Last updated: $Date: 2018-08-06 12:32:02 +0200 (Mon, 06 Aug 2018) $

C++ defect report implementation status

This page tracks which C++ defect reports are implemented within Clang.

- + - + - + - + - + - + - + - + - +
Number Status Issue title Available in Clang?
1 TC1 What if two using-declarations refer to the same function but the declarations introduce different default-arguments? No
2 drafting How can dependent names be used in member declarations that appear outside of the class template definition? Not resolved
3 NAD The template compilation model rules render some explicit specialization declarations not visible during instantiation Yes
4 CD1 Does extern "C" affect the linkage of function names with internal linkage? Yes
5 CD1 CV-qualifiers and type conversions Yes
6 open Should the optimization that allows a class object to alias another object also allow the case of a parameter in an inline function to alias its argument? Not resolved
7 NAD Can a class with a private virtual base class be derived from? Yes
8 CD1 Access to template arguments used in a function return type and in the nested name specifier Duplicate of 45
9 CD1 Clarification of access to base class members Yes
10 CD1 Can a nested class access its own class name as a qualified name if it is a private member of the enclosing class? Duplicate of 45
11 CD1 How do the keywords typename/template interact with using-declarations? Yes
12 dup Default arguments on different declarations for the same function and the Koenig lookup Superseded by 239
13 NAD extern "C" for Parameters of Function Templates No
14 NAD extern "C" functions and declarations in different namespaces Yes
15 dup Default arguments for parameters of function templates Yes
16 CD1 Access to members of indirect private base classes Yes
17 NAD Footnote 99 should discuss the naming class when describing members that can be accessed from friends Yes
18 NAD f(TYPE) where TYPE is void should be allowed Superseded by 577
19 NAD Clarify protected member access Yes
20 TC1 Some clarifications needed for 12.8 para 15 Yes
21 TC1 Can a default argument for a template parameter appear in a friend declaration? Yes
22 TC1 Template parameter with a default argument that refers to itself Superseded by 481
23 NAD Some questions regarding partial ordering of function templates Yes
24 TC1 Errors in examples in 14.7.3 N/A
25 TC1 Exception specifications and pointers to members Yes
26 NAD Copy constructors and default arguments Yes
27 NAD Overload ambiguities for builtin ?: prototypes Yes
28 CD1 'exit', 'signal' and static object destruction N/A (Library DR)
29 CD1 Linkage of locally declared functions Clang 3.4
30 TC1 Valid uses of "::template" Superseded by 468 (C++11 onwards)
31 NAD Looking up new/delete Yes
32 TC1 Clarification of explicit instantiation of non-exported templates N/A
33 TC1 Argument dependent lookup and overloaded functions Yes
34 NAD Argument dependent lookup and points of instantiation N/A
35 TC1 Definition of default-initialization Duplicate of 178
36 open using-declarations in multiple-declaration contexts Not resolved
37 NAD When is uncaught_exception() true? Superseded by 475
38 TC1 Explicit template arguments and operator functions Yes
39 CD1 Conflicting ambiguity rules No
40 TC1 Syntax of declarator-id N/A
41 TC1 Clarification of lookup of names after declarator-id Yes
42 NAD Redefining names from base classes Yes
43 TC1 Copying base classes (PODs) using memcpy N/A
44 CD1 Member specializations Superseded by 727
45 CD1 Access to nested classes Yes
46 NAD Explicit instantiation of member templates Yes
47 NAD Template friend issues Superseded by 329
48 TC1 Definitions of unused static members Yes
49 TC1 Restriction on non-type, non-value template arguments Yes
50 NAD Converting pointer to incomplete type to same type Yes
51 TC1 Overloading and user-defined conversions Yes
52 TC1 Non-static members, member selection and access checking Yes
53 TC1 Lvalue-to-rvalue conversion before certain static_casts Yes
54 CD1 Static_cast from private base to derived class Yes
55 NAD Adding/subtracting pointer and enumeration value Yes
56 TC1 Redeclaring typedefs within classes Yes
57 open Empty unions Not resolved
58 CD1 Signedness of bit fields of enum type Yes
59 TC1 Clarification of overloading and UDC to reference type Yes
60 CD1 Reference binding and valid conversion sequences Yes
61 NAD Address of static member function "&p->f" Yes
62 CD1 Unnamed members of classes used as type parameters Yes
63 CD1 Class instantiation from pointer conversion to void*, null and self Yes
64 TC1 Partial ordering to disambiguate explicit specialization Yes
65 TC1 Typo in default argument example N/A
66 NAD Visibility of default args vs overloads added after using-declaration No
67 TC1 Evaluation of left side of object-expression N/A
68 TC1 Grammar does not allow "friend class A<int>;" Yes
69 TC1 Storage class specifiers on template declarations Yes
70 CD1 Is an array bound a nondeduced context? Yes
71 NAD Incorrect cross reference N/A
72 dup Linkage and storage class specifiers for templates Duplicate of 69
73 TC1 Pointer equality No
74 TC1 Enumeration value in direct-new-declarator Yes
75 TC1 In-class initialized members must be const Yes
76 TC1 Are const volatile variables considered "constant expressions"? Yes
77 CD1 The definition of friend does not allow nested classes to be friends Yes
78 CD1 Section 8.5 paragraph 9 should state it only applies to non-static objects Superseded by ????
79 dup Alignment and placement new N/A
80 TC1 Class members with same name as class Yes
81 NAD Null pointers and C compatibility N/A
82 dup Definition of "using" a constant expression Duplicate of 48
83 TC1 Overloading and deprecated conversion of string literal Yes
84 TC1 Overloading and conversion loophole used by auto_ptr Yes
85 TC1 Redeclaration of member class Yes
86 CD1 Lifetime of temporaries in query expressions Duplicate of 446
87 CD1 Exception specifications on function parameters No
88 NAD Specialization of member constant templates Yes
89 TC1 Object lifetime does not account for reference rebinding N/A
90 TC1 Should the enclosing class be an "associated class" too? Yes
91 NAD A union's associated types should include the union itself Yes
92 CD4 Should exception-specifications be part of the type system? Clang 4 (C++17 onwards)
93 TC1 Missing word in 3.8 basic.life paragraph 2 N/A
94 TC1 Inconsistencies in the descriptions of constant expressions Yes
95 NAD Elaborated type specifiers referencing names declared in friend decls Yes
96 C++11 Syntactic disambiguation using the template keyword No
97 NAD Use of bool constants in integral constant expressions Yes
98 TC1 Branching into try block Yes
99 NAD Partial ordering, references and cv-qualifiers Superseded by 214
100 TC1 Clarify why string literals are not allowed as template arguments Yes
101 TC1 Redeclaration of extern "C" names via using-declarations Clang 3.5
102 NAD Operator lookup rules do not work well with parts of the library Yes
103 TC1 Is it extended-namespace-definition or extension-namespace-definition ? N/A
104 NAD Destroying the exception temp when no handler is found N/A (Library DR)
105 TC1 Meaning of "template function" N/A
106 CD1 Creating references to references during template deduction/instantiation Superseded by 540
107 NAD Linkage of operator functions Yes
108 TC1 Are classes nested in templates dependent? Yes
109 NAD Allowing ::template in using-declarations Yes
110 open Can template functions and classes be declared in the same scope? Not resolved
111 NAD Copy constructors and cv-qualifiers Duplicate of 535
112 CD1 Array types and cv-qualifiers Yes
113 CD1 Visibility of called function Yes
114 NAD Virtual overriding by template member function specializations Yes
115 CD1 Address of template-id Yes
116 TC1 Equivalent and functionally-equivalent function templates Yes
117 NAD Timing of destruction of temporaries N/A
118 CD1 Calls via pointers to virtual member functions Yes
119 CD1 Object lifetime and aggregate initialization N/A
120 TC1 Nonexistent non-terminal qualified-name N/A
121 TC1 Dependent type names with non-dependent nested-name-specifiers Yes
122 CD1 template-ids as unqualified-ids Yes
123 TC1 Bad cross-reference N/A
124 CD1 Lifetime of temporaries in default initialization of class arrays Duplicate of 201
125 CD1 Ambiguity in friend declaration syntax Yes
126 TC1 Exception specifications and const Partial
127 TC1 Ambiguity in description of matching deallocation function Yes
128 TC1 Casting between enum types Yes
129 CD3 Stability of uninitialized auto variables Duplicate of 616
130 NAD Sequence points and new-expressions N/A
131 TC1 Typo in Lao characters Yes
132 NAD Local types and linkage No
133 dup Exception specifications and checking Duplicate of 87
134 TC1 Template classes and declarator-ids N/A
135 TC1 Class type in in-class member function definitions Yes
136 CD1 Default arguments and friend declarations Clang 3.4
137 TC1 static_cast of cv void* Yes
138 drafting Friend declaration name lookup Not resolved
139 CD1 Error in friend lookup example Yes
140 CD1 Agreement of parameter declarations Yes
141 CD1 Non-member function templates in member access expressions Yes
142 TC1 Injection-related errors in access example Yes
143 CD1 Friends and Koenig lookup Yes
144 open Position of friend specifier Not resolved
145 TC1 Deprecation of prefix ++ Yes
146 open Floating-point zero Not resolved
147 TC1 Naming the constructor Yes
148 TC1 POD classes and pointers to members Yes
149 TC1 Accessibility and ambiguity N/A
150 C++17 Template template parameters and default arguments Unknown
151 TC1 Terminology of zero-initialization Yes
152 TC1 explicit copy constructors Yes
153 TC1 Misleading wording (rank of conversion) N/A
154 NAD Anonymous unions in unnamed namespaces Yes
155 dup Brace initializer for scalar Duplicate of 632
156 drafting Name lookup for conversion functions Not resolved
157 open Omitted typedef declarator Not resolved
158 CD1 Aliasing and qualification conversions Yes
159 TC1 Namespace qualification in declarators Clang 3.5
160 CD1 Missing std:: qualification N/A
161 TC1 Access to protected nested type Yes
162 CD1 (&C::f)() with nonstatic members No
163 TC1 Description of subaggregate initializer N/A
164 TC1 Overlap between Koenig and normal lookup Yes
165 NAD Definitions of friends and block-scope externs No
166 TC1 Friend declarations of template-ids Yes
167 NAD Deprecating static functions Superseded by 1012
168 NAD C linkage for static member functions No
169 NAD template-ids in using-declarations Yes
170 drafting Pointer-to-member conversions Not resolved
171 TC1 Global namespace scope Yes
172 CD1 Unsigned int as underlying type of enum Yes
173 TC1 Constraints on execution character set Yes
174 NAD Undeprecating global static Superseded by 1012
175 CD1 Class name injection and base name access Yes
176 TC1 Name injection and templates Yes
177 CD1 Lvalues vs rvalues in copy-initialization Yes
178 TC1 More on value-initialization Yes
179 TC1 Function pointers and subtraction Yes
180 CD1 typename and elaborated types Yes
181 TC1 Errors in template template-parameter example Yes
182 NAD Access checking on explicit specializations Yes
183 TC1 typename in explicit specializations Superseded by 382
184 CD1 Default arguments in template template-parameters Yes
185 TC1 "Named" temporaries and copy elision Unknown
186 open Name hiding and template template-parameters Not resolved
187 TC1 Scope of template parameter names Superseded by 481
188 TC1 Comma operator and rvalue conversion Yes
189 drafting Definition of operator and punctuator Not resolved
190 TC1 Layout-compatible POD-struct types Unknown
191 open Name lookup does not handle complex nesting Not resolved
192 drafting Name lookup in parameters Not resolved
193 TC1 Order of destruction of local automatics of destructor Unknown
194 TC1 Identifying constructors Yes
195 CD1 Converting between function and object pointers Yes
196 open Arguments to deallocation functions Not resolved
197 CD1 Issues with two-stage lookup of dependent names Yes
198 CD1 Definition of "use" in local and nested classes Yes
199 CD1 Order of destruction of temporaries Unknown
200 dup Partial ordering and explicit arguments Duplicate of 214
201 CD1 Order of destruction of temporaries in initializers Unknown
202 TC1 Use of overloaded function name Yes
203 NAD Type of address-of-member expression Unknown
204 CD1 Exported class templates No
205 drafting Templates and static data members Not resolved
206 TC1 Semantic constraints on non-dependent names Yes
207 CD1 using-declarations and protected access Yes
208 CD1 Rethrowing exceptions in nested handlers Unknown
209 NAD Must friend declaration names be accessible? Yes
210 TC1 What is the type matched by an exception handler? Unknown
211 NAD Constructors should not be allowed to return normally after an exception Yes
212 CD4 Implicit instantiation is not described clearly enough Unknown
213 TC1 Lookup in dependent base classes Yes
214 CD1 Partial ordering of function templates is underspecified Yes
215 CD1 Template parameters are not allowed in nested-name-specifiers Yes
216 CD1 Linkage of nameless class-scope enumeration types No
217 TC1 Default arguments for non-template member functions of class templates Yes
218 CD1 Specification of Koenig lookup Yes
219 NAD Cannot defend against destructors that throw exceptions N/A
220 CD1 All deallocation functions should be required not to throw N/A
221 CD1 Must compound assignment operators be member functions? Yes
222 CD1 Sequence points and lvalue-returning operators Duplicate of 637
223 CD3 The meaning of deprecation N/A
224 CD1 Definition of dependent names No
225 NAD Koenig lookup and fundamental types Yes
226 CD1 Default template arguments for function templates No
227 TC1 How many scopes in an if statement? Yes
228 CD1 Use of template keyword with non-member templates Yes
229 NAD Partial specialization of function templates Yes
230 NAD Calls to pure virtual functions Yes
231 NAD Visibility of names after using-directives Yes
232 drafting Is indirection through a null pointer undefined behavior? Not resolved
233 open References vs pointers in UDC overload resolution Not resolved
234 NAD Reuse of base class subobjects N/A
235 TC1 Assignment vs initialization N/A
236 NAD Explicit temporaries and integral constant expressions Yes
237 CD1 Explicit instantiation and base class members Duplicate of 470
238 CD4 Precision and accuracy constraints on floating point Unknown
239 CD1 Footnote 116 and Koenig lookup Yes
240 CD3 Uninitialized values and undefined behavior Duplicate of 616
241 TC1 Error in example in 14.8.1 Yes
242 CD4 Interpretation of old-style casts Unknown
243 NAD Weighting of conversion functions in direct-initialization Yes
244 CD1 Destructor lookup Partial
245 CD1 Name lookup in elaborated-type-specifiers Yes
246 CD1 Jumps in function-try-block handlers Yes
247 NAD Pointer-to-member casts and function overload resolution Yes
248 C++11 Identifier characters Yes (C++11 onwards)
249 TC1 What is a member function template? Yes
250 TC1 Address of function template specialization with non-deduced template arguments Yes
251 open How many signed integer types are there? Not resolved
252 CD1 Looking up deallocation functions in virtual destructors Yes
253 C++17 Why must empty or fully-initialized const objects be initialized? Unknown
254 CD1 Definitional problems with elaborated-type-specifiers Yes
255 drafting Placement deallocation functions and lookup ambiguity Not resolved
256 CD1 Overflow in size calculations Duplicate of 624
257 CD2 Abstract base constructors and virtual base initialization Yes
258 CD1 using-declarations and cv-qualifiers Yes
259 CD1 Restrictions on explicit specialization and instantiation Clang 4
260 open User-defined conversions and built-in operator= Not resolved
261 CD1 When is a deallocation function "used?" No
262 CD1 Default arguments and ellipsis Yes
263 CD1 Can a constructor be declared a friend? Yes
264 open Unusable template constructors and conversion functions Not resolved
265 dup Destructors, exceptions, and deallocation Duplicate of 353
266 NAD No grammar sentence symbol N/A
267 open Alignment requirement for new-expressions Not resolved
268 open Macro name suppression in rescanned replacement text Not resolved
269 NAD Order of initialization of multiply-defined static data members of class templates N/A
270 CD1 Order of initialization of static data members of class templates N/A
271 open Explicit instantiation and template argument deduction Not resolved
272 CD1 Explicit destructor invocation and qualified-ids Yes
273 CD1 POD classes and operator&() Yes
274 CD1 Cv-qualification and char-alias access to out-of-lifetime objects N/A
275 CD1 Explicit instantiation/specialization and using-directives No
276 CD1 Order of destruction of parameters and temporaries N/A
277 CD1 Zero-initialization of pointers Yes
278 open External linkage and nameless entities Not resolved
279 open Correspondence of "names for linkage purposes" Not resolved
280 CD1 Access and surrogate call functions Yes
281 CD1 inline specifier in friend declarations No
282 open Namespace for extended_type_info Not resolved
283 CD1 Template type-parameters are not syntactically type-names Yes
284 CD1 qualified-ids in class declarations No
285 NAD Identifying a function template being specialized Yes
286 CD1 Incorrect example in partial specialization Yes
287 drafting Order dependencies in template instantiation Not resolved
288 CD1 Misuse of "static type" in describing pointers N/A
289 CD1 Incomplete list of contexts requiring a complete type Yes
290 NAD Should memcpy be allowed into a POD with a const member? N/A
291 CD1 Overload resolution needed when binding reference to class rvalue Duplicate of 391
292 CD3 Deallocation on exception in new before arguments evaluated Unknown
293 open Syntax of explicit instantiation/specialization too permissive Not resolved
294 NAD Can static_cast drop exception specifications? No
295 CD1 cv-qualifiers on function types Clang 3.7
296 CD1 Can conversion functions be static? Yes
297 open Which template does an explicit specialization specialize? Not resolved
298 CD1 T::x when T is cv-qualified Yes
299 CD1 Conversion on array bound expression in new Yes (C++11 onwards)
300 CD1 References to functions in template argument deduction Yes
301 CD1 Syntax for template-name Yes
302 CD1 Value-initialization and generation of default constructor Yes
303 NAD Integral promotions on bit-fields N/A
304 TC1 Value-initialization of a reference Yes
305 CD1 Name lookup in destructor call No
306 CD1 Ambiguity by class name injection No
307 NAD Initialization of a virtual base class subobject N/A
308 NAD Catching exceptions with ambiguous base classes Yes
309 CD1 Linkage of entities whose names are not simply identifiers, in introduction Duplicate of 485
310 open Can function templates differing only in parameter cv-qualifiers be overloaded? Not resolved
311 NAD Using qualified name to reopen nested namespace Yes
312 CD3 “use” of invalid pointer value not defined Duplicate of 616
313 dup Class with single conversion function to integral as array size in new Duplicate of 299 (C++11 onwards)
314 C++17 template in base class specifier Unknown
315 NAD Is call of static member function through null pointer undefined? N/A
316 NAD Injected-class-name of template used as template template parameter Superseded by 1004
317 CD1 Can a function be declared inline after it has been called? Clang 3.5
318 CD1 struct A::A should not name the constructor of A Superseded by 1310
319 CD1 Use of names without linkage in declaring entities with linkage No
320 CD1 Question on copy constructor elision example Yes
321 dup Associated classes and namespaces for argument-dependent lookup Duplicate of 557
322 CD1 Deduction of reference conversions Yes
323 CD1 Where must export appear? No
324 CD1 Can "&" be applied to assignment to bit-field? Yes
325 drafting When are default arguments parsed? Not resolved
326 CD1 Wording for definition of trivial constructor Yes
327 CD1 Use of "structure" without definition Duplicate of 538
328 CD1 Missing requirement that class member types be complete Yes
329 CD1 Evaluation of friends of templates Clang 3.5
330 CD4 Qualification conversions and pointers to arrays of pointersSVNClang 7
331 CD1 Allowed copy constructor signatures Yes
332 CD3 cv-qualified void parameter types Duplicate of 577
333 NAD Ambiguous use of "declaration" in disambiguation section Yes
334 NAD Is a comma-expression dependent if its first operand is? Yes
335 CD1 Allowing export on template members of nontemplate classes No
336 CD1 Explicit specialization examples are still incorrect Yes
337 CD1 Attempt to create array of abtract type should cause deduction to fail Yes
338 open Enumerator name with linkage used as class name in other translation unit Not resolved
339 CD1 Overload resolution in operand of sizeof in constant expression Yes
340 NAD Unclear wording in disambiguation section Yes
341 C++11 extern "C" namespace member function versus global variable Superseded by 1708
342 CD3 Terminology: "indirection" versus "dereference" N/A
343 C++17 Make template optional in contexts that require a type Unknown
344 CD3 Naming destructors Duplicate of 1435
345 CD1 Misleading comment on example in templates chapter Yes
346 NAD Typo in 15.4 N/A
347 NAD Use of derived class name in defining base class nested class Yes
348 CD1 delete and user-written deallocation functions N/A
349 CD1 Template argument deduction for conversion functions and qualification conversions No
350 open signed char underlying representation for objects Not resolved
351 CD1 Sequence point error: unspecified or undefined? N/A
352 CD1 Nondeduced contexts Yes
353 CD1 Is deallocation routine called if destructor throws exception in delete? Unknown
354 CD1 Null as nontype template argument Yes (C++11 onwards)
355 C++11 Global-scope :: in nested-name-specifier Yes
356 NAD Wording of behavior of generated copy constructor for scalar members N/A
357 CD1 Definition of signature should include name Yes
358 NAD Namespaces and extern "C" Yes
359 NAD Type definition in anonymous union Yes
360 open Using-declaration that reduces access Not resolved
361 open Forward reference to default argument Not resolved
362 CD1 Order of initialization in instantiation units N/A
363 NAD Initialization of class from self N/A
364 CD1 Calling overloaded function with static in set, with no object Yes
365 open Storage duration and temporaries Not resolved
366 CD1 String literal allowed in integral constant expression? Yes
367 CD1 throw operator allowed in constant expression? Yes
368 CD1 Uses of non-type parameters that should cause deduction to fail Yes
369 drafting Are new/delete identifiers or preprocessing-op-or-punc? Not resolved
370 CD1 Can #include <...> form be used other than for standard C++ headers? N/A
371 open Interleaving of constructor calls Not resolved
372 CD1 Is access granted by base class specifiers available in following base class specifiers? No
373 C++11 Lookup on namespace qualified name in using-directive Clang 5
374 CD2 Can explicit specialization outside namespace use qualified name? Yes
375 dup Confusing example on lookup with typename Duplicate of 345
376 NAD Class "definition" versus class "declaration" N/A
377 CD1 Enum whose enumerators will not fit in any integral type Yes
378 CD1 Wording that says temporaries are declared Duplicate of 276
379 CD1 Change "class declaration" to "class definition" N/A
380 open Definition of "ambiguous base class" missing Not resolved
381 CD1 Incorrect example of base class member lookup Yes
382 CD1 Allow typename outside of templates Yes (C++11 onwards)
383 CD1 Is a class with a declared but not defined destructor a POD? Yes
384 NAD Argument-dependent lookup and operator functions Yes
385 CD1 How does protected member check of 11.5 interact with using-declarations? Yes
386 drafting Friend declaration of name brought in by using-declaration Not resolved
387 CD1 Errors in example in 14.6.5 Yes
388 CD3 Catching base*& from a throw of derived* Unknown
389 CD1 Unnamed types in entities with linkage No
390 CD1 Pure virtual must be defined when implicitly called Yes
391 CD1 Require direct binding of short-lived references to rvalues Yes (C++11 onwards)
392 CD1 Use of full expression lvalue before temporary destruction Unknown
393 CD4 Pointer to array of unknown bound in template argument list in parameter Unknown
394 CD1 identifier-list is never defined N/A
395 NAD Conversion operator template syntax Yes
396 CD1 Misleading note regarding use of auto for disambiguation Yes
397 CD1 Same address for string literals from default arguments in inline functions? Superseded by 1823
398 CD1 Ambiguous wording on naming a type in deduction Yes
399 drafting Destructor lookup redux Not resolved
400 CD1 Using-declarations and the "struct hack" Yes
401 CD1 When is access for template parameter default arguments checked? Yes
402 open More on partial ordering of function templates Not resolved
403 CD1 Reference to a type as a template-id Yes
404 CD1 Unclear reference to construction with non-trivial constructor N/A
405 open Unqualified function name lookup Not resolved
406 CD1 Static data member in class with name for linkage purposes Yes
407 C++11 Named class with associated typedef: two names or one? Clang 3.8
408 CD2 sizeof applied to unknown-bound array static data member of template Clang 3.4
409 CD1 Obsolete paragraph missed by changes for issue 224 Yes
410 CD1 Paragraph missed in changes for issue 166 No
411 open Use of universal-character-name in character versus string literals Not resolved
412 NAD Can a replacement allocation function be inline? Yes
413 CD1 Definition of "empty class" Yes
414 CD1 Multiple types found on destructor lookup Duplicate of 305
415 CD1 Template deduction does not cause instantiation Yes
416 CD1 Class must be complete to allow operator lookup? Yes
417 CD1 Using derived-class qualified name in out-of-class nested class definition No
418 open Imperfect wording on error on multiple default arguments on a called function Not resolved
419 open Can cast to virtual base class be done on partially-constructed object? Not resolved
420 CD1 postfixexpression->scalar_type_dtor() inconsistent Yes
421 CD1 Is rvalue.field an rvalue? Yes
422 NAD Is a typedef redeclaration allowed with a template type that might be the same? Yes
423 NAD Can a conversion be done on the left operand of a compound assignment? Yes
424 CD1 Wording problem with issue 56 resolution on redeclaring typedefs in class scope Yes
425 CD1 Set of candidates for overloaded built-in operator with float operand Yes
426 C++17 Identically-named variables, one internally and one externally linked, allowed? Unknown
427 CD1 static_cast ambiguity: conversion versus cast to derived Yes
428 CD1 Mention of expression with reference type Yes
429 CD1 Matching deallocation function chosen based on syntax or signature? Yes (C++11 onwards)
430 CD1 Ordering of expression evaluation in initializer list Yes (C++11 onwards)
431 C++11 Defect in wording in 14.2 Yes
432 CD1 Is injected class name visible in base class specifier list? Yes
433 CD1 Do elaborated type specifiers in templates inject into enclosing namespace scope? Yes
434 NAD Unclear suppression of standard conversions while binding reference to lvalue Yes
435 NAD Change "declararation or definition" to "declaration" N/A
436 CD1 Problem in example in 9.6 paragraph 4 Yes
437 CD1 Is type of class allowed in member function exception specification? Superseded by 1308
438 CD2 Possible flaw in wording for multiple accesses to object between sequence points Unknown
439 CD1 Guarantees on casting pointer back to cv-qualified version of original type Unknown
440 open Allow implicit pointer-to-member conversion on nontype template argument Not resolved
441 CD1 Ordering of static reference initialization Unknown
442 CD1 Incorrect use of null pointer constant in description of delete operator Superseded by 348
443 CD1 Wording nit in description of lifetime of temporaries N/A
444 NAD Overriding and the generated copy assignment operator Yes
445 NAD Wording issue on friend declarations Yes
446 CD1 Does an lvalue-to-rvalue conversion on the "?" operator produce a temporary? Yes
447 CD1 Is offsetof type-dependent? Yes
448 C++11 Set of template functions in call with dependent explicit argument Yes
449 NAD Consistency in use of hyphen with names of "non" entities N/A
450 CD1 Binding a reference to const to a cv-qualified array rvalue Yes
451 CD1 Expressions with invalid results and ill-formedness Yes
452 CD1 Wording nit on description of this Yes
453 drafting References may only bind to “valid” objects Not resolved
454 CD1 When is a definition of a static data member required? Unknown
455 drafting Partial ordering and non-deduced arguments Not resolved
456 NAD Is initialized const int or const bool variable a null pointer constant? Yes
457 CD1 Wording nit on use of const variables in constant expressions Yes
458 C++11 Hiding of member template parameters by other members No
459 open Hiding of template parameters by base class members Not resolved
460 CD1 Can a using-declaration name a namespace? Yes
461 NAD Make asm conditionally-supported N/A
462 CD3 Lifetime of temporaries bound to comma expressions Unknown
463 CD1 reinterpret_cast<T*>(0) N/A
464 CD1 Wording nit on lifetime of temporaries to which references are bound N/A
465 NAD May constructors of global objects call exit()? N/A
466 CD1 cv-qualifiers on pseudo-destructor type No
467 NAD Jump past initialization of local static variable Yes
468 CD1 Allow ::template outside of templates Yes (C++11 onwards)
469 NAD Const template specializations and reference arguments No
470 CD1 Instantiation of members of an explicitly-instantiated class template Yes
471 NAD Conflicting inherited access specifications Yes
472 drafting Casting across protected inheritance Not resolved
473 open Block-scope declarations of allocator functions Not resolved
474 CD1 Block-scope extern declarations in namespace members Yes
475 C++11 When is std::uncaught_exception() true? (take 2) Unknown
476 extension Determining the buffer size for placement new Not resolved
477 CD1 Can virtual appear in a friend declaration? Clang 3.5
478 NAD May a function parameter be an array of an abstract class type? Yes
479 CD1 Copy elision in exception handling Yes
480 CD1 Is a base of a virtual base also virtual? Yes
481 CD2 Scope of template parameters Yes
482 CD3 Qualified declarators in redeclarations Clang 3.5
483 CD3 Normative requirements on integral ranges Yes
484 CD1 Can a base-specifier name a cv-qualified class type? Yes
485 CD1 What is a “name”? Yes
486 CD1 Invalid return types and template argument deduction Yes
487 NAD Operator overloading in constant expressions Yes
488 CD1 Local types, overload resolution, and template argument deduction Yes (C++11 onwards)
489 NAD Must member function templates be instantiated during overload resolution? N/A
490 CD2 Name lookup in friend declarations Yes
491 CD1 Initializers for empty-class aggregrate members Duplicate of 413
492 CD1 typeid constness inconsistent with example Unknown
493 CD2 Type deduction from a bool context Duplicate of 976
494 CD1 Problems with the resolution of issue 45 Duplicate of 372
495 CD2 Overload resolution with template and non-template conversion functions Clang 3.5
496 CD3 Is a volatile-qualified type really a POD? Superseded by 2094
497 CD1 Missing required initialization in example Superseded by 253
498 open Storage class specifiers in definitions of class members Not resolved
499 CD2 Throwing an array of unknown size Yes
500 CD1 Access in base-specifiers of friend and nested classes Duplicate of 372
501 NAD Visibility of friend declarations within the befriending class Yes
502 C++11 Dependency of nested enumerations and enumerators Yes
503 open Cv-qualified function types in template argument deduction Not resolved
504 open Should use of a variable in its own initializer require a diagnostic? Not resolved
505 CD1 Conditionally-supported behavior for unknown character escapes Yes
506 CD1 Conditionally-supported behavior for non-POD objects passed to ellipsis Yes
507 dup Ambiguity assigning class object to built-in type Duplicate of 260
508 C++11 Non-constructed value-initialized objects N/A
509 CD1 Dead code in the specification of default initialization N/A
510 CD1 Default initialization of POD classes? N/A
511 open POD-structs with template assignment operators Not resolved
512 NAD Union members with user-declared non-default constructors Yes
513 CD1 Non-class “most-derived” objects N/A
514 CD1 Is the initializer for a namespace member in the scope of the namespace? Yes
515 CD1 Non-dependent references to base class members Superseded by 1017
516 CD1 Use of signed in bit-field declarations N/A
517 CD1 Partial specialization following explicit instantiation No
518 CD1 Trailing comma following enumerator-list Yes (C++11 onwards)
519 CD1 Null pointer preservation in void* conversions Yes
520 CD1 Old-style casts between incomplete class types N/A
521 CD1 Requirements for exceptions thrown by allocation functions No
522 CD1 Array-to-pointer decay in template argument deduction Yes
523 open Can a one-past-the-end pointer be invalidated by deleting an adjacent object? Not resolved
524 CD1 Can function-notation calls to operator functions be dependent? Yes
525 CD1 Missing * in example Yes
526 CD1 Confusing aspects in the specification of non-deduced contexts Yes
527 CD2 Problems with linkage of types N/A
528 open Why are incomplete class types not allowed with typeid? Not resolved
529 drafting Use of template<> with “explicitly-specialized” class templates Not resolved
530 CD1 Nontype template arguments in constant expressions Yes
531 C++11 Defining members of explicit specializations Partial
532 C++11 Member/nonmember operator template partial ordering Clang 3.5
533 NAD Special treatment for C-style header names N/A
534 CD1 template-names and operator-function-ids Yes
535 CD3 Copy construction without a copy constructor Yes
536 drafting Problems in the description of id-expressions Not resolved
537 CD1 Definition of “signature” N/A
538 CD1 Definition and usage of structure, POD-struct, POD-union, and POD class N/A
539 CD3 Constraints on type-specifier-seq Yes
540 CD1 Propagation of cv-qualifiers in reference-to-reference collapse Yes
541 CD2 Dependent function types Yes
542 CD2 Value initialization of arrays of POD-structs Yes
543 CD1 Value initialization and default constructors Yes
544 NAD Base class lookup in explicit specialization Yes
545 open User-defined conversions and built-in operator overload resolution Not resolved
546 C++11 Explicit instantiation of class template members Yes
547 C++11 Partial specialization on member function types Yes
548 dup qualified-ids in declarations Duplicate of 482
549 drafting Non-deducible parameters in partial specializations Not resolved
550 dup Pointer to array of unknown bound in parameter declarations Unknown
551 CD1 When is inline permitted in an explicit instantiation? Yes (C++11 onwards)
552 NAD Use of typename in the type in a non-type parameter-declaration Yes
553 NAD Problems with friend allocation and deallocation functions Unknown
554 drafting Definition of “declarative region” and “scope” Not resolved
555 drafting Pseudo-destructor name lookup Not resolved
556 CD2 Conflicting requirements for acceptable aliasing N/A
557 CD1 Does argument-dependent lookup cause template instantiation? Yes
558 CD1 Excluded characters in universal character names Yes
559 CD1 Editing error in issue 382 resolution Yes
560 drafting Use of the typename keyword in return types Not resolved
561 CD2 Internal linkage functions in dependent name lookup Yes
562 open qualified-ids in non-expression contexts Not resolved
563 open Linkage specification for objects Not resolved
564 CD2 Agreement of language linkage or linkage-specifications? Yes
565 CD3 Conflict rules for using-declarations naming function templates Yes
566 NAD Conversion of negative floating point values to integer type Yes
567 NAD Can size_t and ptrdiff_t be larger than long? N/A
568 CD1 Definition of POD is too strict Yes (C++11 onwards)
569 CD2 Spurious semicolons at namespace scope should be allowed Yes (C++11 onwards)
570 CD2 Are references subject to the ODR? Duplicate of 633
571 CD2 References declared const Unknown
572 C++11 Standard conversions for non-built-in types Yes
573 C++11 Conversions between function pointers and void* No
574 NAD Definition of “copy assignment operator” Yes
575 C++11 Criteria for deduction failure Yes
576 CD2 Typedefs in function definitions Yes
577 CD3 void in an empty parameter list Yes
578 open Phase 1 replacement of characters with universal-character-names Not resolved
579 open What is a “nested” > or >>? Not resolved
580 C++11 Access in template-parameters of member and friend definitions Partial
581 open Can a templated constructor be explicitly instantiated or specialized? Not resolved
582 CD1 Template conversion functions N/A
583 CD3 Relational pointer comparisons against the null pointer constant Clang 4
584 NAD Unions and aliasing N/A
585 NAD Friend template template parameters Yes
586 NAD Default template-arguments and template argument deduction N/A
587 CD2 Lvalue operands of a conditional expression differing only in cv-qualification Yes
588 CD2 Searching dependent bases of classes local to function templates Yes
589 CD2 Direct binding of class and array rvalues in reference initialization Yes
590 C++11 Nested classes and the “current instantiation” Yes
591 CD4 When a dependent base class is the current instantiation No
592 CD1 Exceptions during construction of local static objects N/A
593 NAD Falling off the end of a destructor's function-try-block handler Unknown
594 CD1 Coordinating issues 119 and 404 with delegating constructors N/A
595 dup Exception specifications in templates instantiated from class bodies Duplicate of 1330
596 NAD Replacing an exception object Unknown
597 CD3 Conversions applied to out-of-lifetime non-POD lvalues N/A
598 CD2 Associated namespaces of overloaded functions and function templates Yes
599 CD2 Deleting a null function pointer Partial
600 open Does access control apply to members or to names? Not resolved
601 CD2 Type of literals in preprocessing expressions Yes
602 C++11 When is the injected-class-name of a class template a template? Yes
603 CD1 Type equivalence and unsigned overflow Yes
604 CD2 Argument list for overload resolution in copy-initialization N/A
605 C++11 Linkage of explicit specializations Unknown
606 CD1 Template argument deduction for rvalue references Yes
607 open Lookup of mem-initializer-ids Not resolved
608 CD2 Determining the final overrider of a virtual function Yes
609 CD4 What is a “top-level” cv-qualifier? Unknown
610 NAD Computing the negative of 0U Yes
611 CD2 Zero-initializing references Yes
612 CD2 Requirements on a conforming implementation N/A
613 CD1 Unevaluated uses of non-static class members Yes (C++11 onwards)
614 CD1 Results of integer / and % Yes
615 C++11 Incorrect description of variables that can be initialized Yes
616 CD3 Definition of “indeterminate value” Clang 4
617 drafting Lvalue-to-rvalue conversions of uninitialized char objects Not resolved
618 CD2 Casts in preprocessor conditional expressions Yes
619 C++11 Completeness of array types Yes
620 CD1 Declaration order in layout-compatible POD structs Duplicate of 568
621 C++11 Template argument deduction from function return types Unknown
622 NAD Relational comparisons of arbitrary pointers Unknown
623 CD3 Use of pointers to deallocated storage N/A
624 CD1 Overflow in calculating size of allocation Unknown
625 CD2 Use of auto as a template-argument Yes
626 CD2 Preprocessor string literals Yes
627 NAD Values behaving as types Yes
628 CD2 The values of an enumeration with no enumerator N/A
629 CD1 auto parsing ambiguity Yes
630 CD2 Equality of narrow and wide character values in the basic character set Yes
631 CD3 Jumping into a “then” clause N/A
632 CD1 Brace-enclosed initializer for scalar member of aggregate Yes
633 CD2 Specifications for variables that should also apply to references N/A
634 CD1 Conditionally-supported behavior for non-POD objects passed to ellipsis redux Yes
635 NAD Names of constructors and destructors of templates Yes
636 CD4 Dynamic type of objects and aliasing Unknown
637 CD1 Sequencing rules and example disagree Yes
638 CD2 Explicit specialization and friendship No
639 CD1 What makes side effects “different” from one another? Yes
640 open Accessing destroyed local objects of static storage duration Not resolved
641 CD2 Overload resolution and conversion-to-same-type operators Yes
642 CD2 Definition and use of “block scope” and “local scope” Yes
643 NAD Use of decltype in a class member-specification Yes
644 CD1 Should a trivial class type be a literal type? Partial
645 CD2 Are bit-field and non-bit-field members layout compatible? N/A
646 NAD Can a class with a constexpr copy constructor be a literal type? Superseded by 981
647 CD1 Non-constexpr instances of constexpr constructor templates Yes
648 CD1 Constant expressions in constexpr initializers Yes
649 CD1 Optionally ill-formed extended alignment requests Yes
650 CD2 Order of destruction for temporaries bound to the returned value of a function Unknown
651 CD1 Problems in decltype specification and examples Yes
652 CD2 Compile-time evaluation of floating-point expressions Yes
653 CD2 Copy assignment of unions Unknown
654 CD1 Conversions to and from nullptr_t Yes
655 C++11 Initialization not specified for forwarding constructors Yes
656 CD2 Direct binding to the result of a conversion operator Yes
657 CD2 Abstract class parameter in synthesized declaration Partial
658 CD2 Defining reinterpret_cast for pointer types Unknown
659 CD1 Alignment of function types Yes
660 CD1 Unnamed scoped enumerations Yes
661 CD1 Semantics of arithmetic comparisons Unknown
662 NAD Forming a pointer to a reference type Yes
663 CD1 Valid Cyrillic identifier characters Yes (C++11 onwards)
664 CD2 Direct binding of references to non-class rvalue references Yes
665 CD2 Problems in the specification of dynamic_cast Yes
666 CD1 Dependent qualified-ids without the typename keyword Yes
667 CD2 Trivial special member functions that cannot be implicitly defined Yes
668 CD2 Throwing an exception from the destructor of a local static object Unknown
669 NAD Confusing specification of the meaning of decltype Yes
670 open Copy initialization via derived-to-base conversion in the second step Not resolved
671 CD1 Explicit conversion from a scoped enumeration type to integral type Yes
672 CD2 Sequencing of initialization in new-expressions Unknown
673 NAD Injection of names from elaborated-type-specifiers in friend declarations Yes
674 C++11 “matching specialization” for a friend declaration No
675 CD3 Signedness of bit-field with typedef or template parameter type Duplicate of 739
676 C++11 static_assert-declarations and general requirements for declarations N/A
677 CD1 Deleted operator delete and virtual destructors No
678 C++11 Language linkage of member function parameter types and the ODR Unknown
679 CD1 Equivalence of template-ids and operator function templates Yes
680 CD2 What is a move constructor? N/A
681 CD1 Restrictions on declarators with late-specified return types Partial
682 drafting Missing description of lookup of template aliases Not resolved
683 CD1 Requirements for trivial subobject special functions Yes
684 CD1 Constant expressions involving the address of an automatic variable Superseded by 1454
685 CD2 Integral promotion of enumeration ignores fixed underlying type Yes
686 CD1 Type declarations/definitions in type-specifier-seqs and type-ids Yes
687 extension template keyword with unqualified-ids Not resolved
688 CD1 Constexpr constructors and static initialization Unknown
689 open Maximum values of signed and unsigned integers Not resolved
690 CD2 The dynamic type of an rvalue reference Unknown
691 C++11 Template parameter packs in class template partial specializations Unknown
692 C++11 Partial ordering of variadic class template partial specializations No
693 CD2 New string types and deprecated conversion Unknown
694 C++11 Zero- and value-initialization of union objects Unknown
695 CD2 Compile-time calculation errors in constexpr functions Unknown
696 C++11 Use of block-scope constants in local classes Unknown
697 open Deduction rules apply to more than functions Not resolved
698 open The definition of “sequenced before” is too narrow Not resolved
699 CD2 Must constexpr member functions be defined in the class member-specification? Unknown
700 C++11 Constexpr member functions of class templates Unknown
701 CD2 When is the array-to-pointer conversion applied? Unknown
702 CD2 Preferring conversion to std::initializer_list Unknown
703 CD2 Narrowing for literals that cannot be exactly represented Unknown
704 CD2 To which postfix-expressions does overload resolution apply? Unknown
705 CD2 Suppressing argument-dependent lookup via parentheses Unknown
706 NAD Use of auto with rvalue references Unknown
707 CD2 Undefined behavior in integral-to-floating conversions Unknown
708 open Partial specialization of member templates of class templates Not resolved
709 C++11 Enumeration names as nested-name-specifiers in deduction failure Unknown
710 CD2 Data races during construction Unknown
711 CD2 auto with braced-init-list Unknown
712 CD3 Are integer constant operands of a conditional-expression “used?” Unknown
713 CD2 Unclear note about cv-qualified function types Unknown
714 CD2 Static const data members and braced-init-lists Unknown
715 CD2 Class member access constant expressions Unknown
716 CD2 Specifications that should apply only to non-static union data members Unknown
717 CD2 Unintentional restrictions on the use of thread_local Unknown
718 open Non-class, non-function friend declarations Not resolved
719 CD2 Specifications for operator-function-id that should also apply to literal-operator-id Unknown
720 CD2 Need examples of lambda-expressions Unknown
721 CD2 Where must a variable be initialized to be used in a constant expression? Unknown
722 CD2 Can nullptr be passed to an ellipsis? Unknown
726 CD2 Atomic and non-atomic objects in the memory model Unknown
727 C++17 In-class explicit specializations Partial
728 extension Restrictions on local classes Not resolved
729 CD3 Qualification conversions and handlers of reference-to-pointer type Unknown
730 CD2 Explicit specializations of members of non-template classes Unknown
731 CD2 Omitted reference qualification of member function type Unknown
732 CD2 Late-specified return types in function definitions Unknown
733 NAD Reference qualification of copy assignment operators Unknown
734 CD2 Are unique addresses required for namespace-scope variables? Unknown
735 CD2 Missing case in specification of safely-derived pointers Unknown
736 NAD Is the & ref-qualifier needed? Unknown
737 CD2 Uninitialized trailing characters in string initialization Unknown
738 C++11 constexpr not permitted by the syntax of constructor declarations Unknown
739 CD3 Signedness of plain bit-fields Unknown
740 CD2 Incorrect note on data races Unknown
741 C++11 “plain” long long bit-fields Unknown
742 open Postfix increment/decrement with long bit-field operands Not resolved
743 CD2 Use of decltype in a nested-name-specifier Unknown
744 CD2 Matching template arguments with template template parameters with parameter packs Unknown
745 open Effect of ill-formedness resulting from #error Not resolved
746 CD2 Use of auto in new-expressions Unknown
747 dup Access of protected base classes Unknown
749 CD2 References to function types with a cv-qualifier or ref-qualifier Unknown
750 CD2 Implementation constraints on reference-only closure objects Unknown
751 CD2 Deriving from closure classes Unknown
752 CD2 Name lookup in nested lambda-expressions Unknown
753 CD2 Array names in lambda capture sets Unknown
754 CD2 Lambda expressions in default arguments of block-scope function declarations Unknown
755 CD3 Generalized lambda-captures Unknown
756 CD2 Dropping cv-qualification on members of closure objects Unknown
757 CD2 Types without linkage in declarations Unknown
758 C++11 Missing cases of declarations that are not definitions Unknown
759 CD2 Destruction of closure objects Unknown
760 CD2 this inside a nested class of a non-static member function Unknown
761 CD2 Inferred return type of closure object call operator Unknown
762 CD2 Name lookup in the compound-statement of a lambda expression Unknown
763 CD2 Is a closure object's operator() inline? Unknown
764 CD2 Capturing unused variables in a lambda expression Unknown
765 CD2 Local types in inline functions with external linkage Unknown
766 CD2 Where may lambda expressions appear? Unknown
767 CD2 void and other unnamed lambda-parameters Unknown
768 CD2 Ellipsis in a lambda parameter list Unknown
769 CD2 Initialization of closure objects Unknown
770 CD2 Ambiguity in late-specified return type Unknown
771 CD2 Move-construction of reference members of closure objects Unknown
772 CD2 capture-default in lambdas in local default arguments Unknown
773 C++11 Parentheses in address non-type template arguments Unknown
774 CD2 Can a closure class be a POD? Unknown
775 CD2 Capturing references to functions Unknown
776 CD2 Delegating constructors, destructors, and std::exit Unknown
777 CD2 Default arguments and parameter packs Clang 3.7
778 C++11 Template parameter packs in non-type template parameters Unknown
779 CD2 Rvalue reference members of closure objects? Unknown
782 CD2 Lambda expressions and argument-dependent lookup Unknown
783 open Definition of “argument” Not resolved
784 C++11 List of incompatibilities with the previous Standard Unknown
785 CD2 “Execution sequence” is inappropriate phraseology Unknown
786 CD2 Definition of “thread” Unknown
787 CD2 Unnecessary lexical undefined behavior Unknown
788 CD2 Relationship between locale and values of the execution character set Unknown
789 CD2 Deprecating trigraphs Unknown
790 CD2 Concatenation of raw and non-raw string literals Unknown
792 CD2 Effects of std::quick_exit Unknown
793 CD2 Use of class members during destruction Unknown
794 extension Base-derived conversion in member type of pointer-to-member conversion Not resolved
795 NAD Dependency of lambdas on <functional> Unknown
796 CD2 Lifetime of a closure object with members captured by reference Unknown
797 CD2 Converting a no-capture lambda to a function type Unknown
798 C++11 Overloaded subscript operator described in clause 5 Unknown
799 CD2 Can reinterpret_cast be used to cast an operand to its own type? Unknown
800 NAD Safely-derived pointers and object pointers converted from function pointers Unknown
801 CD2 Casting away constness in a cast to rvalue reference type Unknown
803 CD2 sizeof an enumeration type with a fixed underlying type Unknown
804 CD2 Deducing the type in new auto(x) Unknown
805 CD2 Which exception to throw for overflow in array size calculation Unknown
806 CD2 Enumeration types in integral constant expressions Unknown
807 NAD typeid expressions in constant expressions Unknown
808 CD2 Non-type decl-specifiers versus max-munch Unknown
809 CD2 Deprecation of the register keyword Unknown
810 CD2 Block-scope thread_local variables should be implicitly static Unknown
811 CD2 Unclear implications of const-qualification Unknown
812 CD2 Duplicate names in inline namespaces Unknown
813 open typename in a using-declaration with a non-dependent name Not resolved
814 CD2 Attribute to indicate that a function throws nothing Unknown
815 CD2 Parameter pack expansion inside attributes Unknown
816 CD2 Diagnosing violations of [[final]] Unknown
817 CD2 Meaning of [[final]] applied to a class definition Unknown
818 CD2 Function parameter packs in non-final positions Unknown
819 NAD Access control and deleted implicitly-declared special member functions Unknown
820 CD2 Deprecation of export Unknown
822 NAD Additional contexts for template aliases Unknown
823 CD2 Literal types with constexpr conversions as non-type template arguments Unknown
828 CD2 Destruction of exception objects Unknown
829 NAD At what point is std::unexpected called? Unknown
830 CD2 Deprecating exception specifications Unknown
831 CD2 Limit on recursively nested template instantiations Unknown
832 CD2 Value of preprocessing numbers Unknown
833 CD2 Explicit conversion of a scoped enumeration value to a floating type Unknown
834 CD2 What is an “ordinary string literal”? Unknown
835 CD2 Scoped enumerations and the “usual arithmetic conversions” Unknown
836 NAD [[noreturn]] applied to function types Unknown
837 C++11 Constexpr functions and return braced-init-list Unknown
838 C++11 Use of this in a brace-or-equal-initializer Unknown
839 dup sizeof with opaque enumerations Unknown
840 CD2 Rvalue references as nontype template parameters Unknown
842 CD2 Casting to rvalue reference type Unknown
845 CD2 What is the “first declaration” of an explicit specialization? Unknown
846 CD2 Rvalue references to functions Unknown
847 CD2 Error in rvalue reference deduction example Unknown
850 CD2 Restrictions on use of non-static data members Unknown
852 open using-declarations and dependent base classes Not resolved
853 CD2 Support for relaxed pointer safety Unknown
854 CD2 Left shift and unsigned extended types Unknown
855 CD2 Incorrect comments in braced-init-list assignment example Unknown
858 CD2 Example binding an rvalue reference to an lvalue Unknown
860 C++11 Explicit qualification of constexpr member functions Unknown
861 CD2 Unintended ambiguity in inline namespace lookup Unknown
862 CD2 Undefined behavior with enumerator value overflow Unknown
863 CD2 Rvalue reference cast to incomplete type Unknown
864 C++11 braced-init-list in the range-based for statement Unknown
865 CD2 Initializing a std::initializer_list Unknown
869 CD2 Uninitialized thread_local objects Unknown
872 CD2 Lexical issues with raw strings Unknown
873 C++11 Deducing rvalue references in declarative contexts Unknown
874 CD2 Class-scope definitions of enumeration types Unknown
876 CD2 Type references in rvalue reference deduction specification Unknown
877 CD2 Viable functions and binding references to rvalues Unknown
879 CD2 Missing built-in comparison operators for pointer types Unknown
880 CD2 Built-in conditional operator for scoped enumerations Unknown
882 CD2 Defining main as deleted Unknown
883 CD2 std::memcpy vs std::memmove Unknown
884 CD2 Defining an explicitly-specialized static data member Unknown
885 NAD Partial ordering of function templates with unordered parameter pairs Unknown
886 CD2 Member initializers and aggregates Unknown
887 CD2 Move construction of thrown object Unknown
888 CD2 Union member initializers Unknown
891 CD2 const_cast to rvalue reference from objectless rvalue Unknown
892 C++11 Missing requirements for constexpr constructors Unknown
893 NAD Brace syntax for enumerator-definitions Unknown
896 CD2 Rvalue references and rvalue-reference conversion functions Unknown
897 open _Pragma and extended string-literals Not resolved
898 C++11 Declarations in constexpr functions Unknown
899 CD2 Explicit conversion functions in direct class initialization Unknown
900 extension Lifetime of temporaries in range-based for Not resolved
901 drafting Deleted operator delete Not resolved
902 NAD In-class initialization of non-constant static data members Unknown
903 CD3 Value-dependent integral null pointer constants Unknown
904 CD2 Parameter packs in lambda-captures Unknown
905 CD2 Explicit defaulted copy constructors and trivial copyability Unknown
906 CD2 Which special member functions can be defaulted? Unknown
908 CD2 Deleted global allocation and deallocation functions Unknown
909 NAD Old-style casts with conversion functions Unknown
910 CD2 Move constructors and implicitly-declared copy constructors Unknown
912 CD3 Character literals and universal-character-names Unknown
913 CD2 Deduction rules for array- and function-type conversion functions Unknown
914 extension Value-initialization of array types Not resolved
915 CD2 Deleted specializations of member function templates Unknown
916 open Does a reference type have a destructor? Not resolved
919 CD2 Contradictions regarding inline namespaces Unknown
920 CD2 Interaction of inline namespaces and using-declarations Unknown
921 CD2 Unclear specification of inline namespaces Unknown
922 CD2 Implicit default constructor definitions and const variant members Unknown
923 CD2 Inline explicit specializations Unknown
924 C++11 alias-declaration as a class member Unknown
925 open Type of character literals in preprocessor expressions Not resolved
926 CD2 Inline unnamed namespaces Unknown
927 CD2 Implicitly-deleted default constructors and member initializers Unknown
928 CD2 Defaulting a function that would be implicitly defined as deleted Unknown
929 CD2 What is a template alias? Unknown
930 CD2 alignof with incomplete array type Unknown
931 CD2 Confusing reference to the length of a user-defined string literal Unknown
932 CD2 UCNs in closing delimiters of raw string literals Unknown
933 CD2 32-bit UCNs with 16-bit wchar_t Unknown
934 CD2 List-initialization of references Unknown
935 CD2 Missing overloads for character types for user-defined literals Unknown
936 CD2 Array initialization with new string literals Unknown
937 NAD Restrictions on values of template arguments in user-defined literals Unknown
938 C++11 Initializer lists and array new Unknown
939 CD2 Explicitly checking virtual function overriding Unknown
940 CD2 Global anonymous unions Unknown
941 C++11 Explicit specialization of deleted function template Unknown
942 CD2 Is this an entity? Unknown
943 DRWP Is T() a temporary? Unknown
944 extension reinterpret_cast for all types with the same size and alignment Not resolved
945 C++11 Use of this in a late-specified return type Unknown
946 CD2 Order of destruction of local static objects and calls to std::atexit Unknown
947 NAD Deducing type template arguments from default function arguments Unknown
948 C++11 constexpr in conditions Clang 3.7
949 open Requirements for freestanding implementations Not resolved
950 CD2 Use of decltype as a class-name Unknown
951 CD2 Problems with attribute-specifiers Unknown
952 drafting Insufficient description of “naming class” Not resolved
953 CD2 Rvalue references and function viability Unknown
954 open Overload resolution of conversion operator templates with built-in types Not resolved
955 CD2 Can a closure type's operator() be virtual? Unknown
956 CD2 Function prototype scope with late-specified return types Unknown
957 CD2 Alternative tokens and attribute-tokens Unknown
958 NAD Lambdas and decltype Unknown
959 CD2 Alignment attribute for class and enumeration types Unknown
960 CD2 Covariant functions and lvalue/rvalue references Unknown
961 CD2 Overload resolution and conversion of std::nullptr_t to bool Unknown
962 CD2 Attributes appertaining to class and enum types Unknown
963 CD2 Comparing nullptr with 0 Unknown
964 C++11 Incorrect description of when the lvalue-to-rvalue conversion applies Unknown
965 CD2 Limiting the applicability of the carries_dependency attribute Unknown
966 CD2 Nested types without linkage Unknown
967 NAD Exception specification of replacement allocation function Unknown
968 CD2 Syntactic ambiguity of the attribute notation Unknown
969 CD2 Explicit instantiation declarations of class template specializations Unknown
970 CD2 Consistent use of “appertain” and “apply” Unknown
971 C++11 Incorrect treatment of exception-declarations Unknown
972 C++11 Allowing multiple attribute-specifiers Unknown
973 CD2 Function types in exception-specifications Unknown
974 CD3 Default arguments for lambdas Unknown
975 CD3 Restrictions on return type deduction for lambdas Unknown
976 CD2 Deduction for const T& conversion operators Unknown
977 CD3 When is an enumeration type complete? Unknown
978 CD2 Incorrect specification for copy initialization Unknown
979 CD2 Position of attribute-specifier in declarator syntax Unknown
980 CD2 Explicit instantiation of a member of a class template Unknown
981 C++11 Constexpr constructor templates and literal types Unknown
982 NAD Initialization with an empty initializer list Unknown
983 CD2 Ambiguous pointer-to-member constant Unknown
984 CD2 “Deduced type” is unclear in auto type deduction Unknown
985 C++11 Alternative tokens and user-defined literals Unknown
986 CD2 Transitivity of using-directives versus qualified lookup Unknown
987 CD4 Which declarations introduce namespace members? Unknown
988 CD2 Reference-to-reference collapsing with decltype Unknown
989 CD2 Misplaced list-initialization example Unknown
990 CD2 Value initialization with multiple initializer-list constructors Clang 3.5
991 CD2 Reference parameters of constexpr functions and constructors Unknown
992 NAD Inheriting explicitness Unknown
993 C++11 Freedom to perform instantiation at the end of the translation unit Unknown
994 C++11 braced-init-list as a default argument Unknown
995 CD2 Incorrect example for using-declaration and explicit instantiation Unknown
996 C++11 Ambiguous partial specializations of member class templates Unknown
997 C++11 Argument-dependent lookup and dependent function template parameter types Unknown
998 dup Function parameter transformations and template functions Unknown
999 CD2 “Implicit” or “implied” object argument/parameter? Unknown
1000 CD2 Mistaking member typedefs for constructors Unknown
1001 drafting Parameter type adjustment in dependent parameter types Not resolved
1002 NAD Pack expansion for function arguments Unknown
1003 CD3 Acceptable definitions of main Unknown
1004 C++11 Injected-class-names as arguments for template template parameters Clang 5
1005 NAD Qualified name resolution in member functions of class templates Unknown
1006 C++11 std::nullptr_t as a non-type template parameter Unknown
1007 NAD Protected access and pointers to members Unknown
1008 extension Querying the alignment of an object Not resolved
1009 C++11 Missing cases in the declarator-id of a function template declaration Unknown
1010 CD2 Address of object with dynamic storage duration in constant expression Unknown
1011 C++11 Standard conversions that cannot be inverted Unknown
1012 C++11 Undeprecating static Unknown
1013 CD3 Uninitialized std::nullptr_t objects Unknown
1014 NAD Overload resolution between const T& and T&& Unknown
1015 C++11 Template arguments and argument-dependent lookup Unknown
1016 C++11 Overloadable declarations, function templates, and references Unknown
1017 C++11 Member access transformation in unevaluated operands Unknown
1018 C++11 Ambiguity between simple-declaration and attribute-declaration Unknown
1019 dup Dependent simple-template-ids in base-specifiers and mem-initializers Unknown
1020 C++11 Implicitly-defined copy constructors and explicit base class constructors Unknown
1021 CD4 Definitions of namespace members Unknown
1022 C++11 Can an enumeration variable have values outside the values of the enumeration? Unknown
1023 dup thread_local objects as non-type template arguments Unknown
1024 CD3 Limits on multicharacter literals Unknown
1025 C++11 Use of a reference as a non-type template argument Unknown
1026 NAD Cv-qualified non-class rvalues Unknown
1027 drafting Type consistency and reallocation of scalar types Not resolved
1028 open Dependent names in non-defining declarations Not resolved
1029 C++11 Type of a destructor call Unknown
1030 C++11 Evaluation order in initializer-lists used in aggregate initialization Unknown
1031 C++11 Optional elements in attributes Unknown
1032 C++11 Empty pack expansions Unknown
1033 C++11 Restrictions on alignment attributes Unknown
1034 C++11 Attributes for return statements in lambdas Unknown
1035 C++11 Omitted and required decl-specifiers Unknown
1036 C++11 Alignment attribute in an exception-declaration Unknown
1037 C++11 Requirements for operands of delete-expressions and deallocation functions Unknown
1038 open Overload resolution of &x.static_func Not resolved
1039 dup Coordinating C and C++ alignment specifications Unknown
1040 NAD Memory model issues Unknown
1041 dup alias-declarations as class members Unknown
1042 C++11 Attributes in alias-declarations Unknown
1043 C++11 Qualified name lookup in the current instantiation Unknown
1044 C++11 Point of declaration for an alias-declaration Unknown
1045 NAD Requiring explicit instantiation declarations Unknown
1046 open What is a “use” of a class specialization? Not resolved
1047 C++11 When is typeid value-dependent? Unknown
1048 CD3 auto deduction and lambda return type deduction. Clang 3.6
1049 open Copy elision through reference parameters of inline functions Not resolved
1050 NAD Effects of thread support on object lifetime Unknown
1051 C++11 Reference members and generated copy constructors Unknown
1052 dup const non-static data member and PODness Unknown
1053 NAD Terminate vs undefined behavior for noexcept violation Unknown
1054 C++11 Lvalue-to-rvalue conversions in expression statements No
1055 C++11 Permissible uses of void Unknown
1056 C++11 Template aliases, member definitions, and the current instantiation Unknown
1057 C++11 decltype and the current instantiation Unknown
1058 NAD Reference binding of incompatible array types Unknown
1059 CD3 Cv-qualified array types (with rvalues) Unknown
1060 C++11 Scoped enumerators in integral constant expressions Unknown
1061 C++11 Negative array bounds in a new-expression Unknown
1062 C++11 Syntax of attribute-specifiers in lambdas Unknown
1063 C++11 [[hiding]] with non-attribute declarations Unknown
1064 C++11 Defaulted move constructor for a union Unknown
1065 C++11 [[hiding]] with [[override]] Unknown
1066 C++11 When is a copy/move assignment operator implicitly defined? Unknown
1067 NAD [[hiding]], using-declarations, and multiple inheritance Unknown
1068 C++11 Template aliases with default arguments and template parameter packs Unknown
1069 C++11 Incorrect function type with trailing-return-type Unknown
1070 C++11 Missing initializer clauses in aggregate initialization Clang 3.5
1071 C++11 Literal class types and trivial default constructors Unknown
1072 C++11 Scoped enumerator with the same name as its containing class Unknown
1073 C++11 Merging dynamic-exception-specifications and noexcept-specifications Unknown
1074 C++11 Value-dependent noexcept-expressions Unknown
1075 C++11 Grammar does not allow template alias in type-name Unknown
1076 DRWP Value categories and lvalue temporaries Unknown
1077 extension Explicit specializations in non-containing namespaces Not resolved
1078 NAD Narrowing and the usual arithmetic conversions Unknown
1079 C++11 Overload resolution involving aggregate initialization Unknown
1080 C++11 Confusing relationship between templates and copy constructors Unknown
1081 C++11 Defaulted destructor and unusable operator delete Unknown
1082 C++11 Implicit copy function if subobject has none? Unknown
1083 C++11 Passing an object to ellipsis with non-trivial move constructor Unknown
1084 NAD Conditions for a deleted move function Unknown
1085 NAD Move assignment operators and virtual bases Unknown
1086 C++11 const_cast to rvalue reference to function type Unknown
1087 C++11 Additional applications of issue 899 Unknown
1088 C++11 Dependent non-type template arguments Unknown
1089 drafting Template parameters in member selections Not resolved
1090 C++11 Alignment of subobjects Unknown
1091 C++11 Inconsistent use of the term “object expression” Unknown
1092 drafting Cycles in overload resolution during instantiation Not resolved
1093 CD3 Value-initializing non-objects Unknown
1094 C++11 Converting floating-point values to scoped enumeration types Unknown
1095 C++11 List-initialization of references Unknown
1096 C++11 Missing requirement for template definitions Unknown
1097 NAD Aggregate initialization of function parameters Unknown
1098 C++11 Pointer conversions in constant expressions Unknown
1099 C++11 Infinite recursion in constexpr functions Unknown
1100 C++11 constexpr conversion functions and non-type template arguments Unknown
1101 C++11 Non-integral initialized static data members Unknown
1102 C++11 Better example of undefined behavior Unknown
1103 C++11 Reversion of phase 1 and 2 transformations in raw string literals Unknown
1104 C++11 Global-scope template arguments vs the <: digraph Unknown
1105 C++11 Issues relating to TR 10176:2003 Unknown
1106 C++11 Need more detail in nullptr keyword description Unknown
1107 C++11 Overload resolution for user-defined integer literals Unknown
1108 NAD User-defined literals have not been implemented Unknown
1109 C++11 When is “use” a reference to the ODR meaning? Unknown
1110 NAD Incomplete return type should be allowed in decltype operand Unknown
1111 C++11 Remove dual-scope lookup of member template names Unknown
1112 C++11 constexpr variables should have internal linkage like const Unknown
1113 C++11 Linkage of namespace member of unnamed namespace Partial
1114 C++11 Incorrect use of placement new in example Unknown
1115 C++11 C-compatible alignment specification Unknown
1116 CD4 Aliasing of union members Unknown
1117 C++11 Incorrect note about xvalue member access expressions Unknown
1118 NAD Implicit lambda capture via explicit copy constructor Unknown
1119 C++11 Missing case in description of member access ambiguity Unknown
1120 C++11 reinterpret_cast and void* Unknown
1121 C++11 Unnecessary ambiguity error in formation of pointer to member Unknown
1122 C++11 Circular definition of std::size_t Unknown
1123 C++11 Destructors should be noexcept by default Unknown
1124 NAD Error in description of value category of pointer-to-member expression Unknown
1125 C++11 Unclear definition of “potential constant expression” Unknown
1126 C++11 constexpr functions in const initializers Unknown
1127 C++11 Overload resolution in constexpr functions Unknown
1128 C++11 attribute-specifiers in decl-specifier-seqs Unknown
1129 C++11 Default nothrow for constexpr functions Unknown
1130 C++11 Function parameter type adjustments and decltype Unknown
1131 C++11 Template aliases in elaborated-type-specifiers Unknown
1132 NAD Keyword vs attribute for noreturn Unknown
1133 C++11 Keywords vs attributes for control of hiding and overriding Unknown
1134 C++11 When is an explicitly-defaulted function defined? Unknown
1135 C++11 Explicitly-defaulted non-public special member functions Unknown
1136 C++11 Explicitly-defaulted explicit constructors Unknown
1137 C++11 Explicitly-defaulted virtual special member functions Unknown
1138 C++11 Rvalue-ness check for rvalue reference binding is wrong Unknown
1139 C++11 Rvalue reference binding to scalar xvalues Unknown
1140 C++11 Incorrect redefinition of POD class Unknown
1141 NAD Non-static data member initializers have not been implemented Unknown
1142 C++11 friend declaration of member function of containing class Unknown
1143 NAD Move semantics for *this have not been implemented Unknown
1144 C++11 Remove access declarations Unknown
1145 C++11 Defaulting and triviality Unknown
1146 C++11 exception-specifications of defaulted functions Unknown
1147 C++11 Destructors should be default nothrow Unknown
1148 C++11 Copy elision and move construction of function parameters Unknown
1149 C++11 Trivial non-public copy operators in subobjects Unknown
1150 NAD Inheriting constructors have not been implemented Unknown
1151 C++11 Overload resolution with initializer-list and non-list constructors Unknown
1152 C++11 Rules for determining existence of implicit conversion sequence Unknown
1153 C++11 Type matching in address of overloaded function Unknown
1154 C++11 Address of thread_local variable as non-type template argument Unknown
1155 C++11 Internal-linkage non-type template arguments Unknown
1156 C++11 Partial ordering in a non-call context Unknown
1157 open Partial ordering of function templates is still underspecified Not resolved
1158 C++11 Recursive instantiation via alias template Unknown
1159 C++11 Class and enumeration definitions in template aliases Unknown
1160 C++11 Definitions of template members and the current instantiation Unknown
1161 C++11 Dependent nested-name-specifier in a pointer-to-member declarator Unknown
1162 NAD Dependent elaborated-type-specifiers in non-deduced contexts Unknown
1163 NAD extern template prevents inlining functions not marked inline Unknown
1164 C++11 Partial ordering of f(T&) and f(T&&) Unknown
1165 C++11 Exceptions when destroying array elements Unknown
1166 C++11 exception-declarations that do not declare objects Unknown
1167 C++11 function-try-blocks for destructors Unknown
1168 C++11 Additional reasons to call std::terminate Unknown
1169 C++11 Missing feature macro for strict pointer safety Unknown
1170 C++11 Access checking during template argument deduction Unknown
1171 C++11 Partial stack unwinding with noexcept violation Unknown
1172 drafting “instantiation-dependent” constructs Not resolved
1173 C++11 Unclear specification of effects of signal handling Unknown
1174 C++11 When is a pure virtual function “used?” Unknown
1175 C++11 Disambiguating user-defined literals Unknown
1176 C++11 Definition of release sequence Unknown
1177 C++11 Intra-thread dependency-ordered-before Unknown
1178 C++11 Deduction failure matching placement new Unknown
1179 NAD Cv-qualification of non-type template parameters Unknown
1180 C++11 Over-aligned class types Unknown
1181 C++11 What is a “built-in type?” Unknown
1182 C++11 Incorrect description of pack expansion syntax Unknown
1183 C++11 Expansion of parameter packs in declarators Unknown
1184 C++11 Argument conversions to nondeduced parameter types Unknown
1185 C++11 Misleading description of language linkage and member function types Unknown
1186 C++11 Non-dependent constexpr violations in function templates Unknown
1187 C++11 Problems in initialization example Unknown
1188 C++11 Type punning in constant expressions Unknown
1189 C++11 Address of distinct base class subobjects Unknown
1190 C++11 Operations on non-safely-derived pointers Unknown
1191 C++11 Deleted subobject destructors and implicitly-defined constructors Unknown
1192 C++11 Inadvertent change to ODR and templates Unknown
1193 C++11 Use of address-constant pointers in constant expressions Unknown
1194 C++11 Constexpr references Unknown
1195 C++11 References to non-literal types in constexpr functions Unknown
1196 C++11 Definition required for explicit instantiation after explicit specialization? Unknown
1197 C++11 Constexpr arrays Unknown
1198 C++11 Literal types and copy constructors Unknown
1199 C++11 Deleted constexpr functions Unknown
1200 open Lookup rules for template parameters Not resolved
1201 C++11 Are deleted and defaulted functions definitions? Unknown
1202 C++11 Calling virtual functions during destruction Unknown
1203 dup Misleading note regarding initialized static data members Unknown
1204 C++11 Specifiers in a for-range-declaration Unknown
1205 dup Lvalue reference binding and function viability Unknown
1206 C++11 Defining opaque enumeration members of class templates Unknown
1207 C++11 Type of class member in trailing-return-type Unknown
1208 C++11 Explicit noexcept in defaulted definition Unknown
1209 open Is a potentially-evaluated expression in a template definition a “use?” Not resolved
1210 C++11 Injection of elaborated-type-specifier in enumeration scope Unknown
1211 drafting Misaligned lvalues Not resolved
1212 C++11 Non-function-call xvalues and decltype Unknown
1213 CD3 Array subscripting and xvaluesSVNClang 7
1214 C++11 Kinds of initializers Unknown
1215 C++11 Definition of POD struct Unknown
1216 C++11 Exceptions “allowed” by a noexcept-specification Unknown
1217 NAD Are deleted functions implicitly noexcept? Unknown
1218 C++11 What is the “currently-handled exception” in a multi-threaded program? Unknown
1219 C++11 Non-static data member initializers in constant expressions Unknown
1220 C++11 Looking up conversion-type-ids Unknown
1221 open Partial ordering and reference collapsing Not resolved
1222 NAD Unnecessary restriction on auto array types Unknown
1223 drafting Syntactic disambiguation and trailing-return-types Not resolved
1224 C++11 constexpr defaulted copy constructors Unknown
1225 C++11 constexpr constructors and virtual bases Unknown
1226 CD3 Converting a braced-init-list default argument Unknown
1227 CD3 Mixing immediate and non-immediate contexts in deduction failure Unknown
1228 NAD Copy-list-initialization and explicit constructors Unknown
1229 C++11 Overload resolution with empty braced-init-list argument Unknown
1230 open Confusing description of ambiguity of destructor name Not resolved
1231 C++11 Variadic templates requiring an empty pack expansion Unknown
1232 C++11 Creation of array temporaries using a braced-init-list Unknown
1233 C++11 Pack expansions and dependent calls Unknown
1234 C++11 abstract-declarator does not permit ... after ptr-operator Unknown
1235 C++11 “Unused” ellipsis and default arguments in partial ordering Unknown
1236 C++11 Inconsistently-interrelated examples Unknown
1237 C++11 Deprecated implicit copy assignment in example Unknown
1238 C++11 Overloading ambiguity binding reference to function Unknown
1239 C++11 Hexadecimal floating-point literals vs user-defined literals Unknown
1240 C++11 constexpr defaulted constructors Unknown
1241 C++11 Which members does a destructor destroy? Unknown
1242 C++11 Initializing variant class members Unknown
1243 C++11 Misleading footnote regarding multiple-declarator declarations Unknown
1244 C++11 Equivalence of alias templates and class templates Unknown
1245 C++11 Matching declarations involving decltype Unknown
1246 C++11 Non-deduced non-final parameter packs Unknown
1247 CD4 Restriction on alias name appearing in type-id Unknown
1248 open Updating Annex C to C99 Not resolved
1249 drafting Cv-qualification of nested lambda capture Not resolved
1250 CD3 Cv-qualification of incomplete virtual function return types Clang 3.9
1251 CD3 C compatibility: casting to unqualified void* Unknown
1252 drafting Overloading member function templates based on dependent return type Not resolved
1253 drafting Generic non-template members Not resolved
1254 NAD odr-use vs template arguments and constexpr functions Unknown
1255 drafting Definition problems with constexpr functions Not resolved
1256 open Unevaluated operands are not necessarily constant expressions Not resolved
1257 open Instantiation via non-dependent references in uninstantiated templates Not resolved
1258 drafting “Instantiation context” differs from dependent lookup rules Not resolved
1259 NAD Deleting a POD via a pointer to base Unknown
1260 CD3 Incorrect use of term “overloaded” in description of odr-use Unknown
1261 CD3 Explicit handling of cv-qualification with non-class prvalues Unknown
1262 CD3 Default template arguments and deduction failure Unknown
1263 NAD Mismatch between rvalue reference binding and overload resolution Unknown
1264 CD3 Use of this in constexpr constructor Unknown
1265 CD3 Mixed use of the auto specifier Clang 5
1266 open user-defined-integer-literal overflow Not resolved
1267 CD3 Rvalue reference types in exception-specifications Unknown
1268 CD3 reinterpret_cast of an xvalue operand Unknown
1269 CD3 dynamic_cast of an xvalue operand Unknown
1270 CD3 Brace elision in array temporary initialization Unknown
1271 drafting Imprecise wording regarding dependent types Not resolved
1272 NAD Implicit definition of static data member of const literal type Unknown
1273 NAD Accessibility and function signatures Unknown
1274 CD4 Common nonterminal for expression and braced-init-list Unknown
1275 CD3 Incorrect comment in example of template parameter pack restriction Unknown
1276 NAD Reference to stdint.h Unknown
1277 NAD Lax definition of intmax_t and uintmax_t Unknown
1278 drafting Incorrect treatment of contrived object Not resolved
1279 drafting Additional differences between C++ 2003 and C++ 2011 Not resolved
1280 NAD Object reallocation and reference members Unknown
1281 NAD Virtual and dependent base classes Unknown
1282 CD3 Underspecified destructor exception-specification Unknown
1283 drafting Static data members of classes with typedef name for linkage purposes Not resolved
1284 CD4 Should the lifetime of an array be independent of that of its elements? Unknown
1285 open Trivial destructors and object lifetime Not resolved
1286 drafting Equivalence of alias templates Not resolved
1287 C++14 Direct initialization vs “implicit” conversion in reference binding Unknown
1288 CD3 Reference list initialization Unknown
1289 NAD Can an alias template name the current instantiation? Unknown
1290 CD3 Lifetime of the underlying array of an initializer_list member Unknown
1291 drafting Looking up a conversion-type-id Not resolved
1292 CD4 Dependent calls with braced-init-lists containing a pack expansion Unknown
1293 CD3 String literals in constant expressions Unknown
1294 drafting Side effects in dynamic/static initialization Not resolved
1295 CD3 Binding a reference to an rvalue bit-field Clang 4
1296 CD3 Ill-formed template declarations (not just definitions) Unknown
1297 CD3 Misplaced function attribute-specifier Unknown
1298 CD3 Incorrect example in overload resolution Unknown
1299 DRWP “Temporary objects” vs “temporary expressions” Unknown
1300 dup T() for array types Unknown
1301 CD3 Value initialization of union Unknown
1302 CD3 noexcept applied to expression of type void Unknown
1303 NAD C language linkage for template with internal linkage Unknown
1304 drafting Omitted array bound with string initialization Not resolved
1305 CD3 alignof applied to array of unknown size Unknown
1306 CD3 Modifying an object within a const member function Unknown
1307 C++14 Overload resolution based on size of array initializer-list Unknown
1308 CD3 Completeness of class type within an exception-specification Unknown
1309 CD4 Incorrect note regarding lookup of a member of the current instantiation Unknown
1310 CD3 What is an “acceptable lookup result?” Clang 5
1311 CD3 Volatile lvalues in constant expressions Unknown
1312 CD3 Simulated reinterpret_cast in constant expressions Unknown
1313 CD3 Undefined pointer arithmetic in constant expressions Unknown
1314 NAD Pointer arithmetic within standard-layout objects Unknown
1315 CD4 Restrictions on non-type template arguments in partial specializations Partial
1316 NAD constexpr function requirements and class scope Unknown
1317 NAD Unnamed scoped enumerations Unknown
1318 CD3 Syntactic ambiguities with final Unknown
1319 NAD Error in pack expansion example Unknown
1320 CD3 Converting scoped enumerations to bool Unknown
1321 CD3 Equivalency of dependent calls Unknown
1322 drafting Function parameter type decay in templates Not resolved
1323 NAD Nonexistent nonterminal in alignment-specifier grammar Unknown
1324 CD3 Value initialization and defaulted constructors Unknown
1325 NAD Omitted declarator in friend declarations Unknown
1326 extension Deducing an array bound from an initializer-list Not resolved
1327 CD3 virt-specifier in a defaulted definition Unknown
1328 CD3 Conflict in reference binding vs overload resolution Unknown
1329 CD3 Recursive deduction substitutions Unknown
1330 CD3 Delayed instantiation of noexcept specifiers Clang 4 (C++11 onwards)
1331 extension const mismatch with defaulted copy constructor Not resolved
1332 drafting Handling of invalid universal-character-names Not resolved
1333 CD3 Omission of const in a defaulted copy constructor Unknown
1334 NAD Layout compatibility and cv-qualification Unknown
1335 drafting Stringizing, extended characters, and universal-character-names Not resolved
1336 CD3 Definition of “converting constructor” Unknown
1337 dup Partial ordering and non-deduced parameters Unknown
1338 CD4 Aliasing and allocation functions Unknown
1339 NAD Parenthesized braced-init-list and arrays Unknown
1340 CD3 Complete type in member pointer expressions Unknown
1341 NAD Bit-field initializers Unknown
1342 drafting Order of initialization with multiple declarators Not resolved
1343 C++17 Sequencing of non-class initialization Unknown
1344 C++14 Adding new special member functions to a class via default arguments Unknown
1345 CD3 Initialization of anonymous union class members Unknown
1346 CD3 expression-list initializers and the auto specifier Clang 3.5
1347 CD3 Consistency of auto in multiple-declarator declarations Yes
1348 drafting Use of auto in a trailing-return-type Not resolved
1349 dup Consistency of alias template redeclarations Unknown
1350 CD3 Incorrect exception specification for inherited constructors Unknown
1351 CD4 Problems with implicitly-declared exception-specifications Unknown
1352 CD3 Inconsistent class scope and completeness rules Unknown
1353 drafting Array and variant members and deleted special member functions Not resolved
1354 CD3 Destructor exceptions for temporaries in noexcept expressions Unknown
1355 CD3 Aggregates and “user-provided” constructors Unknown
1356 CD4 Exception specifications of copy assignment operators with virtual bases Unknown
1357 CD3 brace-or-equal-initializers for function and typedef members Unknown
1358 CD3 Unintentionally ill-formed constexpr function template instances Unknown
1359 CD3 constexpr union constructors Clang 3.5
1360 drafting constexpr defaulted default constructors Not resolved
1361 CD3 Requirement on brace-or-equal-initializers of literal types Unknown
1362 CD3 Complete type required for implicit conversion to T& Unknown
1363 CD3 Triviality vs multiple default constructors Unknown
1364 CD3 constexpr function parameters Unknown
1365 CD3 Calling undefined constexpr functions Unknown
1366 CD3 Deleted constexpr constructors and virtual base classes Unknown
1367 CD3 Use of this in a constant expression Unknown
1368 CD3 Value initialization and defaulted constructors (part 2) Unknown
1369 CD3 Function invocation substitution of this Unknown
1370 CD3 identifier-list cannot contain ellipsis Unknown
1371 NAD Deduction from T&& in return types Unknown
1372 CD3 Cross-references incorrect in conversion function template argument deduction Unknown
1373 dup Overload resolution changes matching reference-binding changes Unknown
1374 CD3 Qualification conversion vs difference in reference binding Unknown
1375 CD3 Reference to anonymous union? Unknown
1376 C++14 static_cast of temporary to rvalue reference Unknown
1377 dup Access declarations not mentioned in Annex C Unknown
1378 open When is an instantiation required? Not resolved
1379 NAD Is std::initializer_list an aggregate? Unknown
1380 CD3 Type definitions in template-parameter parameter-declarations Unknown
1381 CD3 Implicitly-declared special member functions and default nothrow Unknown
1382 CD3 Dead code for constructor names Unknown
1383 CD3 Clarifying discarded-value expressions Unknown
1384 NAD reinterpret_cast in constant expressions Unknown
1385 CD3 Syntactic forms of conversion functions for surrogate call functions Unknown
1386 NAD Explicitly-specified partial argument list with multiple parameter packs Unknown
1387 CD3 Missing non-deduced context for decltype Unknown
1388 CD3 Missing non-deduced context following a function parameter pack Clang 4
1389 NAD Recursive reference in trailing-return-type Unknown
1390 drafting Dependency of alias template specializations Not resolved
1391 CD4 Conversions to parameter types with non-deduced template arguments Partial
1392 CD3 Explicit conversion functions for references and non-references Unknown
1393 extension Pack expansions in using-declarations Not resolved
1394 CD3 Incomplete types as parameters of deleted functions Unknown
1395 C++17 Partial ordering of variadic templates reconsidered Unknown
1396 drafting Deferred instantiation and checking of non-static data member initializers Not resolved
1397 CD4 Class completeness in non-static data member initializers Unknown
1398 CD3 Non-type template parameters of type std::nullptr_t Unknown
1399 CD3 Deduction with multiple function parameter packs Duplicate of 1388
1400 NAD Function pointer equality Unknown
1401 CD3 Similar types and reference compatibility Unknown
1402 CD3 Move functions too often deleted Unknown
1403 open Universal-character-names in comments Not resolved
1404 drafting Object reallocation in unions Not resolved
1405 CD3 constexpr and mutable members of literal types Unknown
1406 CD3 ref-qualifiers and added parameters of non-static member function templates Unknown
1407 NAD Integral to bool conversion in converted constant expressions Unknown
1408 CD3 What is “the same aggregate initialization?” Unknown
1409 CD3 What is the second standard conversion sequence of a list-initialization sequence? Unknown
1410 CD3 Reference overload tiebreakers should apply to rvalue references Unknown
1411 CD3 More on global scope :: in nested-name-specifier Unknown
1412 CD3 Problems in specifying pointer conversions Unknown
1413 CD3 Missing cases of value-dependency Unknown
1414 drafting Binding an rvalue reference to a reference-unrelated lvalue Not resolved
1415 CD3 Missing prohibition of block-scope definition of extern object Unknown
1416 CD3 Function cv-qualifiers and typeid Unknown
1417 C++14 Pointers/references to functions with cv-qualifiers or ref-qualifier Unknown
1418 CD3 Type of initializer_list backing array Unknown
1419 NAD Evaluation order in aggregate initialization Unknown
1420 NAD Abstract final classes Unknown
1421 NAD Full expressions and aggregate initialization Unknown
1422 dup Type of character literals containing universal-character-names Unknown
1423 CD3 Convertibility of nullptr to bool Unknown
1424 C++14 When must sub-object destructors be accessible? Unknown
1425 CD3 Base-class subobjects of standard-layout structs N/A (ABI constraint)
1426 extension Allowing additional parameter types in defaulted functions Not resolved
1427 NAD Default constructor and deleted or inaccessible destructors Unknown
1428 CD3 Dynamic const objects Unknown
1429 NAD Scope of a member template's template parameter Unknown
1430 drafting Pack expansion into fixed alias template parameter list Not resolved
1431 CD3 Exceptions from other than throw-expressions Unknown
1432 drafting Newly-ambiguous variadic template expansions Not resolved
1433 extension trailing-return-type and point of declaration Not resolved
1434 NAD Parenthesized braced-init-list Unknown
1435 CD3 template-id as the declarator for a class template constructor Unknown
1436 drafting Interaction of constant expression changes with preprocessor expressions Not resolved
1437 CD3 alignas in alias-declaration Unknown
1438 CD3 Non-dereference use of invalid pointers Unknown
1439 CD3 Lookup and friend template declarations Unknown
1440 CD3 Acceptable decltype-specifiers used as nested-name-specifiers Unknown
1441 C++14 Unclear wording for signal handler restrictions Unknown
1442 CD3 Argument-dependent lookup in the range-based for Unknown
1443 NAD Default arguments and non-static data members Unknown
1444 drafting Type adjustments of non-type template parameters Not resolved
1445 dup Argument-dependent lookup of begin and end Unknown
1446 CD4 Member function with no ref-qualifier and non-member function with rvalue reference Unknown
1447 CD3 static_cast of bit-field lvalue to rvalue reference Unknown
1448 NAD Integral values of type bool Unknown
1449 CD3 Narrowing conversion of negative value to unsigned type Unknown
1450 CD3 INT_MIN % -1 Unknown
1451 extension Objects with no linkage in non-type template arguments Not resolved
1452 drafting Value-initialized objects may be constants Not resolved
1453 CD3 Volatile members in literal classes? Unknown
1454 CD3 Passing constants through constexpr functions via references Unknown
1455 CD3 Lvalue converted constant expressions Unknown
1456 CD3 Address constant expression designating the one-past-the-end address Unknown
1457 CD3 Undefined behavior in left-shift Unknown
1458 CD3 Address of incomplete type vs operator&() Unknown
1459 open Reference-binding tiebreakers in overload resolution Not resolved
1460 C++14 What is an empty union? Clang 3.5
1461 NAD Narrowing conversions to bit-fields Unknown
1462 CD3 Deduction failure vs “ill-formed, no diagnostic required” Unknown
1463 extension extern "C" alias templates Not resolved
1464 CD3 Negative array bound in a new-expression Unknown
1465 CD4 noexcept and std::bad_array_new_length Unknown
1466 C++14 Visible sequences of side effects are redundant Unknown
1467 CD4 List-initialization of aggregate from same-type object Clang 3.7 (C++11 onwards)
1468 drafting typeid, overload resolution, and implicit lambda capture Not resolved
1469 extension Omitted bound in array new-expression Not resolved
1470 NAD Thread migration Unknown
1471 CD3 Nested type of non-dependent base Unknown
1472 CD3 odr-use of reference variables Unknown
1473 CD3 Syntax of literal-operator-id Unknown
1474 NAD User-defined literals and <inttypes.h> format macros Unknown
1475 CD3 Errors in [[carries_dependency]] example Unknown
1476 CD3 Definition of user-defined type Unknown
1477 CD3 Definition of a friend outside its namespace Unknown
1478 drafting template keyword for dependent template template arguments Not resolved
1479 CD3 Literal operators and default arguments Unknown
1480 CD3 Constant initialization via non-constant temporary Unknown
1481 CD3 Increment/decrement operators with reference parameters Unknown
1482 CD3 Point of declaration of enumeration Unknown
1483 NAD Non-dependent static_assert-declarations Unknown
1484 CD4 Unused local classes of function templates Unknown
1485 drafting Out-of-class definition of member unscoped opaque enumeration Not resolved
1486 drafting Base-derived conversion in member pointer deduction Not resolved
1487 CD3 When are inheriting constructors declared? Unknown
1488 drafting abstract-pack-declarators in type-ids Not resolved
1489 CD3 Is value-initialization of an array constant initialization? Unknown
1490 CD4 List-initialization from a string literal Clang 3.7 (C++11 onwards)
1491 CD3 Move construction and rvalue reference members Unknown
1492 CD4 Exception specifications on template destructors Unknown
1493 C++14 Criteria for move-construction Unknown
1494 CD3 Temporary initialization for reference binding in list-initialization Unknown
1495 CD3 Partial specialization of variadic class template Clang 4
1496 CD4 Triviality with deleted and missing default constructors Unknown
1497 NAD Aggregate initialization with parenthesized string literal Unknown
1498 dup Lifetime of temporaries in range-based for Unknown
1499 drafting Missing case for deleted move assignment operator Not resolved
1500 open Name lookup of dependent conversion function Not resolved
1501 NAD Nested braces in list-initialization Unknown
1502 CD3 Value initialization of unions with member initializers Unknown
1503 CD3 Exceptions during copy to exception object Unknown
1504 CD3 Pointer arithmetic after derived-base conversion Unknown
1505 dup Direct binding of reference to temporary in list-initialization Unknown
1506 CD3 Value category of initializer_list object Unknown
1507 CD3 Value initialization with trivial inaccessible default constructor Unknown
1508 C++14 Template initializer-list constructors Unknown
1509 C++14 Definition of “non-template function” Unknown
1510 CD3 cv-qualified references via decltype Unknown
1511 CD3 const volatile variables and the one-definition rule Unknown
1512 CD3 Pointer comparison vs qualification conversions Clang 4
1513 drafting initializer_list deduction failure Not resolved
1514 C++14 Ambiguity between enumeration definition and zero-length bit-field Unknown
1515 CD3 Modulo 2n arithmetic for implicitly-unsigned types Unknown
1516 CD3 Definition of “virtual function call” Unknown
1517 drafting Unclear/missing description of behavior during construction/destruction Not resolved
1518 CD4 Explicit default constructors and copy-list-initialization Clang 4
1519 NAD Conflicting default and variadic constructors Unknown
1520 NAD Alias template specialization vs pack expansion Unknown
1521 drafting T{expr} with reference types Not resolved
1522 CD3 Access checking for initializer_list array initialization Unknown
1523 DRWP Point of declaration in range-based for Unknown
1524 drafting Incompletely-defined class template base Not resolved
1525 NAD Array bound inference in temporary array Unknown
1526 dup Dependent-class lookup in the current instantiation Unknown
1527 CD3 Assignment from braced-init-list Unknown
1528 CD3 Repeated cv-qualifiers in declarators Unknown
1529 drafting Nomenclature for variable vs reference non-static data member Not resolved
1530 drafting Member access in out-of-lifetime objects Not resolved
1531 CD3 Definition of “access” (verb) Unknown
1532 CD3 Explicit instantiation and member templates Unknown
1533 CD3 Function pack expansion for member initialization Unknown
1534 dup cv-qualification of prvalue of type “array of class” Unknown
1535 CD3 typeid in core constant expressions Unknown
1536 drafting Overload resolution with temporary from initializer list Not resolved
1537 CD3 Optional compile-time evaluation of constant expressions Unknown
1538 CD3 C-style cast in braced-init-list assignment Unknown
1539 CD3 Definition of “character type” Unknown
1540 NAD Use of address constants in constant expressions Unknown
1541 CD3 cv void return types Unknown
1542 drafting Compound assignment of braced-init-list Not resolved
1543 CD3 Implicit conversion sequence for empty initializer list Unknown
1544 CD3 Linkage of member of unnamed namespace Unknown
1545 drafting friend function templates defined in class templates Not resolved
1546 NAD Errors in function template default arguments Unknown
1547 NAD typename keyword in alias-declarations Unknown
1548 drafting Copy/move construction and conversion functions Not resolved
1549 open Overloaded comma operator with void operand Not resolved
1550 CD3 Parenthesized throw-expression operand of conditional-expression Yes
1551 C++14 Wording problems in using-declaration specification Unknown
1552 CD4 exception-specifications and defaulted special member functions Unknown
1553 CD3 sizeof and xvalue bit-fields Unknown
1554 drafting Access and alias templates Not resolved
1555 extension Language linkage and function type compatibility Not resolved
1556 CD3 Constructors and explicit conversion functions in direct initialization Unknown
1557 CD3 Language linkage of converted lambda function pointer Unknown
1558 CD4 Unused arguments in alias template specializations Unknown
1559 CD3 String too long in initializer list of new-expression Unknown
1560 CD3 Gratuitous lvalue-to-rvalue conversion in conditional-expression with throw-expression operand Clang 3.5
1561 extension Aggregates with empty base classes Not resolved
1562 C++14 Non-static data member initializers and union ctor-initializer Unknown
1563 CD3 List-initialization and overloaded function disambiguation Unknown
1564 NAD Template argument deduction from an initializer list Unknown
1565 NAD Copy elision and lifetime of initializer_list underlying array Unknown
1566 NAD Should new std::initializer_list<T> be ill-formed? Unknown
1567 C++14 Inheriting constructors and copy/move constructors Unknown
1568 dup Temporary lifetime extension with intervening cast Unknown
1569 C++14 Deducing a function parameter pack before ellipsis Unknown
1570 C++14 Address of subobject as non-type template argument Unknown
1571 CD4 cv-qualification for indirect reference binding via conversion function Unknown
1572 CD4 Incorrect example for rvalue reference binding via conversion function Unknown
1573 CD4 Inherited constructor characteristics Clang 3.9
1574 NAD Explicitly-defaulted constexpr functions in wrapper templates Unknown
1575 C++14 Incorrect definition of “strict pointer safety” Unknown
1576 C++14 Discarded-value volatile xvalues Unknown
1577 NAD Unnecessary restrictions on partial specializations Unknown
1578 NAD Value-initialization of aggregates Unknown
1579 C++14 Return by converting move constructor Clang 3.9
1580 drafting Default arguments in explicit instantiations Not resolved
1581 drafting When are constexpr member functions defined? Not resolved
1582 drafting Template default arguments and deduction failure Not resolved
1583 C++14 Incorrect example of unspecified behavior Unknown
1584 drafting Deducing function types from cv-qualified types Not resolved
1585 NAD Value category of member access of rvalue reference member Unknown
1586 NAD Naming a destructor via decltype Unknown
1587 C++14 constexpr initialization and nested anonymous unions Unknown
1588 CD3 Deducing cv-qualified auto Unknown
1589 CD4 Ambiguous ranking of list-initialization sequences Clang 3.7 (C++11 onwards)
1590 drafting Bypassing non-copy/move constructor copying Not resolved
1591 CD4 Deducing array bound and element type from initializer list Unknown
1592 C++14 When do template parameters match? Unknown
1593 C++14 “Parameter type” of special member functions Unknown
1594 drafting Lazy declaration of special members vs overload errors Not resolved
1595 C++14 Constructors “involved in” subobject initialization Unknown
1596 CD4 Non-array objects as array[1] Unknown
1597 CD3 Misleading constexpr example Unknown
1598 C++14 Criterion for equality of pointers to members Unknown
1599 open Lifetime of initializer_list underlying array Not resolved
1600 CD4 Erroneous reference initialization in example Unknown
1601 C++14 Promotion of enumeration with fixed underlying type Unknown
1602 open Linkage of specialization vs linkage of template arguments Not resolved
1603 CD4 Errors resulting from giving unnamed namespaces internal linkage Unknown
1604 C++14 Double temporaries in reference initialization Unknown
1605 CD3 Misleading parenthetical comment for explicit destructor call Unknown
1606 NAD sizeof closure class Unknown
1607 C++14 Lambdas in template parameters Unknown
1608 C++14 Operator lookup in trailing return type Unknown
1609 open Default arguments and function parameter packs Not resolved
1610 drafting Cv-qualification in deduction of reference to array Not resolved
1611 C++14 Deleted default constructor for abstract class Duplicate of 1658
1612 C++14 Implicit lambda capture and anonymous unions Unknown
1613 C++14 Constant expressions and lambda capture Unknown
1614 CD4 Address of pure virtual function vs odr-use Unknown
1615 CD4 Alignment of types, variables, and members Unknown
1616 drafting Disambiguation parsing and template parameters Not resolved
1617 open alignas and non-defining declarations Not resolved
1618 C++14 Gratuitously-unsigned underlying enum type Unknown
1619 open Definition of current instantiation Not resolved
1620 open User-defined literals and extended integer types Not resolved
1621 drafting Member initializers in anonymous unions Not resolved
1622 C++17 Empty aggregate initializer for union Unknown
1623 drafting Deleted default union constructor and member initializers Not resolved
1624 NAD Destruction of union members with member initializers Unknown
1625 open Adding spaces between tokens in stringizing Not resolved
1626 drafting constexpr member functions in brace-or-equal-initializers Not resolved
1627 NAD Agreement of dependent alignas specifiers Unknown
1628 open Deallocation function templates Not resolved
1629 C++14 Can a closure class be a literal type? Unknown
1630 CD4 Multiple default constructor templates Unknown
1631 CD4 Incorrect overload resolution for single-element initializer-list Clang 3.7
1632 open Lambda capture in member initializers Not resolved
1633 CD4 Copy-initialization in member initialization Unknown
1634 drafting Temporary storage duration Not resolved
1635 drafting How similar are template default arguments to function default arguments? Not resolved
1636 drafting Bits required for negative enumerator values Not resolved
1637 NAD Recursion in constexpr template default constructor Unknown
1638 CD4 Declaring an explicit specialization of a scoped enumeration Yes
1639 CD4 exception-specifications and pointer/pointer-to-member expressions Unknown
1640 drafting Array of abstract instance of class template Not resolved
1641 NAD Assignment in member initializer Unknown
1642 open Missing requirements for prvalue operands Not resolved
1643 extension Default arguments for template parameter packs Not resolved
1644 open Equivalent exception-specifications in function template declarations Not resolved
1645 CD4 Identical inheriting constructors via default arguments Clang 3.9
1646 drafting decltype-specifiers, abstract classes, and deduction failure Not resolved
1647 drafting Type agreement of non-type template arguments in partial specializations Not resolved
1648 C++14 thread_local vs block extern declarations Unknown
1649 C++14 Error in the syntax of mem-initializer-list Unknown
1650 NAD Class prvalues in reference initialization Unknown
1651 drafting Lifetime extension of temporary via reference to subobject Not resolved
1652 CD4 Object addresses in constexpr expressions Unknown
1653 CD4 Removing deprecated increment of bool Clang 4 (C++17 onwards)
1654 dup Literal types and constexpr defaulted constructors Unknown
1655 drafting Line endings in raw string literals Not resolved
1656 drafting Encoding of numerically-escaped characters Not resolved
1657 CD4 Attributes for namespaces and enumerators Unknown
1658 C++14 Deleted default constructor for abstract class via destructor Clang 5
1659 open Initialization order of thread_local template static data members Not resolved
1660 C++14 member-declaration requirements and unnamed bit-fields Unknown
1661 NAD Preservation of infinite loops Unknown
1662 C++14 Capturing function parameter packs Unknown
1663 NAD Capturing an empty pack expansion Unknown
1664 C++14 Argument-dependent lookup of lambdas used in default arguments Unknown
1665 drafting Declaration matching in explicit instantiations Not resolved
1666 C++14 Address constant expressions Unknown
1667 NAD Function exiting via exception called by destructor during unwinding Unknown
1668 drafting Parameter type determination still not clear enough Not resolved
1669 C++14 auto return type for main Unknown
1670 drafting auto as conversion-type-id Not resolved
1671 NAD Unclear rules for deduction with cv-qualification Unknown
1672 CD4 Layout compatibility with multiple empty basesSVNClang 7
1673 C++14 Clarifying overload resolution for the second step of copy-initialization Unknown
1674 C++14 Return type deduction for address of function Unknown
1675 NAD Size limit for automatic array object Unknown
1676 drafting auto return type for allocation and deallocation functions Not resolved
1677 C++17 Constant initialization via aggregate initialization Unknown
1678 NAD Naming the type of an array of runtime bound Unknown
1679 NAD Range-based for and array of runtime bound Unknown
1680 drafting Including <initializer_list> for range-based for Not resolved
1681 C++14 init-captures and nested lambdas Unknown
1682 open Overly-restrictive rules on function templates as allocation functions Not resolved
1683 CD4 Incorrect example after constexpr changes Unknown
1684 C++14 Static constexpr member functions for non-literal classes Clang 3.6
1685 NAD Value category of noexcept expression Unknown
1686 CD4 Which variables are “explicitly declared const?” Unknown
1687 C++14 Conversions of operands of built-in operatorsSVNClang 7
1688 NAD Volatile constexpr variables Unknown
1689 C++14 Syntactic nonterminal for operand of alignas Unknown
1690 C++14 Associated namespace for local type Unknown
1691 C++14 Argument-dependent lookup and opaque enumerations Unknown
1692 C++14 Associated namespaces of doubly-nested classes Unknown
1693 C++14 Superfluous semicolons in class definitions Unknown
1694 CD4 Restriction on reference to temporary as a constant expression Unknown
1695 NAD Lifetime extension via init-capture Unknown
1696 CD4 Temporary lifetime and non-static data member initializersSVNClang 7
1697 drafting Lifetime extension and copy elision Not resolved
1698 open Files ending in \ Not resolved
1699 drafting Does befriending a class befriend its friends? Not resolved
1700 NAD Does the special rvalue-reference deduction apply to alias templates? Unknown
1701 drafting Array vs sequence in object representation Not resolved
1702 drafting Rephrasing the definition of “anonymous union” Not resolved
1703 NAD Language linkage of names of functions with internal linkage Unknown
1704 DRWP Type checking in explicit instantiation of variable templates Unknown
1705 CD4 Unclear specification of “more specialized” Unknown
1706 drafting alignas pack expansion syntax Not resolved
1707 C++14 template in elaborated-type-specifier without nested-name-specifier Unknown
1708 CD4 overly-strict requirements for names with C language linkage Unknown
1709 drafting Stringizing raw string literals containing newline Not resolved
1710 C++17 Missing template keyword in class-or-decltype Unknown
1711 drafting Missing specification of variable template partial specializations Not resolved
1712 CD4 constexpr variable template declarations Unknown
1713 drafting Linkage of variable template specializations Not resolved
1714 NAD odr-use of this from a local class Unknown
1715 CD4 Access and inherited constructor templates Clang 3.9
1716 C++14 When are default arguments evaluated? Unknown
1717 C++14 Missing specification of type of binary literal Unknown
1718 drafting Macro invocation spanning end-of-file Not resolved
1719 CD4 Layout compatibility and cv-qualification revisited Unknown
1720 NAD Macro invocation in #include directive Unknown
1721 drafting Diagnosing ODR violations for static data members Not resolved
1722 CD4 Should lambda to function pointer conversion function be noexcept? Unknown
1723 drafting Multicharacter user-defined character literals Not resolved
1724 drafting Unclear rules for deduction failure Not resolved
1725 NAD Trailing return type with nested function declarator Unknown
1726 drafting Declarator operators and conversion function Not resolved
1727 NAD Type of a specialization of a variable template Unknown
1728 DRWP Type of an explicit instantiation of a variable template Unknown
1729 drafting Matching declarations and definitions of variable templates Not resolved
1730 drafting Can a variable template have an unnamed type? Not resolved
1731 NAD is_trivially_X and definitions of special member functions Unknown
1732 C++14 Defining types in conditions and range-based for statements Unknown
1733 drafting Return type and value for operator= with ref-qualifier Not resolved
1734 CD4 Nontrivial deleted copy functions Unknown
1735 drafting Out-of-range literals in user-defined-literals Not resolved
1736 CD4 Inheriting constructor templates in a local class Clang 3.9
1737 C++14 Type dependence of call to a member of the current instantiation Unknown
1738 C++14 Explicit instantiation/specialization of inheriting constructor templates Unknown
1739 C++14 Conversion of floating point to enumeration Unknown
1740 C++14 Disambiguation of noexcept Unknown
1741 C++14 odr-use of class object in lvalue-to-rvalue conversion Unknown
1742 open using-declarations and scoped enumerators Not resolved
1743 NAD init-captures in nested lambdas Unknown
1744 CD4 Unordered initialization for variable template specializations Unknown
1745 NAD thread_local constexpr variable Unknown
1746 C++14 Are volatile scalar types trivially copyable? Unknown
1747 C++14 Constant initialization of reference to function Unknown
1748 CD4 Placement new with a null pointer Clang 3.7
1749 NAD Confusing definition for constant initializer Unknown
1750 CD4 “Argument” vs “parameter” Unknown
1751 CD4 Non-trivial operations vs non-trivial initialization Unknown
1752 CD4 Right-recursion in mem-initializer-list Unknown
1753 CD4 decltype-specifier in nested-name-specifier of destructor Unknown
1754 NAD Declaration of partial specialization of static data member template Unknown
1755 drafting Out-of-class partial specializations of member templates Not resolved
1756 CD4 Direct-list-initialization of a non-class object Clang 3.7
1757 CD4 Const integral subobjects Unknown
1758 CD4 Explicit conversion in copy/move list initialization Clang 3.7
1759 C++14 UTF-8 code units in plain char Unknown
1760 C++14 Access of member corresponding to init-capture Unknown
1761 NAD Runtime check on size of automatic array Unknown
1762 C++14 Reserved identifier used in literal-operator-id example Unknown
1763 open Length mismatch in template type deduction Not resolved
1764 C++14 Hiding of function from using-declaration by signature Unknown
1765 C++14 Overflow of enumeration used as enumerator value Unknown
1766 CD4 Values outside the range of the values of an enumeration Unknown
1767 C++14 Scoped enumeration in a switch statement Unknown
1768 NAD Zero-element array of runtime bound Unknown
1769 C++14 Catching a base class of the exception object Unknown
1770 C++14 Type matching of non-type template parameters and arguments Unknown
1771 open Restricted lookup in nested-name-specifier Not resolved
1772 C++14 __func__ in a lambda body Unknown
1773 C++14 Out-of-lifetime lvalue-to-rvalue conversion Unknown
1774 CD4 Discrepancy between subobject destruction and stack unwinding Unknown
1775 C++14 Undefined behavior of line splice in raw string literal Unknown
1776 CD4 Replacement of class objects containing reference members Unknown
1777 CD4 Empty pack expansion in dynamic-exception-specification Unknown
1778 C++14 exception-specification in explicitly-defaulted functions Unknown
1779 CD4 Type dependency of __func__ Unknown
1780 CD4 Explicit instantiation/specialization of generic lambda operator() Unknown
1781 open Converting from nullptr_t to bool in overload resolution Not resolved
1782 CD4 Form of initialization for nullptr_t to bool conversion Unknown
1783 NAD Why are virtual destructors non-trivial? Unknown
1784 C++17 Concurrent execution during static local initialization Unknown
1785 NAD Conflicting diagnostic requirements for template definitions Unknown
1786 C++14 Effect of merging allocations on memory leakage Unknown
1787 C++14 Uninitialized unsigned char values Unknown
1788 CD4 Sized deallocation of array of non-class type Unknown
1789 drafting Array reference vs array decay in overload resolution Not resolved
1790 extension Ellipsis following function parameter pack Not resolved
1791 CD4 Incorrect restrictions on cv-qualifier-seq and ref-qualifier Unknown
1792 NAD Incorrect example of explicit specialization of member enumeration Unknown
1793 CD4 thread_local in explicit specializations Unknown
1794 C++17 template keyword and alias templates Unknown
1795 CD4 Disambiguating original-namespace-definition and extension-namespace-definition Unknown
1796 CD4 Is all-bits-zero for null characters a meaningful requirement? Unknown
1797 CD4 Are all bit patterns of unsigned char distinct numbers? Unknown
1798 NAD exception-specifications of template arguments Unknown
1799 CD4 mutable and non-explicit const qualification Unknown
1800 CD4 Pointer to member of nested anonymous union Unknown
1801 drafting Kind of expression referring to member of anonymous union Not resolved
1802 CD4 char16_t string literals and surrogate pairs Unknown
1803 drafting opaque-enum-declaration as member-declaration Not resolved
1804 CD4 Partial specialization and friendship Unknown
1805 CD4 Conversions of array operands in conditional-expressions Unknown
1806 CD4 Virtual bases and move-assignment Unknown
1807 CD4 Order of destruction of array elements after an exception Unknown
1808 drafting Constructor templates vs default constructors Not resolved
1809 CD4 Narrowing and template argument deduction Unknown
1810 CD4 Invalid ud-suffixes Unknown
1811 CD4 Lookup of deallocation function in a virtual destructor definition Unknown
1812 C++17 Omission of template in a typename-specifier Unknown
1813 CD4 Direct vs indirect bases in standard-layout classesSVNClang 7
1814 CD4 Default arguments in lambda-expressions Unknown
1815 CD4 Lifetime extension in aggregate initialization No
1816 CD4 Unclear specification of bit-field values Unknown
1817 drafting Linkage specifications and nested scopes Not resolved
1818 open Visibility and inherited language linkage Not resolved
1819 CD4 Acceptable scopes for definition of partial specialization Unknown
1820 open Qualified typedef names Not resolved
1821 open Qualified redeclarations in a class member-specification Not resolved
1822 open Lookup of parameter names in lambda-expressions Not resolved
1823 CD4 String literal uniqueness in inline functions Unknown
1824 CD4 Completeness of return type vs point of instantiation Unknown
1825 C++17 Partial ordering between variadic and non-variadic function templates Unknown
1826 NAD const floating-point in constant expressions Unknown
1827 drafting Reference binding with ambiguous conversions Not resolved
1828 drafting nested-name-specifier ambiguity Not resolved
1829 open Dependent unnamed types Not resolved
1830 CD4 Repeated specifiers Unknown
1831 NAD Explicitly vs implicitly deleted move constructors Unknown
1832 CD4 Casting to incomplete enumeration Unknown
1833 NAD friend declarations naming implicitly-declared member functions Unknown
1834 CD4 Constant initialization binding a reference to an xvalue Unknown
1835 drafting Dependent member lookup before < Not resolved
1836 DRWP Use of class type being defined in trailing-return-type Unknown
1837 drafting Use of this in friend and local class declarations Not resolved
1838 CD4 Definition via unqualified-id and using-declaration Unknown
1839 drafting Lookup of block-scope extern declarations Not resolved
1840 drafting Non-deleted explicit specialization of deleted function template Not resolved
1841 drafting < following template injected-class-name Not resolved
1842 concurrency Unevaluated operands and “carries a dependency” Not resolved
1843 CD4 Bit-field in conditional operator with throw operand Unknown
1844 drafting Defining “immediate context” Not resolved
1845 drafting Point of instantiation of a variable template specialization Not resolved
1846 CD4 Declaring explicitly-defaulted implicitly-deleted functions Unknown
1847 CD4 Clarifying compatibility during partial ordering Unknown
1848 CD4 Parenthesized constructor and destructor declarators Unknown
1849 drafting Variable templates and the ODR Not resolved
1850 CD4 Differences between definition context and point of instantiation Unknown
1851 CD4 decltype(auto) in new-expressions Unknown
1852 CD4 Wording issues regarding decltype(auto) Unknown
1853 drafting Defining “allocated storage” Not resolved
1854 drafting Disallowing use of implicitly-deleted functions Not resolved
1855 dup Out-of-lifetime access to nonstatic data members Unknown
1856 open Indirect nested classes of class templates Not resolved
1857 drafting Additional questions about bits Not resolved
1858 CD4 Comparing pointers to union members Unknown
1859 drafting UTF-16 in char16_t string literals Not resolved
1860 C++17 What is a “direct member?” Unknown
1861 CD4 Values of a bit-field Unknown
1862 DR Determining “corresponding members” for friendship Unknown
1863 CD4 Requirements on thrown object type to support std::current_exception() Unknown
1864 extension List-initialization of array objects Not resolved
1865 CD4 Pointer arithmetic and multi-level qualification conversions Unknown
1866 CD4 Initializing variant members with non-trivial destructors Unknown
1867 NAD Function/expression ambiguity with qualified parameter name Unknown
1868 drafting Meaning of “placeholder type” Not resolved
1869 NAD thread_local vs linkage-specifications Unknown
1870 CD4 Contradictory wording about definitions vs explicit specialization/instantiation Unknown
1871 extension Non-identifier characters in ud-suffix Not resolved
1872 CD4 Instantiations of constexpr templates that cannot appear in constant expressions Unknown
1873 CD4 Protected member access from derived class friends Unknown
1874 CD4 Type vs non-type template parameters with class keyword Unknown
1875 CD4 Reordering declarations in class scope Unknown
1876 extension Preventing explicit specialization Not resolved
1877 CD4 Return type deduction from return with no operand Unknown
1878 CD4 operator auto template Unknown
1879 NAD Inadequate definition of alignment requirement Unknown
1880 drafting When are parameter objects destroyed? Not resolved
1881 CD4 Standard-layout classes and unnamed bit-fieldsSVNClang 7
1882 CD4 Reserved names without library use Unknown
1883 drafting Protected access to constructors in mem-initializers Not resolved
1884 drafting Unclear requirements for same-named external-linkage entities Not resolved
1885 CD4 Return value of a function is underspecified Unknown
1886 CD4 Language linkage for main() Unknown
1887 CD4 Problems with :: as nested-name-specifier Unknown
1888 CD4 Implicitly-declared default constructors and explicit Unknown
1889 open Unclear effect of #pragma on conformance Not resolved
1890 drafting Member type depending on definition of member function Not resolved
1891 CD4 Move constructor/assignment for closure class Clang 4
1892 CD4 Use of auto in function type Unknown
1893 tentatively ready Function-style cast with braced-init-lists and empty pack expansions Unknown
1894 open typedef-names and using-declarations Not resolved
1895 CD4 Deleted conversions in conditional operator operands Unknown
1896 drafting Repeated alias templates Not resolved
1897 drafting ODR vs alternative tokens Not resolved
1898 drafting Use of “equivalent” in overload resolution Not resolved
1899 CD4 Value-dependent constant expressions Unknown
1900 drafting Do friend declarations count as “previous declarations”? Not resolved
1901 drafting punctuator referenced but not defined Not resolved
1902 CD4 What makes a conversion “otherwise ill-formed”? Clang 3.7
1903 CD4 What declarations are introduced by a non-member using-declaration? Unknown
1904 NAD Default template arguments for members of class templates Unknown
1905 MAD Dependent types and injected-class-names Unknown
1906 review Name lookup in member friend declaration Not resolved
1907 drafting using-declarations and default arguments Not resolved
1908 drafting Dual destructor lookup and template-ids Not resolved
1909 CD4 Member class template with the same name as the class Yes
1910 tentatively ready “Shall” requirement applied to runtime behavior Unknown
1911 CD4 constexpr constructor with non-literal base class Unknown
1912 extension exception-specification of defaulted function Not resolved
1913 drafting decltype((x)) in lambda-expressions Not resolved
1914 extension Duplicate standard attributes Not resolved
1915 extension Potentially-invoked destructors in non-throwing constructors Not resolved
1916 CD4 “Same cv-unqualified type” Unknown
1917 drafting decltype-qualified enumeration names Not resolved
1918 open friend templates with dependent scopes Not resolved
1919 open Overload resolution for ! with explicit conversion operator Not resolved
1920 CD4 Qualification mismatch in pseudo-destructor-name Unknown
1921 NAD constexpr constructors and point of initialization of const variables Unknown
1922 CD4 Injected class template names and default arguments Unknown
1923 extension Lvalues of type void Not resolved
1924 review Definition of “literal” and kinds of literals Not resolved
1925 CD4 Bit-field prvalues Unknown
1926 CD4 Potential results of subscript operator Unknown
1927 dup Lifetime of temporaries in init-captures Unknown
1928 NAD Triviality of deleted special member functions Unknown
1929 CD4 template keyword following namespace nested-name-specifier Unknown
1930 CD4 init-declarator-list vs member-declarator-list Unknown
1931 extension Default-constructible and copy-assignable closure types Not resolved
1932 CD4 Bit-field results of conditional operators Unknown
1933 NAD Implementation limit for initializer-list elements Unknown
1934 extension Relaxing exception-specification compatibility requirements Not resolved
1935 drafting Reuse of placement arguments in deallocation Not resolved
1936 drafting Dependent qualified-ids Not resolved
1937 drafting Incomplete specification of function pointer from lambda Not resolved
1938 drafting Should hosted/freestanding be implementation-defined? Not resolved
1939 drafting Argument conversions to nondeduced parameter types revisited Not resolved
1940 CD4 static_assert in anonymous unions Yes
1941 CD4 SFINAE and inherited constructor default arguments Clang 3.9
1942 CD4 Incorrect reference to trailing-return-type Unknown
1943 open Unspecified meaning of “bit” Not resolved
1944 open New C incompatibilities Not resolved
1945 open Friend declarations naming members of class templates in non-templates Not resolved
1946 CD4 exception-specifications vs pointer dereference Unknown
1947 NAD Digit separators following non-octal prefix Yes
1948 NAD exception-specification of replacement global new Yes
1949 CD4 “sequenced after” instead of “sequenced before” Unknown
1950 NAD Restructuring description of ranks of conversion sequences Unknown
1951 CD4 Cv-qualification and literal types Unknown
1952 CD4 Constant expressions and library undefined behavior Unknown
1953 open Data races and common initial sequence Not resolved
1954 open typeid null dereference check in subexpressions Not resolved
1955 CD4 #elif with invalid controlling expression Unknown
1956 CD4 Reuse of storage of automatic variables Unknown
1957 extension decltype(auto) with direct-list-initialization Not resolved
1958 CD4 decltype(auto) with parenthesized initializer Unknown
1959 CD4 Inadvertently inherited copy constructor Clang 3.9
1960 NAD Visibility of entity named in class-scope using-declaration Unknown
1961 C++17 Potentially-concurrent actions within a signal handler Unknown
1962 drafting Type of __func__ Not resolved
1963 CD4 Implementation-defined identifier characters Unknown
1964 NAD opaque-enum-declaration in alias-declaration? Unknown
1965 drafting Explicit casts to reference types Not resolved
1966 CD4 Colon following enumeration elaborated-type-specifier Unknown
1967 CD4 Temporary lifetime and move-elision Unknown
1968 NAD Address of typeid in constant expressions Yes
1969 open Missing exclusion of ~S as an ordinary function name Not resolved
1970 NAD Ambiguity resolution for (T())*x Unknown
1971 CD4 Unclear disambiguation of destructor and operator~ Unknown
1972 open Identifier character restrictions in non-identifiers Not resolved
1973 drafting Which parameter-declaration-clause in a lambda-expression? Not resolved
1974 open Redundant specification of non-type typename-specifier Not resolved
1975 CD4 Permissible declarations for exception-specifications Unknown
1976 NAD Ambiguity of namespace-aliases Unknown
1977 drafting Contradictory results of failed destructor lookup Not resolved
1978 CD4 Redundant description of explicit constructor use Unknown
1979 drafting Alias template specialization in template member definition Not resolved
1980 drafting Equivalent but not functionally-equivalent redeclarations Not resolved
1981 CD4 Implicit contextual conversions and explicit Unknown
1982 NAD Deduction extending parameter pack Unknown
1983 tentatively ready Inappropriate use of virt-specifier Unknown
1984 NAD Lossless narrowing conversions Unknown
1985 NAD Unknown bound array member with brace-or-equal-initializer Unknown
1986 drafting odr-use and delayed initialization Not resolved
1987 NAD constexpr static data members across translation units Unknown
1988 CD4 Ambiguity between dependent and non-dependent bases in implicit member access Unknown
1989 drafting Insufficient restrictions on parameters of postfix operators Not resolved
1990 CD4 Ambiguity due to optional decl-specifier-seq Unknown
1991 CD4 Inheriting constructors vs default arguments Clang 3.9
1992 CD4 new (std::nothrow) int[N] can throw Unknown
1993 drafting Use of template<> defining member of explicit specialization Not resolved
1994 dup Confusing wording regarding multiple template<> prefixes Duplicate of 529
1995 CD4 exception-specifications and non-type template parameters Unknown
1996 drafting Reference list-initialization ignores conversion functions Not resolved
1997 drafting Placement new and previous initialization Not resolved
1998 NAD Additional sources of xvalue expressions Unknown
1999 CD4 Representation of source characters as universal-character-names Unknown
2000 CD4 header-name outside #include directive Unknown
2001 CD4 non-directive is underspecified Unknown
2002 open White space within preprocessing directives Not resolved
2003 drafting Zero-argument macros incorrectly specified Not resolved
2004 CD4 Unions with mutable members in constant expressions Unknown
2005 NAD Incorrect constexpr reference initialization requirements Unknown
2006 CD4 Cv-qualified void types Unknown
2007 drafting Argument-dependent lookup for operator= Not resolved
2008 CD4 Default template-arguments underspecified Unknown
2009 open Unclear specification of class scope Not resolved
2010 CD4 exception-specifications and conversion operators Unknown
2011 C++17 Unclear effect of reference capture of reference Unknown
2012 CD4 Lifetime of references Unknown
2013 drafting Pointer subtraction in large array Not resolved
2014 NAD Unneeded deallocation signatures Unknown
2015 CD4 odr-use of deleted virtual functions Unknown
2016 CD4 Confusing wording in description of conversion function Unknown
2017 CD4 Flowing off end is not equivalent to no-expression return Unknown
2018 drafting Qualification conversion vs reference binding Not resolved
2019 CD4 Member references omitted from description of storage duration Unknown
2020 drafting Inadequate description of odr-use of implicitly-invoked functions Not resolved
2021 dup Function template redeclaration via alias template Unknown
2022 CD4 Copy elision in constant expressions Unknown
2023 drafting Composite reference result type of conditional operator Not resolved
2024 CD4 Dependent types and unexpanded parameter packs Unknown
2025 dup Declaration matching via alias templates Unknown
2026 CD4 Zero-initialization and constexpr Unknown
2027 CD4 Unclear requirements for multiple alignas specifiers Unknown
2028 drafting Converting constructors in rvalue reference initialization Not resolved
2029 dup Abstract class return type in decltype operand Unknown
2030 NAD Access of injected-class-name with template arguments Unknown
2031 CD4 Missing incompatibility for && Unknown
2032 CD4 Default template-arguments of variable templates Unknown
2033 CD4 Redundant restriction on partial specialization argument Unknown
2034 NAD Deprecating uncaught_exception() Unknown
2035 CD3 Multi-section example is confusing Unknown
2036 NAD Refactoring parameters-and-qualifiers Unknown
2037 drafting Alias templates and template declaration matching Not resolved
2038 CD4 Document C++14 incompatibility of new braced deduction rule Unknown
2039 CD4 Constant conversions to bool Unknown
2040 CD4 trailing-return-type no longer ambiguous Unknown
2041 CD4 Namespace for explicit class template specialization Unknown
2042 drafting Exceptions and deallocation functions Not resolved
2043 drafting Generalized template arguments and array-to-pointer decay Not resolved
2044 CD4 decltype(auto) and void Unknown
2045 drafting “Identical” template parameter lists Not resolved
2046 C++17 Incomplete thread specifications Unknown
2047 CD4 Coordinating “throws anything” specifications Unknown
2048 open C-style casts that cast away constness vs static_cast Not resolved
2049 drafting List initializer in non-type template default argument Not resolved
2050 NAD Consolidate specification of linkage Unknown
2051 drafting Simplifying alias rules Not resolved
2052 CD4 Template argument deduction vs overloaded operators Unknown
2053 drafting auto in non-generic lambdas Not resolved
2054 open Missing description of class SFINAE Not resolved
2055 drafting Explicitly-specified non-deduced parameter packs Not resolved
2056 drafting Member function calls in partially-initialized class objects Not resolved
2057 drafting Template template arguments with default arguments Not resolved
2058 drafting More errors from internal-linkage namespaces Not resolved
2059 tentatively ready Linkage and deduced return types Unknown
2060 NAD Deduced return type for explicit specialization Unknown
2061 CD4 Inline namespace after simplifications Unknown
2062 drafting Class template redeclaration requirements Not resolved
2063 CD4 Type/nontype hiding in class scope Unknown
2064 CD4 Conflicting specifications for dependent decltype-specifiers Unknown
2065 drafting Current instantiation of a partial specialization Not resolved
2066 CD4 Does type-dependent imply value-dependent? Unknown
2067 open Generated variadic templates requiring empty pack Not resolved
2068 CD4 When can/must a defaulted virtual destructor be defined? Unknown
2069 CD4 Do destructors have names? Unknown
2070 drafting using-declaration with dependent nested-name-specifier Not resolved
2071 CD4 typedef with no declarator Unknown
2072 drafting Default argument instantiation for member functions of templates Not resolved
2073 drafting Allocating memory for exception objects Not resolved
2074 drafting Type-dependence of local class of function template Not resolved
2075 CD4 Passing short initializer lists to array reference parameters Unknown
2076 CD4 List-initialization of arguments for constructor parameters Unknown
2077 drafting Overload resolution and invalid rvalue-reference initialization Not resolved
2078 NAD Name lookup of mem-initilizer-id Unknown
2079 CD4 [[ appearing in a balanced-token-seq Unknown
2080 drafting Example with empty anonymous union member Not resolved
2081 tentatively ready Deduced return type in redeclaration or specialization of function template Unknown
2082 CD4 Referring to parameters in unevaluated operands of default arguments Unknown
2083 drafting Incorrect cases of odr-use Not resolved
2084 CD4 NSDMIs and deleted union default constructors Unknown
2085 CD4 Invalid example of adding special member function via default argument Unknown
2086 drafting Reference odr-use vs implicit capture Not resolved
2087 open Left shift of negative value by zero bits Not resolved
2088 tentatively ready Late tiebreakers in partial ordering Unknown
2089 drafting Restricting selection of builtin overloaded operators Not resolved
2090 drafting Dependency via non-dependent base class Not resolved
2091 CD4 Deducing reference non-type template arguments Unknown
2092 tentatively ready Deduction failure and overload resolution Unknown
2093 CD4 Qualification conversion for pointer-to-member handler matching Unknown
2094 C++17 Trivial copy/move constructor for class with volatile member Clang 5
2095 CD4 Capturing rvalue references to functions by copy Unknown
2096 CD4 Constraints on literal unions Unknown
2097 extension Lambdas and noreturn attribute Not resolved
2098 CD4 Is uncaught_exceptions() per-thread? Unknown
2099 CD4 Inferring the bound of an array static data member Unknown
2100 C++17 Value-dependent address of static data member of class template Unknown
2101 CD4 Incorrect description of type- and value-dependence Unknown
2102 drafting Constructor checking in new-expression Not resolved
2103 drafting Lvalue-to-rvalue conversion is irrelevant in odr-use of a reference Not resolved
2104 CD4 Internal-linkage constexpr references and ODR requirements Unknown
2105 open When do the arguments for a parameter pack end? Not resolved
2106 CD4 Unclear restrictions on use of function-type template arguments Unknown
2107 CD4 Lifetime of temporaries for default arguments in array copying Unknown
2108 drafting Conversions to non-class prvalues in reference initialization Not resolved
2109 CD4 Value dependence underspecified Unknown
2110 drafting Overload resolution for base class conversion and reference/non-reference Not resolved
2111 extension Array temporaries in reference binding Not resolved
2112 drafting new auto{x} Not resolved
2113 CD4 Incompete specification of types for declarators Unknown
2114 CD3 Missing description of incompatibility from aggregate NSDMIs Unknown
2115 drafting Order of implicit destruction vs release of automatic storage Not resolved
2116 drafting Direct or copy initialization for omitted aggregate initializers Not resolved
2117 drafting Explicit specializations and constexpr function templates Not resolved
2118 open Stateful metaprogramming via friend injection Not resolved
2119 NAD Disambiguation of multi-level covariant return type Unknown
2120 CD4 Array as first non-static data member in standard-layout classSVNClang 7
2121 drafting More flexible lambda syntax Not resolved
2122 CD4 Glvalues of void type Unknown
2123 open Omitted constant initialization of local static variables Not resolved
2124 CD4 Signature of constructor template Unknown
2125 extension Copy elision and comma operator Not resolved
2126 drafting Lifetime-extended temporaries in constant expressions Not resolved
2127 drafting Partial specialization and nullptr Not resolved
2128 drafting Imprecise rule for reference member initializer Not resolved
2129 CD4 Non-object prvalues and constant expressions Unknown
2130 CD4 Over-aligned types in new-expressions Unknown
2131 drafting Ambiguity with opaque-enum-declaration Not resolved
2132 extension Deprecated default generated copy constructors Not resolved
2133 open Converting std::nullptr_t to bool Not resolved
2134 NAD Objectless references to non-static member functions Unknown
2135 NAD mem-initializers for virtual bases of abstract classes Unknown
2136 NAD Argument-dependent lookup and initializer lists Unknown
2137 CD4 List-initialization from object of same type Unknown
2138 NAD Explicit member specialization vs implicit instantiation Unknown
2139 NAD Floating-point requirements for integer representation Unknown
2140 CD4 Lvalue-to-rvalue conversion of std::nullptr_t Unknown
2141 CD4 Ambiguity in new-expression with elaborated-type-specifier Unknown
2142 NAD Missing definition of associated classes and namespaces Unknown
2143 C++17 Value-dependency via injected-class-name Unknown
2144 drafting Function/variable declaration ambiguity Not resolved
2145 CD4 Parenthesized declarator in function definition Unknown
2146 CD4 Scalar object vs memory location in definition of “unsequenced” Unknown
2147 CD4 Initializer-list arguments and pack deduction Unknown
2148 drafting Thread storage duration and order of initialization Not resolved
2149 drafting Brace elision and array length deduction Not resolved
2150 CD3 Initializer list array lifetime Unknown
2151 drafting Exception object is not created Not resolved
2152 NAD Can an alternative token be used as a ud-suffix? Unknown
2153 CD4 pure-specifier in friend declaration Unknown
2154 CD4 Ambiguity of pure-specifier Unknown
2155 C++17 Defining classes and enumerations via using-declarations Unknown
2156 CD4 Definition of enumeration declared by using-declaration Unknown
2157 CD4 Further disambiguation of enumeration elaborated-type-specifier Unknown
2158 drafting Polymorphic behavior during destruction Not resolved
2159 NAD Lambda capture and local thread_local variables Unknown
2160 open Issues with partial ordering Not resolved
2161 NAD Explicit instantiation declaration and “preceding initialization” Unknown
2162 CD3 Capturing this by reference Unknown
2163 CD4 Labels in constexpr functions Unknown
2164 tentatively ready Name hiding and using-directives Unknown
2165 drafting Namespaces, declarative regions, and translation units Not resolved
2166 drafting Unclear meaning of “undefined constexpr function” Not resolved
2167 CD4 Non-member references with lifetimes within the current evaluation Unknown
2168 open Narrowing conversions and +/- infinity Not resolved
2169 extension Narrowing conversions and overload resolution Not resolved
2170 drafting Unclear definition of odr-use for arrays Not resolved
2171 CD4 Triviality of copy constructor with less-qualified parameter Unknown
2172 drafting Multiple exceptions with one exception object Not resolved
2173 open Partial specialization with non-deduced contexts Not resolved
2174 C++17 Unclear rules for friend definitions in templates Unknown
2175 CD4 Ambiguity with attribute in conversion operator declaration Unknown
2176 CD4 Destroying the returned object when a destructor throws Unknown
2177 DR Placement operator delete and parameter copies Unknown
2178 NAD Substitution of dependent template arguments in default template arguments Unknown
2179 drafting Required diagnostic for partial specialization after first use Not resolved
2180 CD4 Virtual bases in destructors and defaulted assignment operators Yes
2181 drafting Normative requirements in an informative Annex Not resolved
2182 drafting Pointer arithmetic in array-like containers Not resolved
2183 NAD Problems in description of potential exceptions Unknown
2184 CD4 Missing C compatibility entry for decrement of bool Unknown
2185 open Cv-qualified numeric types Not resolved
2186 drafting Unclear point that “preceding initialization” must precede Not resolved
2187 open Protected members and access via qualified-id Not resolved
2188 open empty-declaration ambiguity Not resolved
2189 open Surrogate call template Not resolved
2190 open Insufficient specification of __has_include Not resolved
2191 C++17 Incorrect result for noexcept(typeid(v)) Unknown
2192 open Constant expressions and order-of-eval undefined behavior Not resolved
2193 NAD numeric_limits<int>::radix and digits Unknown
2194 review Impossible case in list initialization Not resolved
2195 open Unsolicited reading of trailing volatile members Not resolved
2196 C++17 Zero-initialization with virtual base classes Unknown
2197 review Overload resolution and deleted special member functions Not resolved
2198 C++17 Linkage of enumerators Unknown
2199 drafting Typedefs and tags Not resolved
2200 NAD Conversions in template argument deduction Unknown
2201 C++17 Cv-qualification of array types Unknown
2202 open When does default argument instantiation occur? Not resolved
2203 drafting Defaulted copy/move constructors and UDCs Not resolved
2204 NAD Naming delegated constructors Unknown
2205 C++17 Restrictions on use of alignas Unknown
2206 C++17 Composite type of object and function pointers Unknown
2207 drafting Alignment of allocation function return value Not resolved
2208 NAD static_assert-declaration does not declare a member Unknown
2209 NAD Destruction of constructed array elements Unknown
2210 NAD Principal/target constructor confusion Unknown
2211 C++17 Hiding by lambda captures and parameters Unknown
2212 open Typedef changing linkage after use Not resolved
2213 drafting Forward declaration of partial specializations Not resolved
2214 C++17 Missing requirement on representation of integer values Unknown
2215 review Redundant description of language linkage in function call Not resolved
2216 NAD Exception specifications in unevaluated contexts Unknown
2217 NAD constexpr constructors for non-literal types Unknown
2218 C++17 Ambiguity and namespace aliases Unknown
2219 open Dynamically-unreachable handlers Not resolved
2220 C++17 Hiding index variable in range-based for Unknown
2221 review Copying volatile objects Not resolved
2222 drafting Additional contexts where instantiation is not required Not resolved
2223 drafting Multiple alignas specifiers Not resolved
2224 C++17 Member subobjects and base-class casts Unknown
2225 NAD reinterpret_cast to same floating-point type Unknown
2226 tentatively ready Xvalues vs lvalues in conditional expressions Unknown
2227 tentatively ready Destructor access and default member initializers Unknown
2228 drafting Ambiguity resolution for cast to function type Not resolved
2229 tentatively ready Volatile unnamed bit-fieldsSVNClang 7
2230 NAD Linkage of extern "C" function in unnamed namespace Unknown
2231 NAD Class member access to static data member template Unknown
2232 open thread_local anonymous unions Not resolved
2233 tentatively ready Function parameter packs following default arguments Unknown
2234 tentatively ready Missing rules for simple-template-id as class-name Unknown
2235 tentatively ready Partial ordering and non-dependent types Unknown
2236 drafting When is an alias template specialization dependent? Not resolved
2237 tentatively ready Can a template-id name a constructor? Unknown
2238 NAD Contradictory alignment requirements for allocation Unknown
2239 NAD Sized deallocation with a trivial destructor Unknown
2240 open this is not odr-used in a constant expression Not resolved
2241 open Overload resolution is not invoked with a single function Not resolved
2242 drafting ODR violation with constant initialization possibly omitted Not resolved
2243 drafting Incorrect use of implicit conversion sequence Not resolved
2244 open Base class access in aggregate initialization Not resolved
2245 open Point of instantiation of incomplete class template Not resolved
2246 open Access of indirect virtual base class constructors Not resolved
2247 C++17 Lambda capture and variable argument list Unknown
2248 C++17 Problems with sized delete Unknown
2249 tentatively ready identifiers and id-expressions Unknown
2250 open Implicit instantiation, destruction, and TUs Not resolved
2251 C++17 Unreachable enumeration list-initialization Unknown
2252 open Enumeration list-initialization from the same type Not resolved
2253 DRWP Unnamed bit-fields and zero-initialization Unknown
2254 tentatively ready Standard-layout classes and bit-fields Unknown
2255 tentatively ready Instantiated static data member templates Unknown
2256 open Lifetime of trivially-destructible objects Not resolved
2257 open Lifetime extension of references vs exceptions Not resolved
2258 open Storage deallocation during period of destruction Not resolved
2259 C++17 Unclear context describing ambiguity Unknown
2260 tentatively ready Explicit specializations of deleted member functions Unknown
2261 open Explicit instantiation of in-class friend definition Not resolved
2262 C++17 Attributes for asm-definition Unknown
2263 open Default argument instantiation for friends Not resolved
2264 open Memberwise copying with indeterminate value Not resolved
2265 open Delayed pack expansion and member redeclarations Not resolved
2266 open Has dependent type vs is type-dependent Not resolved
2267 open Copy-initialization of temporary in reference direct-initialization Not resolved
2268 C++17 Unions with mutable members in constant expressions revisited Unknown
2269 dup Additional recursive references in aggregate DMIs Unknown
2270 extension Non-inline functions and explicit instantiation declarations Not resolved
2271 C++17 Aliasing this Unknown
2272 C++17 Implicit initialization of aggregate members of reference type Unknown
2273 DRWP Inheriting constructors vs implicit default constructor Unknown
2274 NAD Generic lambda capture vs constexpr if Unknown
2275 drafting Type-dependence of function template Not resolved
2276 C++17 Dependent noexcept and function type-dependence Unknown
2277 DRWP Ambiguity inheriting constructors with default arguments Unknown
2278 open Copy elision in constant expressions reconsidered Not resolved
2279 NAD Multiple attribute-specifiers in one attribute-list Unknown
2280 review Matching a usual deallocation function with placement new Not resolved
2281 open Consistency of aligned operator delete replacement Not resolved
2282 drafting Consistency with mismatched aligned/non-over-aligned allocation/deallocation functions Not resolved
2283 drafting Missing complete type requirements Not resolved
2284 open Sequencing of braced-init-list arguments Not resolved
2285 tentatively ready Issues with structured bindings Unknown
2286 NAD Assignment evaluation order Unknown
2287 DRWP Pointer-interconvertibility in non-standard-layout unions Unknown
2288 NAD Contradictory optionality in simple-declaration Unknown
2289 drafting Uniqueness of decomposition declaration names Not resolved
2290 DRWP Unclear specification for overload resolution and deleted special member functions Unknown
2291 dup Implicit conversion sequences in non-call contexts Unknown
2292 drafting simple-template-id is ambiguous between class-name and type-name Not resolved
2293 drafting Requirements for simple-template-id used as a class-name Not resolved
2294 drafting Dependent auto static data members Not resolved
2295 extension Aggregates with deleted defaulted constructors Not resolved
2296 extension Are default argument instantiation failures in the “immediate context”? Not resolved
2297 review Unclear specification of atomic operations Not resolved
2298 concurrency Actions and expression evaluation Not resolved
2299 tentatively ready constexpr vararg functions Unknown
2300 drafting Lambdas in multiple definitions Not resolved
2301 open Value-initialization and constexpr constructor evaluation Not resolved
2302 NAD Address comparison between different member subobjects Unknown
2303 open Partial ordering and recursive variadic inheritance Not resolved
2304 NAD Incomplete type vs overload resolution Unknown
2305 DR Explicit instantiation of constexpr or inline variable template Unknown
2306 open Nested friend templates of class templates Not resolved
2307 DR Unclear definition of “equivalent to a nontype template parameter” Unknown
2308 open Structured bindings and lambda capture Not resolved
2309 drafting Restrictions on nested statements within constexpr functions Not resolved
2310 open Type completeness and derived-to-base pointer conversions Not resolved
2311 open Missed case for guaranteed copy elision Not resolved
2312 drafting Structured bindings and mutable Not resolved
2313 DR Redeclaration of structured binding reference variables Unknown
2314 dup Structured bindings and lambda capture Unknown
2315 DR What is the “corresponding special member” of a variant member? Unknown
2316 drafting Simplifying class conversions in conditional expressions Not resolved
2317 open Self-referential default member initializers Not resolved
2318 drafting Nondeduced contexts in deduction from a braced-init-list Not resolved
2319 drafting Nested brace initialization from same type Not resolved
2320 extension constexpr if and boolean conversions Not resolved
2321 drafting Conditional operator and cv-qualified class prvalues Not resolved
2322 drafting Substitution failure and lexical order Not resolved
2323 drafting Expunge POD Not resolved
2324 drafting Size of base class subobject Not resolved
2325 drafting std::launder and reuse of character buffers Not resolved
2326 dup Type deduction with initializer list containing ambiguous functions Unknown
2327 drafting Copy elision for direct-initialization with a conversion function Not resolved
2328 open Unclear presentation style of template argument deduction rules Not resolved
2329 drafting Virtual base classes and generated assignment operators Not resolved
2330 drafting Missing references to variable templates Not resolved
2331 drafting Redundancy in description of class scope Not resolved
2332 drafting template-name as simple-type-name vs injected-class-name Not resolved
2333 drafting Escape sequences in UTF-8 character literals Not resolved
2334 open Creation of objects by typeid Not resolved
2335 open Deduced return types vs member types Not resolved
2336 drafting Destructor characteristics vs potentially-constructed subobjects Not resolved
2337 open Incorrect implication of logic ladder for conversion sequence tiebreakers Not resolved
2338 DR Undefined behavior converting to short enums with fixed underlying types Unknown
2339 drafting Underspecified template arguments in structured bindings Not resolved
2340 open Reference collapsing and structured bindings Not resolved
2341 extension Structured bindings with static storage duration Not resolved
2342 DR Reference reinterpret_cast and pointer-interconvertibility Unknown
2343 open void* non-type template parameters Not resolved
2344 open Redeclaration of names in init-statements Not resolved
2345 open Jumping across initializers in init-statements and conditions Not resolved
2346 open Local variables in default arguments Not resolved
2347 open Passing short scoped enumerations to ellipsis Not resolved
2348 open Non-templated constexpr if Not resolved
2349 open Class/enumeration names vs conditions Not resolved
2350 open Forwarding references and deduction guides Not resolved
2351 open void{} Not resolved
2352 open Similar types and reference binding Not resolved
2353 open Potential results of a member access expression for a static data member Not resolved
2354 open Extended alignment and object representation Not resolved
2355 open Deducing noexcept-specifiers Not resolved
2356 tentatively ready Base class copy and move constructors should not be inherited Unknown
diff --git a/www/cxx_status.html b/www/cxx_status.html index 7318b0bab885..be65c6ed0480 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1,1094 +1,1094 @@ Clang - C++17, C++14, C++11 and C++98 Status

C++ Support in Clang

-

Last updated: $Date: 2018-07-27 06:41:37 +0200 (Fri, 27 Jul 2018) $

+

Last updated: $Date: 2018-08-06 12:32:02 +0200 (Mon, 06 Aug 2018) $

Clang fully implements all published ISO C++ standards (C++98 / C++03, C++11, and C++14), and most of the upcoming C++17 standard.

The Clang community is continually striving to improve C++ standards compliance between releases by submitting and tracking C++ Defect Reports and implementing resolutions as they become available.

Experimental work is also under way to implement C++ Technical Specifications that will help drive the future of the C++ programming language.

The LLVM bug tracker contains Clang C++ components that track known bugs with Clang's language conformance in each language mode.

C++98 implementation status

Clang implements all of the ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard) except for export (which was removed in C++11).

C++11 implementation status

Clang 3.3 and later implement all of the ISO C++ 2011 standard.

By default, Clang builds C++ code according to the C++98 standard, with many C++11 features accepted as extensions. You can use Clang in C++11 mode with the -std=c++11 option. Clang's C++11 mode can be used with libc++ or with gcc's libstdc++.

List of features and minimum Clang version with support
Language Feature C++11 Proposal Available in Clang?
Rvalue references N2118 Clang 2.9
    Rvalue references for *this N2439 Clang 2.9
Initialization of class objects by rvalues N1610 Clang 2.9
Non-static data member initializers N2756 Clang 3.0
Variadic templates N2242 Clang 2.9
    Extending variadic template template parameters N2555 Clang 2.9
Initializer lists N2672 Clang 3.1
Static assertions N1720 Clang 2.9
auto-typed variables N1984 Clang 2.9
    Multi-declarator auto N1737 Clang 2.9
    Removal of auto as a storage-class specifier N2546 Clang 2.9
    New function declarator syntax N2541 Clang 2.9
Lambda expressions N2927 Clang 3.1
P0588R1 (DR) No
Declared type of an expression N2343 Clang 2.9
    Incomplete return types N3276 Clang 3.1
Right angle brackets N1757 Clang 2.9
Default template arguments for function templates DR226 Clang 2.9
Solving the SFINAE problem for expressions DR339 Clang 2.9
Alias templates N2258 Clang 3.0
Extern templates N1987 Clang 2.9
Null pointer constant N2431 Clang 3.0
Strongly-typed enums N2347 Clang 2.9
Forward declarations for enums N2764
DR1206
Clang 3.1
Standardized attribute syntax N2761 Clang 3.3 (1)
Generalized constant expressions N2235 Clang 3.1
P0859R0 (DR) No
Alignment support N2341 Clang 3.3
Conditionally-support behavior N1627 Clang 2.9
Changing undefined behavior into diagnosable errors N1727 Clang 2.9
Delegating constructors N1986 Clang 3.0
Inheriting constructors N2540 Clang 3.3
P0136R1 (DR) Clang 3.9
Explicit conversion operators N2437 Clang 3.0
New character types N2249 Clang 2.9
Unicode string literals N2442 Clang 3.0
Raw string literals N2442 Clang 3.0
Universal character names in literals N2170 Clang 3.1
User-defined literals N2765 Clang 3.1
Standard Layout Types N2342 Clang 3.0
Defaulted functions N2346 Clang 3.0
Deleted functions N2346 Clang 2.9
Extended friend declarations N1791 Clang 2.9
Extending sizeof N2253
DR850
Clang 3.1
Inline namespaces N2535 Clang 2.9
Unrestricted unions N2544 Clang 3.1
Local and unnamed types as template arguments N2657 Clang 2.9
Range-based for N2930 Clang 3.0
P0962R1 (DR) No
Explicit virtual overrides N2928
N3206
N3272
Clang 3.0
Minimal support for garbage collection and reachability-based leak detection N2670 N/A (2)
Allowing move constructors to throw [noexcept] N3050 Clang 3.0
Defining move special member functions N3053 Clang 3.0
Concurrency
Sequence points N2239 Clang 3.3
Atomic operations N2427 Clang 3.1
Strong Compare and Exchange N2748 Clang 3.1 (3)
Bidirectional Fences N2752 Clang 3.1
Memory model N2429 Clang 3.2
Data-dependency ordering: atomics and memory model N2664 Clang 3.2 (4)
Propagating exceptions N2179 Clang 2.9
Allow atomics use in signal handlers N2547 Clang 3.1
Thread-local storage N2659 Clang 3.3 (5)
Dynamic initialization and destruction with concurrency N2660 Clang 2.9
C99 Features in C++11
__func__ predefined identifier N2340 Clang 2.9
C99 preprocessor N1653 Clang 2.9
long long N1811 Clang 2.9
Extended integral types N1988 N/A (6)

(1): The [[carries_dependency]] attribute has no effect.
(2): No compiler changes are required for an implementation such as Clang that does not provide garbage collection.
(3): All compare-exchange operations are emitted as strong compare-exchanges.
(4): memory_order_consume is lowered to memory_order_acquire.
(5): thread_local support requires a C++ runtime library providing __cxa_thread_atexit, such as libc++abi 3.6 or later, or libsupc++ 4.8 or later.
(6): No compiler changes are required for an implementation such as Clang that does not provide any extended integer types. __int128 is not treated as an extended integer type, because changing intmax_t would be an ABI-incompatible change.

C++14 implementation status

Clang 3.4 and later implement all of the ISO C++ 2014 standard.

You can use Clang in C++14 mode with the -std=c++14 option (use -std=c++1y in Clang 3.4 and earlier).

List of features and minimum Clang version with support
Language Feature C++14 Proposal Available in Clang?
Tweak to certain C++ contextual conversions N3323 Clang 3.4
Binary literals N3472 Clang 2.9
decltype(auto) N3638 Clang 3.3
Return type deduction for normal functions Clang 3.4
Initialized lambda captures N3648 Clang 3.4
Generic lambdas N3649 Clang 3.4
Variable templates N3651 Clang 3.4
Relaxing requirements on constexpr functions N3652 Clang 3.4
Member initializers and aggregates N3653 Clang 3.3
Clarifying memory allocation N3664 Clang 3.4
[[deprecated]] attribute N3760 Clang 3.4
Single quotation mark as digit separator N3781 Clang 3.4
C++ Sized Deallocation N3778 Clang 3.4 (7)

(7): In Clang 3.7 and later, sized deallocation is only enabled if the user passes the -fsized-deallocation flag. The user must supply definitions of the sized deallocation functions, either by providing them explicitly or by using a C++ standard library that does. libstdc++ added these functions in version 5.0, and libc++ added them in version 3.7.

C++17 implementation status

Clang 5 and later implement all the features of the ISO C++ 2017 standard.

You can use Clang in C++17 mode with the -std=c++17 option (use -std=c++1z in Clang 4 and earlier).

List of features and minimum Clang version with support - +
Language Feature C++17 Proposal Available in Clang?
static_assert with no message N3928 Clang 3.5
Disabling trigraph expansion by default N4086 Clang 3.5
typename in a template template parameter N4051 Clang 3.5
New auto rules for direct-list-initialization N3922 Clang 3.8 (8)
Fold expressions N4295 Clang 3.6
P0036R0 Clang 3.9
u8 character literals N4267 Clang 3.6
Nested namespace definition N4230 Clang 3.6
Attributes for namespaces and enumerators N4266 Clang 3.6
Allow constant evaluation for all non-type template arguments N4268 Clang 3.6
Remove deprecated register storage class P0001R1 Clang 3.8
Remove deprecated bool increment P0002R1 Clang 3.8
Make exception specifications part of the type system P0012R1 Clang 4
__has_include in preprocessor conditionals P0061R1 Yes
[[fallthrough]] attribute P0188R1 Clang 3.9
[[nodiscard]] attribute P0189R1 Clang 3.9
[[maybe_unused]] attribute P0212R1 Clang 3.9
Aggregate initialization of classes with base classes P0017R1 Clang 3.9
constexpr lambda expressions P0170R1 Clang 5
Differing begin and end types in range-based for P0184R0 Clang 3.9
Lambda capture of *this P0018R3 Clang 3.9
Direct-list-initialization of enums P0138R2 Clang 3.9
Hexadecimal floating-point literals P0245R1 Yes
Using attribute namespaces without repetition P0028R4 Clang 3.9
Dynamic memory allocation for over-aligned data P0035R4 Clang 4
Template argument deduction for class templates P0091R3 Clang 5
P0512R0
P0620R0 (DR)SVNClang 7
P0702R1 (DR) Clang 6
Non-type template parameters with auto type P0127R2 Clang 4
Guaranteed copy elision P0135R1 Clang 4
Stricter expression evaluation order P0145R3 Clang 4 (9)
P0400R0
Requirement to ignore unknown attributes P0283R2 Yes
constexpr if-statements P0292R2 Clang 3.9
Inline variables P0386R2 Clang 3.9
Structured bindings P0217R3 Clang 4
P0961R1 (DR) No
P0969R0 (DR) No
Separate variable and condition for if and switch P0305R1 Clang 3.9
Matching template template parameters to compatible arguments P0522R0 Partial (10)
Removing deprecated dynamic exception specifications P0003R5 Clang 4
Pack expansions in using-declarations P0195R2 Clang 4

(8): This is a backwards-incompatible change that is applied to all language versions that allow type deduction from auto (per the request of the C++ committee). In Clang 3.7, a warning is emitted for all cases that would change meaning.
(9): Under the MS ABI, function parameters are destroyed from left to right in the callee. As a result, function parameters in calls to operator<<, operator>>, operator->*, operator&&, operator||, and operator, functions using expression syntax are no longer guaranteed to be destroyed in reverse construction order in that ABI.
(10): Despite being the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.

C++2a implementation status

Clang has experimental support for some proposed features of the C++ standard following C++17, provisionally named C++2a. Note that support for these features may change or be removed without notice, as the draft C++2a standard evolves.

You can use Clang in C++2a mode with the -std=c++2a option.

List of features and minimum Clang version with support
Language Feature C++2a Proposal Available in Clang?
Default member initializers for bit-fields P0683R1 Clang 6
const&-qualified pointers to members P0704R1 Clang 6
Allow lambda-capture [=, this] P0409R2 Clang 6
__VA_OPT__ for preprocessor comma elision P0306R4 Clang 6
P1042R1 Partial
Designated initializers P0329R4 Partial (extension)
template-parameter-list for generic lambdas P0428R2 No
Concepts P0734R0 No
P0857R0
Range-based for statements with initializer P0614R1 No
ADL and function templates that are not visible P0846R0 No
const mismatch with defaulted copy constructor P0641R2 No
Consistent comparison (operator<=>) P0515R3 Partial
P0905R1
P1120R0
Access checking on specializations P0692R1 Partial
Default constructible and assignable stateless lambdas P0624R2 No
Lambdas in unevaluated contexts P0315R4 No
[[no_unique_address]] attribute P0840R2 No
[[likely]] and [[unlikely]] attributes P0479R5 No
typename optional in more contexts P0634R3 No
Pack expansion in lambda init-capture P0780R2 No
Class types as non-type template parameters P0732R2 No
Destroying operator delete P0722R3 Clang 6
Virtual function calls in constant expressions P1064R0 No
Prohibit aggregates with user-declared constructors P1008R1 No
Contracts P0542R5 No
Feature test macros P0941R2 (see below)
explicit(bool) P0892R2 No

Defect reports

Clang generally aims to implement resolutions to Defect Reports (bug fixes against prior standards) retroactively, in all prior standard versions where the fix is meaningful. Significant Defect Report changes to language features after the publication of the relevant standard are marked (DR) in the above table.

Clang also has a test suite for conformance to resolutions for issues on the C++ core issues list, most of which are considered Defect Reports. Implementation status for C++ core issues based on that test suite is tracked on a separate page.

Technical specifications and standing documents

ISO C++ also publishes a number of documents describing additional language and library features that are not part of standard C++.

List of features and minimum Clang version with support
Document Latest draft Compiler flag Available in Clang?
SD-6: SG10 feature test recommendations SD-6 N/A Clang 3.4 (N3745)
Clang 3.6 (N4200)
Clang 4 (P0096R3)
Clang 5 (P0096R4)
- SVN (P0096R5) + Clang 7 (P0096R5)
[TS] Concepts P0121R0 Superseded by P0734R0
[DRAFT TS] Coroutines N4663 -fcoroutines-ts
-stdlib=libc++
Clang 5
[TS] Library Fundamentals, Version 1 (invocation type traits) N4480 N/A No
[TS] Library Fundamentals, Version 2 (source_location) N4617 N/A No
[TS] Modules N4720 -fmodules-ts WIP
[DRAFT TS] Reflection N4746 No
[TS] Transactional Memory N4514 No
diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status index 5b1991717d6b..af85c55af915 100755 --- a/www/make_cxx_dr_status +++ b/www/make_cxx_dr_status @@ -1,184 +1,187 @@ #! /usr/bin/env python import sys, os, re index = 'cwg_index.html' output = 'cxx_dr_status.html' dr_test_dir = '../test/CXX/drs' if len(sys.argv) == 1: pass elif len(sys.argv) == 2: index = sys.argv[1] else: print >>sys.stderr, 'Usage: make_drs []' sys.exit(1) class DR: def __init__(self, section, issue, url, status, title): self.section, self.issue, self.url, self.status, self.title = \ section, issue, url, status, title def __repr__(self): return '%s (%s): %s' % (self.issue, self.status, self.title) def parse(dr): section, issue_link, status, title = [ col.split('>', 1)[1].split('')[0] for col in dr.split('', 1)[0].split('', 1)[1].split('<', 1)[0]) title = title.replace('', '').replace('', '').strip() return DR(section, issue, url, status, title) status_re = re.compile(r'\bdr([0-9]+): (.*)') status_map = {} for test_cpp in os.listdir(dr_test_dir): if not test_cpp.endswith('.cpp'): continue test_cpp = os.path.join(dr_test_dir, test_cpp) found_any = False; for match in re.finditer(status_re, file(test_cpp, 'r').read()): status_map[int(match.group(1))] = match.group(2) found_any = True if not found_any: print >> sys.stderr, "warning:%s: no '// dr123: foo' comments in this file" % test_cpp drs = sorted((parse(dr) for dr in file(index, 'r').read().split('')[2:]), key = lambda dr: dr.issue) out_file = file(output, 'w') print >> out_file, '''\ Clang - C++ Defect Report Status

C++ Defect Report Support in Clang

Last updated: $Date$

C++ defect report implementation status

This page tracks which C++ defect reports are implemented within Clang.

''' def availability(issue): status = status_map.get(issue, 'unknown') avail_suffix = '' if status.endswith(' c++11'): status = status[:-6] avail_suffix = ' (C++11 onwards)' elif status.endswith(' c++14'): status = status[:-6] avail_suffix = ' (C++14 onwards)' elif status.endswith(' c++17'): status = status[:-6] avail_suffix = ' (C++17 onwards)' if status == 'unknown': avail = 'Unknown' avail_style = ' class="none"' - elif status == '7': + elif status == '8': avail = 'SVN' avail_style = ' class="svn"' + elif status == '7': + avail = 'Clang 7' + avail_style = ' class="svn"' elif re.match('^[0-9]+\.?[0-9]*', status): avail = 'Clang %s' % status avail_style = ' class="full"' elif status == 'yes': avail = 'Yes' avail_style = ' class="full"' elif status == 'partial': avail = 'Partial' avail_style = ' class="partial"' elif status == 'no': avail = 'No' avail_style = ' class="none"' elif status == 'na': avail = 'N/A' avail_style = ' class="na"' elif status == 'na lib': avail = 'N/A (Library DR)' avail_style = ' class="na"' elif status == 'na abi': avail = 'N/A (ABI constraint)' avail_style = ' class="na"' elif status.startswith('sup '): dup = status.split(' ', 1)[1] avail = 'Superseded by %s' % (dup, dup) try: _, avail_style = availability(int(dup)) except: print >>sys.stderr, "issue %s marked as sup %s" % (issue, dup) avail_style = ' class="none"' elif status.startswith('dup '): dup = int(status.split(' ', 1)[1]) avail = 'Duplicate of %s' % (dup, dup) _, avail_style = availability(dup) else: assert False, 'unknown status %s for issue %s' % (status, dr.issue) return (avail + avail_suffix, avail_style) count = {} for dr in drs: if dr.status in ('concepts',): # Yeah, cool story bro. continue if dr.status in ('open', 'concurrency', 'drafting', 'review', 'extension'): # We may have to deal with these some day, but not yet. row_style = ' class="open"' avail = 'Not resolved' avail_style = '' assert dr.issue not in status_map, "have status for not-ready dr %s" % dr.issue else: row_style = '' avail, avail_style = availability(dr.issue) if not avail.startswith('Sup') and not avail.startswith('Dup'): count[avail] = count.get(avail, 0) + 1 print >> out_file, '''\ %s ''' % (row_style, dr.issue, dr.url, dr.issue, dr.status, dr.title, avail_style, avail) for status, num in sorted(count.items()): print "%s: %s" % (status, num) print >> out_file, '''\
Number Status Issue title Available in Clang?
%s %s %s
'''