Index: stable/11/UPDATING =================================================================== --- stable/11/UPDATING (revision 349966) +++ stable/11/UPDATING (revision 349967) @@ -1,1857 +1,1856 @@ Updating Information for FreeBSD current users. This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. 20190426: CARP now sets DSCP value CS7(Network Traffic) in the flowlabel field of packets by default instead of only setting TOS_LOWDELAY in IPv4, which was deprecated in 1998. Original behavior can be restored by setting sysctl net.inet.carp.dscp=4. 20190416: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 8.0.0. Please see the 20141231 entry below for information about - prerequisites and upgrading, if you are not already using clang 3.5.0 or - higher. RELENG_10 still has 3.4.1, so you should upgrade to r346291 - first if you are upgrading from 10.x. + prerequisites and upgrading, if you are not already using clang 3.5.0 + or higher. 20190226: geom_uzip(4) depends on the new module xz. If geom_uzip is statically compiled into your custom kernel, add 'device xz' statement to the kernel config. 20190220: Co-existance for Forth and Lua interpreters in bootloaders has now been merged to ease testing of lualoader. LOADER_DEFAULT_INTERP, documented in build(7), may be used to control which interpreter flavor is used in the default loader to be installed. For systems where Lua and Forth coexist, this switch can also be made on a running system by creating a link from /boot/loader{,.efi} to /boot/loader_${flavor}{,.efi} rather than requiring a rebuild. The default flavor in this branch will remain Forth. As indicated in the 20190216 UPDATING entry, booting is a complex environment; it would be prudent to assume that lualoader may not work for your setup and make provisions for backup boot methods. 20190220: zfsloader's functionality has now been folded into loader. zfsloader is no longer necesasary once you've updated your boot blocks. For a transition period, we will install a hardlink for zfsloader to loader to allow a smooth transition until the boot blocks can be updated (hard link because old zfs boot blocks don't understand symlinks). 20190216: Lualoader has been merged to facilitate testing on this branch. It's purely opt-in for now by building WITH_LOADER_LUA and WITHOUT_FORTH in /etc/src.conf, but co-existance will come shortly. Booting is a complex environment and test coverage for Lua-enabled loaders has been thin, so it would be prudent to assume it might not work and make provisions for backup boot methods. 20190216: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 7.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20181228: r342562 modifies the NFSv4 server so that it obeys vfs.nfsd.nfs_privport in the same as it is applied to NFSv2 and 3. This implies that NFSv4 servers that have vfs.nfsd.nfs_privport set will only allow mounts from clients using a reserved port#. Since both the FreeBSD and Linux NFSv4 clients use reserved port#s by default, this should not affect most NFSv4 mounts. 20181107: The '%I' format in the kern.corefile sysctl limits the number of core files that a process can generate to the number stored in the debug.ncores sysctl. The '%I' format is replaced by the single digit index. Previously, if all indexes were taken the kernel would overwrite only a core file with the highest index in a filename. Currently the system will create a new core file if there is a free index or if all slots are taken it will overwrite the oldest one. 20180818: WITH_OFED option now only enables the build for the OFED libraries and some fundamental client utilities. OpenSM and rest of the debugging tools are enabled by WITH_OFED_EXTRA build switch. WITH_OFED is turned on by default on amd64. 20180714: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180601: The releng/11.2 branch has been created from stable/11@r334458. 20180504: The tz database (tzdb) has been updated to 2018e. This version more correctly models time stamps in time zones with negative DST such as Europe/Dublin (from 1971 on), Europe/Prague (1946/7), and Africa/Windhoek (1994/2017). This does not affect the UT offsets, only time zone abbreviations and the tm_isdst flag. 20180409: The use of RSS hash from the network card aka flowid has been disabled by default for lagg(4) as it's currently incompatible with the lacp and loadbalance protocols. This can be re-enabled by setting the following in loader.conf: net.link.lagg.default_use_flowid="1" 20180331: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180211: The LOADER_FIREWIRE_SUPPORT build variable as been renamed to WITH/OUT_LOADER_FIREWIRE. LOADER_{NO_,}GELI_SUPPORT has been renamed to WITH/OUT_LOADER_GELI. 20180210: The geli password typed at boot is now hidden. To restore the previous behavior, see geli(8) for configuration options. The SW_WATCHDOG option is no longer necessary to enable the hardclock-based software watchdog if no hardware watchdog is configured. As before, SW_WATCHDOG will cause the software watchdog to be enabled even if a hardware watchdog is configured. 20180108: lint(1) binaries and library are no longer built by default. To enable building them, define WITH_LINT in src.conf. If you are using a FreeBSD 12 or later system to build 11-stable, you may need to install a lint(1) binary to use WITH_LINT. 20171003: When building multiple kernels using KERNCONF, non-existent KERNCONF files will produce an error and buildkernel will fail. Previously missing KERNCONF files silently failed giving no indication as to why, only to subsequently discover during installkernel that the desired kernel was never built in the first place. 20170926: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 5.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170822: Since the switch to GPT disk labels, fsck for UFS/FFS has been unable to automatically find alternate superblocks. As of r322806, the information needed to find alternate superblocks has been moved to the end of the area reserved for the boot block. Filesystems created with a newfs of this vintage or later will create the recovery information. If you have a filesystem created prior to this change and wish to have a recovery block created for your filesystem, you can do so by running fsck in forground mode (i.e., do not use the -p or -y options). As it starts, fsck will ask ``SAVE DATA TO FIND ALTERNATE SUPERBLOCKS'' to which you should answer yes. 20170629: The releng/11.1 branch has been created from stable/11@r320475. 20170518: arm64 builds now use the base system LLD 4.0.0 linker by default, instead of requiring that the aarch64-binutils port or package be installed. To continue using aarch64-binutils, set CROSS_BINUTILS_PREFIX=/usr/local/aarch64-freebsd/bin . 20170529: The ctl.ko module no longer implements the iSCSI target frontend: cfiscsi.ko does instead. If building cfiscsi.ko as a kernel module, the module can be loaded via one of the following methods: - `cfiscsi_load="YES"` in loader.conf(5). - Add `cfiscsi` to `$kld_list` in rc.conf(5). - ctladm(8)/ctld(8), when compiled with iSCSI support (`WITH_ISCSI=yes` in src.conf(5)) Please see cfiscsi(4) for more details. 20170511: The mmcsd.ko module now additionally depends on geom_flashmap.ko. Also, mmc.ko and mmcsd.ko need to be a matching pair built from the same source (previously, the dependency of mmcsd.ko on mmc.ko was missing, but mmcsd.ko now will refuse to load if it is incompatible with mmc.ko). 20170414: Binds and sends to the loopback addresses, IPv6 and IPv4, will now use any explicitly assigned loopback address available in the jail instead of using the first assigned address of the jail. 20170413: As of r316810 for ipfilter, keep frags is no longer assumed when keep state is specified in a rule. r316810 aligns ipfilter with documentation in man pages separating keep frags from keep state. This allows keep state to specified without forcing keep frags and allows keep frags to be specified independently of keep state. To maintain previous behaviour, also specify keep frags with keep state (as documented in ipf.conf.5). 20170402: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 4.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170323: The code that provides support for ZFS .zfs/ directory functionality has been reimplemented. It's not possible now to create a snapshot by mkdir under .zfs/snapshot/. That should be the only user visible change. 20170319: Many changes in the IPsec code have been merged from the FreeBSD-CURRENT branch. The IPSEC_FILTERTUNNEL kernel option is removed in favour of corresponding sysctl. The IPSEC_NAT_T kernel option is also removed, and now NAT-T is supported by default. Security associations now use the single namespace for SPI allocation, so if you use several manually configured security associations with the same SPI, this configuration needs modification. 20161217: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161124: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161119: The layout of the pmap structure has changed for powerpc to put the pmap statistics at the front for all CPU variations. libkvm(3) and all tools that link against it need to be recompiled. 20161030: isl(4) and cyapa(4) drivers now require a new driver, chromebook_platform(4), to work properly on Chromebook-class hardware. On other types of hardware the drivers may need to be configured using device hints. Please see the corresponding manual pages for details. 20161210: Relocatable object files with the extension of .So have been renamed to use an extension of .pico instead. The purpose of this change is to avoid a name clash with shared libraries on case-insensitive file systems. On those file systems, foo.So is the same file as foo.so. 20160811: The releng/11.0 branch has been created from stable/11@r303970. 20160708: The stable/11 branch has been created from head@r302406. 20160622: The libc stub for the pipe(2) system call has been replaced with a wrapper that calls the pipe2(2) system call and the pipe(2) system call is now only implemented by the kernels that include "options COMPAT_FREEBSD10" in their config file (this is the default). Users should ensure that this option is enabled in their kernel or upgrade userspace to r302092 before upgrading their kernel. 20160527: CAM will now strip leading spaces from SCSI disks' serial numbers. This will effect users who create UFS filesystems on SCSI disks using those disk's diskid device nodes. For example, if /etc/fstab previously contained a line like "/dev/diskid/DISK-%20%20%20%20%20%20%20ABCDEFG0123456", you should change it to "/dev/diskid/DISK-ABCDEFG0123456". Users of geom transforms like gmirror may also be affected. ZFS users should generally be fine. 20160523: The bitstring(3) API has been updated with new functionality and improved performance. But it is binary-incompatible with the old API. Objects built with the new headers may not be linked against objects built with the old headers. 20160520: The brk and sbrk functions have been removed from libc on arm64. Binutils from ports has been updated to not link to these functions and should be updated to the latest version before installing a new libc. 20160517: The armv6 port now defaults to hard float ABI. Limited support for running both hardfloat and soft float on the same system is available using the libraries installed with -DWITH_LIBSOFT. This has only been tested as an upgrade path for installworld and packages may fail or need manual intervention to run. New packages will be needed. To update an existing self-hosted armv6hf system, you must add TARGET_ARCH=armv6 on the make command line for both the build and the install steps. 20160510: Kernel modules compiled outside of a kernel build now default to installing to /boot/modules instead of /boot/kernel. Many kernel modules built this way (such as those in ports) already overrode KMODDIR explicitly to install into /boot/modules. However, manually building and installing a module from /sys/modules will now install to /boot/modules instead of /boot/kernel. 20160414: The CAM I/O scheduler has been committed to the kernel. There should be no user visible impact. This does enable NCQ Trim on ada SSDs. While the list of known rogues that claim support for this but actually corrupt data is believed to be complete, be on the lookout for data corruption. The known rogue list is believed to be complete: o Crucial MX100, M550 drives with MU01 firmware. o Micron M510 and M550 drives with MU01 firmware. o Micron M500 prior to MU07 firmware o Samsung 830, 840, and 850 all firmwares o FCCT M500 all firmwares Crucial has firmware http://www.crucial.com/usa/en/support-ssd-firmware with working NCQ TRIM. For Micron branded drives, see your sales rep for updated firmware. Black listed drives will work correctly because these drives work correctly so long as no NCQ TRIMs are sent to them. Given this list is the same as found in Linux, it's believed there are no other rogues in the market place. All other models from the above vendors work. To be safe, if you are at all concerned, you can quirk each of your drives to prevent NCQ from being sent by setting: kern.cam.ada.X.quirks="0x2" in loader.conf. If the drive requires the 4k sector quirk, set the quirks entry to 0x3. 20160330: The FAST_DEPEND build option has been removed and its functionality is now the one true way. The old mkdep(1) style of 'make depend' has been removed. See 20160311 for further details. 20160317: Resource range types have grown from unsigned long to uintmax_t. All drivers, and anything using libdevinfo, need to be recompiled. 20160311: WITH_FAST_DEPEND is now enabled by default for in-tree and out-of-tree builds. It no longer runs mkdep(1) during 'make depend', and the 'make depend' stage can safely be skipped now as it is auto ran when building 'make all' and will generate all SRCS and DPSRCS before building anything else. Dependencies are gathered at compile time with -MF flags kept in separate .depend files per object file. Users should run 'make cleandepend' once if using -DNO_CLEAN to clean out older stale .depend files. 20160306: On amd64, clang 3.8.0 can now insert sections of type AMD64_UNWIND into kernel modules. Therefore, if you load any kernel modules at boot time, please install the boot loaders after you install the kernel, but before rebooting, e.g.: make buildworld make kernel KERNCONF=YOUR_KERNEL_HERE make -C sys/boot install Then follow the usual steps, described in the General Notes section, below. 20160305: Clang, llvm, lldb and compiler-rt have been upgraded to 3.8.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20160301: The AIO subsystem is now a standard part of the kernel. The VFS_AIO kernel option and aio.ko kernel module have been removed. Due to stability concerns, asynchronous I/O requests are only permitted on sockets and raw disks by default. To enable asynchronous I/O requests on all file types, set the vfs.aio.enable_unsafe sysctl to a non-zero value. 20160226: The ELF object manipulation tool objcopy is now provided by the ELF Tool Chain project rather than by GNU binutils. It should be a drop-in replacement, with the addition of arm64 support. The (temporary) src.conf knob WITHOUT_ELFCOPY_AS_OBJCOPY knob may be set to obtain the GNU version if necessary. 20160129: Building ZFS pools on top of zvols is prohibited by default. That feature has never worked safely; it's always been prone to deadlocks. Using a zvol as the backing store for a VM guest's virtual disk will still work, even if the guest is using ZFS. Legacy behavior can be restored by setting vfs.zfs.vol.recursive=1. 20160119: The NONE and HPN patches has been removed from OpenSSH. They are still available in the security/openssh-portable port. 20160113: With the addition of ypldap(8), a new _ypldap user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20151216: The tftp loader (pxeboot) now uses the option root-path directive. As a consequence it no longer looks for a pxeboot.4th file on the tftp server. Instead it uses the regular /boot infrastructure as with the other loaders. 20151211: The code to start recording plug and play data into the modules has been committed. While the old tools will properly build a new kernel, a number of warnings about "unknown metadata record 4" will be produced for an older kldxref. To avoid such warnings, make sure to rebuild the kernel toolchain (or world). Make sure that you have r292078 or later when trying to build 292077 or later before rebuilding. 20151207: Debug data files are now built by default with 'make buildworld' and installed with 'make installworld'. This facilitates debugging but requires more disk space both during the build and for the installed world. Debug files may be disabled by setting WITHOUT_DEBUG_FILES=yes in src.conf(5). 20151130: r291527 changed the internal interface between the nfsd.ko and nfscommon.ko modules. As such, they must both be upgraded to-gether. __FreeBSD_version has been bumped because of this. 20151108: Add support for unicode collation strings leads to a change of order of files listed by ls(1) for example. To get back to the old behaviour, set LC_COLLATE environment variable to "C". Databases administrators will need to reindex their databases given collation results will be different. Due to a bug in install(1) it is recommended to remove the ancient locales before running make installworld. rm -rf /usr/share/locale/* 20151030: The OpenSSL has been upgraded to 1.0.2d. Any binaries requiring libcrypto.so.7 or libssl.so.7 must be recompiled. 20151020: Qlogic 24xx/25xx firmware images were updated from 5.5.0 to 7.3.0. Kernel modules isp_2400_multi and isp_2500_multi were removed and should be replaced with isp_2400 and isp_2500 modules respectively. 20151017: The build previously allowed using 'make -n' to not recurse into sub-directories while showing what commands would be executed, and 'make -n -n' to recursively show commands. Now 'make -n' will recurse and 'make -N' will not. 20151012: If you specify SENDMAIL_MC or SENDMAIL_CF in make.conf, mergemaster and etcupdate will now use this file. A custom sendmail.cf is now updated via this mechanism rather than via installworld. If you had excluded sendmail.cf in mergemaster.rc or etcupdate.conf, you may want to remove the exclusion or change it to "always install". /etc/mail/sendmail.cf is now managed the same way regardless of whether SENDMAIL_MC/SENDMAIL_CF is used. If you are not using SENDMAIL_MC/SENDMAIL_CF there should be no change in behavior. 20151011: Compatibility shims for legacy ATA device names have been removed. It includes ATA_STATIC_ID kernel option, kern.cam.ada.legacy_aliases and kern.geom.raid.legacy_aliases loader tunables, kern.devalias.* environment variables, /dev/ad* and /dev/ar* symbolic links. 20151006: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.7.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20150924: Kernel debug files have been moved to /usr/lib/debug/boot/kernel/, and renamed from .symbols to .debug. This reduces the size requirements on the boot partition or file system and provides consistency with userland debug files. When using the supported kernel installation method the /usr/lib/debug/boot/kernel directory will be renamed (to kernel.old) as is done with /boot/kernel. Developers wishing to maintain the historical behavior of installing debug files in /boot/kernel/ can set KERN_DEBUGDIR="" in src.conf(5). 20150827: The wireless drivers had undergone changes that remove the 'parent interface' from the ifconfig -l output. The rc.d network scripts used to check presence of a parent interface in the list, so old scripts would fail to start wireless networking. Thus, etcupdate(3) or mergemaster(8) run is required after kernel update, to update your rc.d scripts in /etc. 20150827: pf no longer supports 'scrub fragment crop' or 'scrub fragment drop-ovl' These configurations are now automatically interpreted as 'scrub fragment reassemble'. 20150817: Kernel-loadable modules for the random(4) device are back. To use them, the kernel must have device random options RANDOM_LOADABLE kldload(8) can then be used to load random_fortuna.ko or random_yarrow.ko. Please note that due to the indirect function calls that the loadable modules need to provide, the build-in variants will be slightly more efficient. The random(4) kernel option RANDOM_DUMMY has been retired due to unpopularity. It was not all that useful anyway. 20150813: The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired. Control over building the ELF Tool Chain tools is now provided by the WITHOUT_TOOLCHAIN knob. 20150810: The polarity of Pulse Per Second (PPS) capture events with the uart(4) driver has been corrected. Prior to this change the PPS "assert" event corresponded to the trailing edge of a positive PPS pulse and the "clear" event was the leading edge of the next pulse. As the width of a PPS pulse in a typical GPS receiver is on the order of 1 millisecond, most users will not notice any significant difference with this change. Anyone who has compensated for the historical polarity reversal by configuring a negative offset equal to the pulse width will need to remove that workaround. 20150809: The default group assigned to /dev/dri entries has been changed from 'wheel' to 'video' with the id of '44'. If you want to have access to the dri devices please add yourself to the video group with: # pw groupmod video -m $USER 20150806: The menu.rc and loader.rc files will now be replaced during upgrades. Please migrate local changes to menu.rc.local and loader.rc.local instead. 20150805: GNU Binutils versions of addr2line, c++filt, nm, readelf, size, strings and strip have been removed. The src.conf(5) knob WITHOUT_ELFTOOLCHAIN_TOOLS no longer provides the binutils tools. 20150728: As ZFS requires more kernel stack pages than is the default on some architectures e.g. i386, it now warns if KSTACK_PAGES is less than ZFS_MIN_KSTACK_PAGES (which is 4 at the time of writing). Please consider using 'options KSTACK_PAGES=X' where X is greater than or equal to ZFS_MIN_KSTACK_PAGES i.e. 4 in such configurations. 20150706: sendmail has been updated to 8.15.2. Starting with FreeBSD 11.0 and sendmail 8.15, sendmail uses uncompressed IPv6 addresses by default, i.e., they will not contain "::". For example, instead of ::1, it will be 0:0:0:0:0:0:0:1. This permits a zero subnet to have a more specific match, such as different map entries for IPv6:0:0 vs IPv6:0. This change requires that configuration data (including maps, files, classes, custom ruleset, etc.) must use the same format, so make certain such configuration data is upgrading. As a very simple check search for patterns like 'IPv6:[0-9a-fA-F:]*::' and 'IPv6::'. To return to the old behavior, set the m4 option confUSE_COMPRESSED_IPV6_ADDRESSES or the cf option UseCompressedIPv6Addresses. 20150630: The default kernel entropy-processing algorithm is now Fortuna, replacing Yarrow. Assuming you have 'device random' in your kernel config file, the configurations allow a kernel option to override this default. You may choose *ONE* of: options RANDOM_YARROW # Legacy /dev/random algorithm. options RANDOM_DUMMY # Blocking-only driver. If you have neither, you get Fortuna. For most people, read no further, Fortuna will give a /dev/random that works like it always used to, and the difference will be irrelevant. If you remove 'device random', you get *NO* kernel-processed entropy at all. This may be acceptable to folks building embedded systems, but has complications. Carry on reading, and it is assumed you know what you need. *PLEASE* read random(4) and random(9) if you are in the habit of tweaking kernel configs, and/or if you are a member of the embedded community, wanting specific and not-usual behaviour from your security subsystems. NOTE!! If you use RANDOM_DUMMY and/or have no 'device random', you will NOT have a functioning /dev/random, and many cryptographic features will not work, including SSH. You may also find strange behaviour from the random(3) set of library functions, in particular sranddev(3), srandomdev(3) and arc4random(3). The reason for this is that the KERN_ARND sysctl only returns entropy if it thinks it has some to share, and with RANDOM_DUMMY or no 'device random' this will never happen. 20150623: An additional fix for the issue described in the 20150614 sendmail entry below has been been committed in revision 284717. 20150616: FreeBSD's old make (fmake) has been removed from the system. It is available as the devel/fmake port or via pkg install fmake. 20150615: The fix for the issue described in the 20150614 sendmail entry below has been been committed in revision 284436. The work around described in that entry is no longer needed unless the default setting is overridden by a confDH_PARAMETERS configuration setting of '5' or pointing to a 512 bit DH parameter file. 20150614: ALLOW_DEPRECATED_ATF_TOOLS/ATFFILE support has been removed from atf.test.mk (included from bsd.test.mk). Please upgrade devel/atf and devel/kyua to version 0.20+ and adjust any calling code to work with Kyuafile and kyua. 20150614: The import of openssl to address the FreeBSD-SA-15:10.openssl security advisory includes a change which rejects handshakes with DH parameters below 768 bits. sendmail releases prior to 8.15.2 (not yet released), defaulted to a 512 bit DH parameter setting for client connections. To work around this interoperability, sendmail can be configured to use a 2048 bit DH parameter by: 1. Edit /etc/mail/`hostname`.mc 2. If a setting for confDH_PARAMETERS does not exist or exists and is set to a string beginning with '5', replace it with '2'. 3. If a setting for confDH_PARAMETERS exists and is set to a file path, create a new file with: openssl dhparam -out /path/to/file 2048 4. Rebuild the .cf file: cd /etc/mail/; make; make install 5. Restart sendmail: cd /etc/mail/; make restart A sendmail patch is coming, at which time this file will be updated. 20150604: Generation of legacy formatted entries have been disabled by default in pwd_mkdb(8), as all base system consumers of the legacy formatted entries were converted to use the new format by default when the new, machine independent format have been added and supported since FreeBSD 5.x. Please see the pwd_mkdb(8) manual page for further details. 20150525: Clang and llvm have been upgraded to 3.6.1 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150521: TI platform code switched to using vendor DTS files and this update may break existing systems running on Beaglebone, Beaglebone Black, and Pandaboard: - dtb files should be regenerated/reinstalled. Filenames are the same but content is different now - GPIO addressing was changed, now each GPIO bank (32 pins per bank) has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old addressing scheme is now pin 25 on /dev/gpioc3. - Pandaboard: /etc/ttys should be updated, serial console device is now /dev/ttyu2, not /dev/ttyu0 20150501: soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim. If you need the GNU extension from groff soelim(1), install groff from package: pkg install groff, or via ports: textproc/groff. 20150423: chmod, chflags, chown and chgrp now affect symlinks in -R mode as defined in symlink(7); previously symlinks were silently ignored. 20150415: The const qualifier has been removed from iconv(3) to comply with POSIX. The ports tree is aware of this from r384038 onwards. 20150416: Libraries specified by LIBADD in Makefiles must have a corresponding DPADD_ variable to ensure correct dependencies. This is now enforced in src.libnames.mk. 20150324: From legacy ata(4) driver was removed support for SATA controllers supported by more functional drivers ahci(4), siis(4) and mvs(4). Kernel modules ataahci and ataadaptec were removed completely, replaced by ahci and mvs modules respectively. 20150315: Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150307: The 32-bit PowerPC kernel has been changed to a position-independent executable. This can only be booted with a version of loader(8) newer than January 31, 2015, so make sure to update both world and kernel before rebooting. 20150217: If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014), but before r278950, the RNG was not seeded properly. Immediately upgrade the kernel to r278950 or later and regenerate any keys (e.g. ssh keys or openssl keys) that were generated w/ a kernel from that range. This does not affect programs that directly used /dev/random or /dev/urandom. All userland uses of arc4random(3) are affected. 20150210: The autofs(4) ABI was changed in order to restore binary compatibility with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work with the new kernel. 20150131: The powerpc64 kernel has been changed to a position-independent executable. This can only be booted with a new version of loader(8), so make sure to update both world and kernel before rebooting. 20150118: Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix only release, no new features have been added. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0. 20150107: ELF tools addr2line, elfcopy (strip), nm, size, and strings are now taken from the ELF Tool Chain project rather than GNU binutils. They should be drop-in replacements, with the addition of arm64 support. The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the binutils tools, if necessary. See 20150805 for updated information. 20150105: The default Unbound configuration now enables remote control using a local socket. Users who have already enabled the local_unbound service should regenerate their configuration by running "service local_unbound setup" as root. 20150102: The GNU texinfo and GNU info pages have been removed. To be able to view GNU info pages please install texinfo from ports. 20141231: Clang, llvm and lldb have been upgraded to 3.5.0 release. As of this release, a prerequisite for building clang, llvm and lldb is a C++11 capable compiler and C++11 standard library. This means that to be able to successfully build the cross-tools stage of buildworld, with clang as the bootstrap compiler, your system compiler or cross compiler should either be clang 3.3 or later, or gcc 4.8 or later, and your system C++ library should be libc++, or libdstdc++ from gcc 4.8 or later. On any standard FreeBSD 10.x or 11.x installation, where clang and libc++ are on by default (that is, on x86 or arm), this should work out of the box. On 9.x installations where clang is enabled by default, e.g. on x86 and powerpc, libc++ will not be enabled by default, so libc++ should be built (with clang) and installed first. If both clang and libc++ are missing, build clang first, then use it to build libc++. On 8.x and earlier installations, upgrade to 9.x first, and then follow the instructions for 9.x above. Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by default, and do not build clang. Many embedded systems are resource constrained, and will not be able to build clang in a reasonable time, or in some cases at all. In those cases, cross building bootable systems on amd64 is a workaround. This new version of clang introduces a number of new warnings, of which the following are most likely to appear: -Wabsolute-value This warns in two cases, for both C and C++: * When the code is trying to take the absolute value of an unsigned quantity, which is effectively a no-op, and almost never what was intended. The code should be fixed, if at all possible. If you are sure that the unsigned quantity can be safely cast to signed, without loss of information or undefined behavior, you can add an explicit cast, or disable the warning. * When the code is trying to take an absolute value, but the called abs() variant is for the wrong type, which can lead to truncation. If you want to disable the warning instead of fixing the code, please make sure that truncation will not occur, or it might lead to unwanted side-effects. -Wtautological-undefined-compare and -Wundefined-bool-conversion These warn when C++ code is trying to compare 'this' against NULL, while 'this' should never be NULL in well-defined C++ code. However, there is some legacy (pre C++11) code out there, which actively abuses this feature, which was less strictly defined in previous C++ versions. Squid and openjdk do this, for example. The warning can be turned off for C++98 and earlier, but compiling the code in C++11 mode might result in unexpected behavior; for example, the parts of the program that are unreachable could be optimized away. 20141222: The old NFS client and server (kernel options NFSCLIENT, NFSSERVER) kernel sources have been removed. The .h files remain, since some utilities include them. This will need to be fixed later. If "mount -t oldnfs ..." is attempted, it will fail. If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used, the utilities will report errors. 20141121: The handling of LOCAL_LIB_DIRS has been altered to skip addition of directories to top level SUBDIR variable when their parent directory is included in LOCAL_DIRS. Users with build systems with such hierarchies and without SUBDIR entries in the parent directory Makefiles should add them or add the directories to LOCAL_DIRS. 20141109: faith(4) and faithd(8) have been removed from the base system. Faith has been obsolete for a very long time. 20141104: vt(4), the new console driver, is enabled by default. It brings support for Unicode and double-width characters, as well as support for UEFI and integration with the KMS kernel video drivers. You may need to update your console settings in /etc/rc.conf, most probably the keymap. During boot, /etc/rc.d/syscons will indicate what you need to do. vt(4) still has issues and lacks some features compared to syscons(4). See the wiki for up-to-date information: https://wiki.freebsd.org/Newcons If you want to keep using syscons(4), you can do so by adding the following line to /boot/loader.conf: kern.vty=sc 20141102: pjdfstest has been integrated into kyua as an opt-in test suite. Please see share/doc/pjdfstest/README for more details on how to execute it. 20141009: gperf has been removed from the base system for architectures that use clang. Ports that require gperf will obtain it from the devel/gperf port. 20140923: pjdfstest has been moved from tools/regression/pjdfstest to contrib/pjdfstest . 20140922: At svn r271982, The default linux compat kernel ABI has been adjusted to 2.6.18 in support of the linux-c6 compat ports infrastructure update. If you wish to continue using the linux-f10 compat ports, add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are encouraged to update their linux-compat packages to linux-c6 during their next update cycle. 20140729: The ofwfb driver, used to provide a graphics console on PowerPC when using vt(4), no longer allows mmap() of all physical memory. This will prevent Xorg on PowerPC with some ATI graphics cards from initializing properly unless x11-servers/xorg-server is updated to 1.12.4_8 or newer. 20140723: The xdev targets have been converted to using TARGET and TARGET_ARCH instead of XDEV and XDEV_ARCH. 20140719: The default unbound configuration has been modified to address issues with reverse lookups on networks that use private address ranges. If you use the local_unbound service, run "service local_unbound setup" as root to regenerate your configuration, then "service local_unbound reload" to load the new configuration. 20140709: The GNU texinfo and GNU info pages are not built and installed anymore, WITH_INFO knob has been added to allow to built and install them again. UPDATE: see 20150102 entry on texinfo's removal 20140708: The GNU readline library is now an INTERNALLIB - that is, it is statically linked into consumers (GDB and variants) in the base system, and the shared library is no longer installed. The devel/readline port is available for third party software that requires readline. 20140702: The Itanium architecture (ia64) has been removed from the list of known architectures. This is the first step in the removal of the architecture. 20140701: Commit r268115 has added NFSv4.1 server support, merged from projects/nfsv4.1-server. Since this includes changes to the internal interfaces between the NFS related modules, a full build of the kernel and modules will be necessary. __FreeBSD_version has been bumped. 20140629: The WITHOUT_VT_SUPPORT kernel config knob has been renamed WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning which differs from the behaviour controlled by this knob.) 20140619: Maximal length of the serial number in CTL was increased from 16 to 64 chars, that breaks ABI. All CTL-related tools, such as ctladm and ctld, need to be rebuilt to work with a new kernel. 20140606: The libatf-c and libatf-c++ major versions were downgraded to 0 and 1 respectively to match the upstream numbers. They were out of sync because, when they were originally added to FreeBSD, the upstream versions were not respected. These libraries are private and not yet built by default, so renumbering them should be a non-issue. However, unclean source trees will yield broken test programs once the operator executes "make delete-old-libs" after a "make installworld". Additionally, the atf-sh binary was made private by moving it into /usr/libexec/. Already-built shell test programs will keep the path to the old binary so they will break after "make delete-old" is run. If you are using WITH_TESTS=yes (not the default), wipe the object tree and rebuild from scratch to prevent spurious test failures. This is only needed once: the misnumbered libraries and misplaced binaries have been added to OptionalObsoleteFiles.inc so they will be removed during a clean upgrade. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140508: We bogusly installed src.opts.mk in /usr/share/mk. This file should be removed to avoid issues in the future (and has been added to ObsoleteFiles.inc). 20140505: /etc/src.conf now affects only builds of the FreeBSD src tree. In the past, it affected all builds that used the bsd.*.mk files. The old behavior was a bug, but people may have relied upon it. To get this behavior back, you can .include /etc/src.conf from /etc/make.conf (which is still global and isn't changed). This also changes the behavior of incremental builds inside the tree of individual directories. Set MAKESYSPATH to ".../share/mk" to do that. Although this has survived make universe and some upgrade scenarios, other upgrade scenarios may have broken. At least one form of temporary breakage was fixed with MAKESYSPATH settings for buildworld as well... In cases where MAKESYSPATH isn't working with this setting, you'll need to set it to the full path to your tree. One side effect of all this cleaning up is that bsd.compiler.mk is no longer implicitly included by bsd.own.mk. If you wish to use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk as well. 20140430: The lindev device has been removed since /dev/full has been made a standard device. __FreeBSD_version has been bumped. 20140424: The knob WITHOUT_VI was added to the base system, which controls building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1) in order to reorder files share/termcap and didn't build ex(1) as a build tool, so building/installing with WITH_VI is highly advised for build hosts for older releases. This issue has been fixed in stable/9 and stable/10 in r277022 and r276991, respectively. 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds will silently lack HESIOD. 20140405: The uart(4) driver has been changed with respect to its handling of the low-level console. Previously the uart(4) driver prevented any process from changing the baudrate or the CLOCAL and HUPCL control flags. By removing the restrictions, operators can make changes to the serial console port without having to reboot. However, when getty(8) is started on the serial device that is associated with the low-level console, a misconfigured terminal line in /etc/ttys will now have a real impact. Before upgrading the kernel, make sure that /etc/ttys has the serial console device configured as 3wire without baudrate to preserve the previous behaviour. E.g: ttyu0 "/usr/libexec/getty 3wire" vt100 on secure 20140306: Support for libwrap (TCP wrappers) in rpcbind was disabled by default to improve performance. To re-enable it, if needed, run rpcbind with command line option -W. 20140226: Switched back to the GPL dtc compiler due to updates in the upstream dts files not being supported by the BSDL dtc compiler. You will need to rebuild your kernel toolchain to pick up the new compiler. Core dumps may result while building dtb files during a kernel build if you fail to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler. 20140216: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver has been removed. Please use the nfe(4) driver for NVIDIA nForce MCP Ethernet adapters instead. 20140212: An ABI incompatibility crept into the libc++ 3.4 import in r261283. This could cause certain C++ applications using shared libraries built against the previous version of libc++ to crash. The incompatibility has now been fixed, but any C++ applications or shared libraries built between r261283 and r261801 should be recompiled. 20140204: OpenSSH will now ignore errors caused by kernel lacking of Capsicum capability mode support. Please note that enabling the feature in kernel is still highly recommended. 20140131: OpenSSH is now built with sandbox support, and will use sandbox as the default privilege separation method. This requires Capsicum capability mode support in kernel. 20140128: The libelf and libdwarf libraries have been updated to newer versions from upstream. Shared library version numbers for these two libraries were bumped. Any ports or binaries requiring these two libraries should be recompiled. __FreeBSD_version is bumped to 1100006. 20140110: If a Makefile in a tests/ directory was auto-generating a Kyuafile instead of providing an explicit one, this would prevent such Makefile from providing its own Kyuafile in the future during NO_CLEAN builds. This has been fixed in the Makefiles but manual intervention is needed to clean an objdir if you use NO_CLEAN: # find /usr/obj -name Kyuafile | xargs rm -f 20131213: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 1100004. 20131108: The WITHOUT_ATF build knob has been removed and its functionality has been subsumed into the more generic WITHOUT_TESTS. If you were using the former to disable the build of the ATF libraries, you should change your settings to use the latter. 20131025: The default version of mtree is nmtree which is obtained from NetBSD. The output is generally the same, but may vary slightly. If you found you need identical output adding "-F freebsd9" to the command line should do the trick. For the time being, the old mtree is available as fmtree. 20131014: libbsdyml has been renamed to libyaml and moved to /usr/lib/private. This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg 1.1.4_8 and verify bsdyml not linked in, before running "make delete-old-libs": # make -C /usr/ports/ports-mgmt/pkg build deinstall install clean or # pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml 20131010: The stable/10 branch has been created in subversion from head revision r256279. 20131010: The rc.d/jail script has been updated to support jail(8) configuration file. The "jail__*" rc.conf(5) variables for per-jail configuration are automatically converted to /var/run/jail..conf before the jail(8) utility is invoked. This is transparently backward compatible. See below about some incompatibilities and rc.conf(5) manual page for more details. These variables are now deprecated in favor of jail(8) configuration file. One can use "rc.d/jail config " command to generate a jail(8) configuration file in /var/run/jail..conf without running the jail(8) utility. The default pathname of the configuration file is /etc/jail.conf and can be specified by using $jail_conf or $jail__conf variables. Please note that jail_devfs_ruleset accepts an integer at this moment. Please consider to rewrite the ruleset name with an integer. 20130930: BIND has been removed from the base system. If all you need is a local resolver, simply enable and start the local_unbound service instead. Otherwise, several versions of BIND are available in the ports tree. The dns/bind99 port is one example. With this change, nslookup(1) and dig(1) are no longer in the base system. Users should instead use host(1) and drill(1) which are in the base system. Alternatively, nslookup and dig can be obtained by installing the dns/bind-tools port. 20130916: With the addition of unbound(8), a new unbound user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20130911: OpenSSH is now built with DNSSEC support, and will by default silently trust signed SSHFP records. This can be controlled with the VerifyHostKeyDNS client configuration setting. DNSSEC support can be disabled entirely with the WITHOUT_LDNS option in src.conf. 20130906: The GNU Compiler Collection and C++ standard library (libstdc++) are no longer built by default on platforms where clang is the system compiler. You can enable them with the WITH_GCC and WITH_GNUCXX options in src.conf. 20130905: The PROCDESC kernel option is now part of the GENERIC kernel configuration and is required for the rwhod(8) to work. If you are using custom kernel configuration, you should include 'options PROCDESC'. 20130905: The API and ABI related to the Capsicum framework was modified in backward incompatible way. The userland libraries and programs have to be recompiled to work with the new kernel. This includes the following libraries and programs, but the whole buildworld is advised: libc, libprocstat, dhclient, tcpdump, hastd, hastctl, kdump, procstat, rwho, rwhod, uniq. 20130903: AES-NI intrinsic support has been added to gcc. The AES-NI module has been updated to use this support. A new gcc is required to build the aesni module on both i386 and amd64. 20130821: The PADLOCK_RNG and RDRAND_RNG kernel options are now devices. Thus "device padlock_rng" and "device rdrand_rng" should be used instead of "options PADLOCK_RNG" & "options RDRAND_RNG". 20130813: WITH_ICONV has been split into two feature sets. WITH_ICONV now enables just the iconv* functionality and is now on by default. WITH_LIBICONV_COMPAT enables the libiconv api and link time compatibility. Set WITHOUT_ICONV to build the old way. If you have been using WITH_ICONV before, you will very likely need to turn on WITH_LIBICONV_COMPAT. 20130806: INVARIANTS option now enables DEBUG for code with OpenSolaris and Illumos origin, including ZFS. If you have INVARIANTS in your kernel configuration, then there is no need to set DEBUG or ZFS_DEBUG explicitly. DEBUG used to enable witness(9) tracking of OpenSolaris (mostly ZFS) locks if WITNESS option was set. Because that generated a lot of witness(9) reports and all of them were believed to be false positives, this is no longer done. New option OPENSOLARIS_WITNESS can be used to achieve the previous behavior. 20130806: Timer values in IPv6 data structures now use time_uptime instead of time_second. Although this is not a user-visible functional change, userland utilities which directly use them---ndp(8), rtadvd(8), and rtsold(8) in the base system---need to be updated to r253970 or later. 20130802: find -delete can now delete the pathnames given as arguments, instead of only files found below them or if the pathname did not contain any slashes. Formerly, the following error message would result: find: -delete: : relative path potentially not safe Deleting the pathnames given as arguments can be prevented without error messages using -mindepth 1 or by changing directory and passing "." as argument to find. This works in the old as well as the new version of find. 20130726: Behavior of devfs rules path matching has been changed. Pattern is now always matched against fully qualified devfs path and slash characters must be explicitly matched by slashes in pattern (FNM_PATHNAME). Rulesets involving devfs subdirectories must be reviewed. 20130716: The default ARM ABI has changed to the ARM EABI. The old ABI is incompatible with the ARM EABI and all programs and modules will need to be rebuilt to work with a new kernel. To keep using the old ABI ensure the WITHOUT_ARM_EABI knob is set. NOTE: Support for the old ABI will be removed in the future and users are advised to upgrade. 20130709: pkg_install has been disconnected from the build if you really need it you should add WITH_PKGTOOLS in your src.conf(5). 20130709: Most of network statistics structures were changed to be able keep 64-bits counters. Thus all tools, that work with networking statistics, must be rebuilt (netstat(1), bsnmpd(1), etc.) 20130618: Fix a bug that allowed a tracing process (e.g. gdb) to write to a memory-mapped file in the traced process's address space even if neither the traced process nor the tracing process had write access to that file. 20130615: CVS has been removed from the base system. An exact copy of the code is available from the devel/cvs port. 20130613: Some people report the following error after the switch to bmake: make: illegal option -- J usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable] ... *** [buildworld] Error code 2 this likely due to an old instance of make in ${MAKEPATH} (${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE}) which src/Makefile will use that blindly, if it exists, so if you see the above error: rm -rf `make -V MAKEPATH` should resolve it. 20130516: Use bmake by default. Whereas before one could choose to build with bmake via -DWITH_BMAKE one must now use -DWITHOUT_BMAKE to use the old make. The goal is to remove these knobs for 10-RELEASE. It is worth noting that bmake (like gmake) treats the command line as the unit of failure, rather than statements within the command line. Thus '(cd some/where && dosomething)' is safer than 'cd some/where; dosomething'. The '()' allows consistent behavior in parallel build. 20130429: Fix a bug that allows NFS clients to issue READDIR on files. 20130426: The WITHOUT_IDEA option has been removed because the IDEA patent expired. 20130426: The sysctl which controls TRIM support under ZFS has been renamed from vfs.zfs.trim_disable -> vfs.zfs.trim.enabled and has been enabled by default. 20130425: The mergemaster command now uses the default MAKEOBJDIRPREFIX rather than creating it's own in the temporary directory in order allow access to bootstrapped versions of tools such as install and mtree. When upgrading from version of FreeBSD where the install command does not support -l, you will need to install a new mergemaster command if mergemaster -p is required. This can be accomplished with the command (cd src/usr.sbin/mergemaster && make install). 20130404: Legacy ATA stack, disabled and replaced by new CAM-based one since FreeBSD 9.0, completely removed from the sources. Kernel modules atadisk and atapi*, user-level tools atacontrol and burncd are removed. Kernel option `options ATA_CAM` is now permanently enabled and removed. 20130319: SOCK_CLOEXEC and SOCK_NONBLOCK flags have been added to socket(2) and socketpair(2). Software, in particular Kerberos, may automatically detect and use these during building. The resulting binaries will not work on older kernels. 20130308: CTL_DISABLE has also been added to the sparc64 GENERIC (for further information, see the respective 20130304 entry). 20130304: Recent commits to callout(9) changed the size of struct callout, so the KBI is probably heavily disturbed. Also, some functions in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced by macros. Every kernel module using it won't load, so rebuild is requested. The ctl device has been re-enabled in GENERIC for i386 and amd64, but does not initialize by default (because of the new CTL_DISABLE option) to save memory. To re-enable it, remove the CTL_DISABLE option from the kernel config file or set kern.cam.ctl.disable=0 in /boot/loader.conf. 20130301: The ctl device has been disabled in GENERIC for i386 and amd64. This was done due to the extra memory being allocated at system initialisation time by the ctl driver which was only used if a CAM target device was created. This makes a FreeBSD system unusable on 128MB or less of RAM. 20130208: A new compression method (lz4) has been merged to -HEAD. Please refer to zpool-features(7) for more information. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20130129: A BSD-licensed patch(1) variant has been added and is installed as bsdpatch, being the GNU version the default patch. To inverse the logic and use the BSD-licensed one as default, while having the GNU version installed as gnupatch, rebuild and install world with the WITH_BSD_PATCH knob set. 20130121: Due to the use of the new -l option to install(1) during build and install, you must take care not to directly set the INSTALL make variable in your /etc/make.conf, /etc/src.conf, or on the command line. If you wish to use the -C flag for all installs you may be able to add INSTALL+=-C to /etc/make.conf or /etc/src.conf. 20130118: The install(1) option -M has changed meaning and now takes an argument that is a file or path to append logs to. In the unlikely event that -M was the last option on the command line and the command line contained at least two files and a target directory the first file will have logs appended to it. The -M option served little practical purpose in the last decade so its use is expected to be extremely rare. 20121223: After switching to Clang as the default compiler some users of ZFS on i386 systems started to experience stack overflow kernel panics. Please consider using 'options KSTACK_PAGES=4' in such configurations. 20121222: GEOM_LABEL now mangles label names read from file system metadata. Mangling affect labels containing spaces, non-printable characters, '%' or '"'. Device names in /etc/fstab and other places may need to be updated. 20121217: By default, only the 10 most recent kernel dumps will be saved. To restore the previous behaviour (no limit on the number of kernel dumps stored in the dump directory) add the following line to /etc/rc.conf: savecore_flags="" 20121201: With the addition of auditdistd(8), a new auditdistd user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20121117: The sin6_scope_id member variable in struct sockaddr_in6 is now filled by the kernel before passing the structure to the userland via sysctl or routing socket. This means the KAME-specific embedded scope id in sin6_addr.s6_addr[2] is always cleared in userland application. This behavior can be controlled by net.inet6.ip6.deembed_scopeid. __FreeBSD_version is bumped to 1000025. 20121105: On i386 and amd64 systems WITH_CLANG_IS_CC is now the default. This means that the world and kernel will be compiled with clang and that clang will be installed as /usr/bin/cc, /usr/bin/c++, and /usr/bin/cpp. To disable this behavior and revert to building with gcc, compile with WITHOUT_CLANG_IS_CC. Really old versions of current may need to bootstrap WITHOUT_CLANG first if the clang build fails (its compatibility window doesn't extend to the 9 stable branch point). 20121102: The IPFIREWALL_FORWARD kernel option has been removed. Its functionality now turned on by default. 20121023: The ZERO_COPY_SOCKET kernel option has been removed and split into SOCKET_SEND_COW and SOCKET_RECV_PFLIP. NB: SOCKET_SEND_COW uses the VM page based copy-on-write mechanism which is not safe and may result in kernel crashes. NB: The SOCKET_RECV_PFLIP mechanism is useless as no current driver supports disposeable external page sized mbuf storage. Proper replacements for both zero-copy mechanisms are under consideration and will eventually lead to complete removal of the two kernel options. 20121023: The IPv4 network stack has been converted to network byte order. The following modules need to be recompiled together with kernel: carp(4), divert(4), gif(4), siftr(4), gre(4), pf(4), ipfw(4), ng_ipfw(4), stf(4). 20121022: Support for non-MPSAFE filesystems was removed from VFS. The VFS_VERSION was bumped, all filesystem modules shall be recompiled. 20121018: All the non-MPSAFE filesystems have been disconnected from the build. The full list includes: codafs, hpfs, ntfs, nwfs, portalfs, smbfs, xfs. 20121016: The interface cloning API and ABI has changed. The following modules need to be recompiled together with kernel: ipfw(4), pfsync(4), pflog(4), usb(4), wlan(4), stf(4), vlan(4), disc(4), edsc(4), if_bridge(4), gif(4), tap(4), faith(4), epair(4), enc(4), tun(4), if_lagg(4), gre(4). 20121015: The sdhci driver was split in two parts: sdhci (generic SD Host Controller logic) and sdhci_pci (actual hardware driver). No kernel config modifications are required, but if you load sdhc as a module you must switch to sdhci_pci instead. 20121014: Import the FUSE kernel and userland support into base system. 20121013: The GNU sort(1) program has been removed since the BSD-licensed sort(1) has been the default for quite some time and no serious problems have been reported. The corresponding WITH_GNU_SORT knob has also gone. 20121006: The pfil(9) API/ABI for AF_INET family has been changed. Packet filtering modules: pf(4), ipfw(4), ipfilter(4) need to be recompiled with new kernel. 20121001: The net80211(4) ABI has been changed to allow for improved driver PS-POLL and power-save support. All wireless drivers need to be recompiled to work with the new kernel. 20120913: The random(4) support for the VIA hardware random number generator (`PADLOCK') is no longer enabled unconditionally. Add the padlock_rng device in the custom kernel config if needed. The GENERIC kernels on i386 and amd64 do include the device, so the change only affects the custom kernel configurations. 20120908: The pf(4) packet filter ABI has been changed. pfctl(8) and snmp_pf module need to be recompiled to work with new kernel. 20120828: A new ZFS feature flag "com.delphix:empty_bpobj" has been merged to -HEAD. Pools that have empty_bpobj in active state can not be imported read-write with ZFS implementations that do not support this feature. For more information read the zpool-features(5) manual page. 20120727: The sparc64 ZFS loader has been changed to no longer try to auto- detect ZFS providers based on diskN aliases but now requires these to be explicitly listed in the OFW boot-device environment variable. 20120712: The OpenSSL has been upgraded to 1.0.1c. Any binaries requiring libcrypto.so.6 or libssl.so.6 must be recompiled. Also, there are configuration changes. Make sure to merge /etc/ssl/openssl.cnf. 20120712: The following sysctls and tunables have been renamed for consistency with other variables: kern.cam.da.da_send_ordered -> kern.cam.da.send_ordered kern.cam.ada.ada_send_ordered -> kern.cam.ada.send_ordered 20120628: The sort utility has been replaced with BSD sort. For now, GNU sort is also available as "gnusort" or the default can be set back to GNU sort by setting WITH_GNU_SORT. In this case, BSD sort will be installed as "bsdsort". 20120611: A new version of ZFS (pool version 5000) has been merged to -HEAD. Starting with this version the old system of ZFS pool versioning is superseded by "feature flags". This concept enables forward compatibility against certain future changes in functionality of ZFS pools. The first read-only compatible "feature flag" for ZFS pools is named "com.delphix:async_destroy". For more information read the new zpool-features(5) manual page. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20120417: The malloc(3) implementation embedded in libc now uses sources imported as contrib/jemalloc. The most disruptive API change is to /etc/malloc.conf. If your system has an old-style /etc/malloc.conf, delete it prior to installworld, and optionally re-create it using the new format after rebooting. See malloc.conf(5) for details (specifically the TUNING section and the "opt.*" entries in the MALLCTL NAMESPACE section). 20120328: Big-endian MIPS TARGET_ARCH values no longer end in "eb". mips64eb is now spelled mips64. mipsn32eb is now spelled mipsn32. mipseb is now spelled mips. This is to aid compatibility with third-party software that expects this naming scheme in uname(3). Little-endian settings are unchanged. If you are updating a big-endian mips64 machine from before this change, you may need to set MACHINE_ARCH=mips64 in your environment before the new build system will recognize your machine. 20120306: Disable by default the option VFS_ALLOW_NONMPSAFE for all supported platforms. 20120229: Now unix domain sockets behave "as expected" on nullfs(5). Previously nullfs(5) did not pass through all behaviours to the underlying layer, as a result if we bound to a socket on the lower layer we could connect only to the lower path; if we bound to the upper layer we could connect only to the upper path. The new behavior is one can connect to both the lower and the upper paths regardless what layer path one binds to. 20120211: The getifaddrs upgrade path broken with 20111215 has been restored. If you have upgraded in between 20111215 and 20120209 you need to recompile libc again with your kernel. You still need to recompile world to be able to configure CARP but this restriction already comes from 20111215. 20120114: The set_rcvar() function has been removed from /etc/rc.subr. All base and ports rc.d scripts have been updated, so if you have a port installed with a script in /usr/local/etc/rc.d you can either hand-edit the rcvar= line, or reinstall the port. An easy way to handle the mass-update of /etc/rc.d: rm /etc/rc.d/* && mergemaster -i 20120109: panic(9) now stops other CPUs in the SMP systems, disables interrupts on the current CPU and prevents other threads from running. This behavior can be reverted using the kern.stop_scheduler_on_panic tunable/sysctl. The new behavior can be incompatible with kern.sync_on_panic. 20111215: The carp(4) facility has been changed significantly. Configuration of the CARP protocol via ifconfig(8) has changed, as well as format of CARP events submitted to devd(8) has changed. See manual pages for more information. The arpbalance feature of carp(4) is currently not supported anymore. Size of struct in_aliasreq, struct in6_aliasreq has changed. User utilities using SIOCAIFADDR, SIOCAIFADDR_IN6, e.g. ifconfig(8), need to be recompiled. 20111122: The acpi_wmi(4) status device /dev/wmistat has been renamed to /dev/wmistat0. 20111108: The option VFS_ALLOW_NONMPSAFE option has been added in order to explicitely support non-MPSAFE filesystems. It is on by default for all supported platform at this present time. 20111101: The broken amd(4) driver has been replaced with esp(4) in the amd64, i386 and pc98 GENERIC kernel configuration files. 20110930: sysinstall has been removed 20110923: The stable/9 branch created in subversion. This corresponds to the RELENG_9 branch in CVS. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach before reporting problems with a major version upgrade. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell around can lead to problems if pam has changed too much from your starting point to allow continued authentication after the upgrade. This file should be read as a log of events. When a later event changes information of a prior event, the prior event should not be deleted. Instead, a pointer to the entry with the new information should be placed in the old entry. Readers of this file should also sanity check older entries before relying on them blindly. Authors of new entries should write them with this in mind. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ada0: "gpart bootcode -p /boot/gptzfsboot -i 1 ada0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To just build a kernel when you know that it won't mess you up -------------------------------------------------------------- This assumes you are already running a CURRENT system. Replace ${arch} with the architecture of your machine (e.g. "i386", "arm", "amd64", "ia64", "pc98", "sparc64", "powerpc", "mips", etc). cd src/sys/${arch}/conf config KERNEL_NAME_HERE cd ../compile/KERNEL_NAME_HERE make depend make make install If this fails, go to the "To build a kernel" section. To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make kernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make kernel KERNCONF=YOUR_KERNEL_HERE [8] [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a cd src adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a noop. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from current before 20130425 or from -stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] The new kernel must be able to run existing binaries used by an installworld. When upgrading across major versions, the new kernel's configuration must include the correct COMPAT_FREEBSD option for existing binaries (e.g. COMPAT_FREEBSD11 to run 11.x binaries). Failure to do so may leave you with a system that is hard to boot to recover. A GENERIC kernel will include suitable compatibility options to run binaries from older branches. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. [9] When checking out sources, you must include the -P flag to have cvs prune empty directories. If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since September 23, 2011. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: Copyright 1998-2009 M. Warner Losh. All Rights Reserved. Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WARNER LOSH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: stable/11/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h =================================================================== --- stable/11/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h (revision 349966) +++ stable/11/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h (revision 349967) @@ -1,2526 +1,2526 @@ //===- DeclBase.h - Base Classes for representing declarations --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Decl and DeclContext interfaces. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLBASE_H #define LLVM_CLANG_AST_DECLBASE_H #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/VersionTuple.h" #include #include #include #include #include #include #include namespace clang { class ASTContext; class ASTMutationListener; class Attr; class DeclContext; class ExternalSourceSymbolAttr; class FunctionDecl; class FunctionType; class IdentifierInfo; enum Linkage : unsigned char; class LinkageSpecDecl; class Module; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCMethodDecl; class ObjCProtocolDecl; struct PrintingPolicy; class RecordDecl; class SourceManager; class Stmt; class StoredDeclsMap; class TemplateDecl; class TranslationUnitDecl; class UsingDirectiveDecl; /// Captures the result of checking the availability of a /// declaration. enum AvailabilityResult { AR_Available = 0, AR_NotYetIntroduced, AR_Deprecated, AR_Unavailable }; /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. /// /// Note: There are objects tacked on before the *beginning* of Decl /// (and its subclasses) in its Decl::operator new(). Proper alignment /// of all subclasses (not requiring more than the alignment of Decl) is /// asserted in DeclBase.cpp. class alignas(8) Decl { public: /// Lists the kind of concrete classes of Decl. enum Kind { #define DECL(DERIVED, BASE) DERIVED, #define ABSTRACT_DECL(DECL) #define DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END, #define LAST_DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END #include "clang/AST/DeclNodes.inc" }; /// A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). struct EmptyShell {}; /// IdentifierNamespace - The different namespaces in which /// declarations may appear. According to C99 6.2.3, there are /// four namespaces, labels, tags, members and ordinary /// identifiers. C++ describes lookup completely differently: /// certain lookups merely "ignore" certain kinds of declarations, /// usually based on whether the declaration is of a type, etc. /// /// These are meant as bitmasks, so that searches in /// C++ can look into the "tag" namespace during ordinary lookup. /// /// Decl currently provides 15 bits of IDNS bits. enum IdentifierNamespace { /// Labels, declared with 'x:' and referenced with 'goto x'. IDNS_Label = 0x0001, /// Tags, declared with 'struct foo;' and referenced with /// 'struct foo'. All tags are also types. This is what /// elaborated-type-specifiers look for in C. /// This also contains names that conflict with tags in the /// same scope but that are otherwise ordinary names (non-type /// template parameters and indirect field declarations). IDNS_Tag = 0x0002, /// Types, declared with 'struct foo', typedefs, etc. /// This is what elaborated-type-specifiers look for in C++, /// but note that it's ill-formed to find a non-tag. IDNS_Type = 0x0004, /// Members, declared with object declarations within tag /// definitions. In C, these can only be found by "qualified" /// lookup in member expressions. In C++, they're found by /// normal lookup. IDNS_Member = 0x0008, /// Namespaces, declared with 'namespace foo {}'. /// Lookup for nested-name-specifiers find these. IDNS_Namespace = 0x0010, /// Ordinary names. In C, everything that's not a label, tag, /// member, or function-local extern ends up here. IDNS_Ordinary = 0x0020, /// Objective C \@protocol. IDNS_ObjCProtocol = 0x0040, /// This declaration is a friend function. A friend function /// declaration is always in this namespace but may also be in /// IDNS_Ordinary if it was previously declared. IDNS_OrdinaryFriend = 0x0080, /// This declaration is a friend class. A friend class /// declaration is always in this namespace but may also be in /// IDNS_Tag|IDNS_Type if it was previously declared. IDNS_TagFriend = 0x0100, /// This declaration is a using declaration. A using declaration /// *introduces* a number of other declarations into the current /// scope, and those declarations use the IDNS of their targets, /// but the actual using declarations go in this namespace. IDNS_Using = 0x0200, /// This declaration is a C++ operator declared in a non-class /// context. All such operators are also in IDNS_Ordinary. /// C++ lexical operator lookup looks for these. IDNS_NonMemberOperator = 0x0400, /// This declaration is a function-local extern declaration of a /// variable or function. This may also be IDNS_Ordinary if it /// has been declared outside any function. These act mostly like /// invisible friend declarations, but are also visible to unqualified /// lookup within the scope of the declaring function. IDNS_LocalExtern = 0x0800, /// This declaration is an OpenMP user defined reduction construction. IDNS_OMPReduction = 0x1000 }; /// ObjCDeclQualifier - 'Qualifiers' written next to the return and /// parameter types in method declarations. Other than remembering /// them and mangling them into the method's signature string, these /// are ignored by the compiler; they are consumed by certain /// remote-messaging frameworks. /// /// in, inout, and out are mutually exclusive and apply only to /// method parameters. bycopy and byref are mutually exclusive and /// apply only to method parameters (?). oneway applies only to /// results. All of these expect their corresponding parameter to /// have a particular type. None of this is currently enforced by /// clang. /// /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier. enum ObjCDeclQualifier { OBJC_TQ_None = 0x0, OBJC_TQ_In = 0x1, OBJC_TQ_Inout = 0x2, OBJC_TQ_Out = 0x4, OBJC_TQ_Bycopy = 0x8, OBJC_TQ_Byref = 0x10, OBJC_TQ_Oneway = 0x20, /// The nullability qualifier is set when the nullability of the /// result or parameter was expressed via a context-sensitive /// keyword. OBJC_TQ_CSNullability = 0x40 }; /// The kind of ownership a declaration has, for visibility purposes. /// This enumeration is designed such that higher values represent higher /// levels of name hiding. enum class ModuleOwnershipKind : unsigned { /// This declaration is not owned by a module. Unowned, /// This declaration has an owning module, but is globally visible /// (typically because its owning module is visible and we know that /// modules cannot later become hidden in this compilation). /// After serialization and deserialization, this will be converted /// to VisibleWhenImported. Visible, /// This declaration has an owning module, and is visible when that /// module is imported. VisibleWhenImported, /// This declaration has an owning module, but is only visible to /// lookups that occur within that module. ModulePrivate }; protected: /// The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// /// The extra two bits are used for the ModuleOwnershipKind. llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; struct MultipleDC { DeclContext *SemanticDC; DeclContext *LexicalDC; }; /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the Decl was declared. /// For declarations with C++ scope specifiers, it contains a MultipleDC* /// with the context where it semantically belongs (SemanticDC) and the /// context where it was lexically declared (LexicalDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace llvm::PointerUnion DeclCtx; bool isInSemaDC() const { return DeclCtx.is(); } bool isOutOfSemaDC() const { return DeclCtx.is(); } MultipleDC *getMultipleDC() const { return DeclCtx.get(); } DeclContext *getSemanticDC() const { return DeclCtx.get(); } /// Loc - The location of this decl. SourceLocation Loc; /// DeclKind - This indicates which class this is. unsigned DeclKind : 7; /// InvalidDecl - This indicates a semantic error occurred. unsigned InvalidDecl : 1; /// HasAttrs - This indicates whether the decl has attributes or not. unsigned HasAttrs : 1; /// Implicit - Whether this declaration was implicitly generated by /// the implementation rather than explicitly written by the user. unsigned Implicit : 1; /// Whether this declaration was "used", meaning that a definition is /// required. unsigned Used : 1; /// Whether this declaration was "referenced". /// The difference with 'Used' is whether the reference appears in a /// evaluated context or not, e.g. functions used in uninstantiated templates /// are regarded as "referenced" but not "used". unsigned Referenced : 1; /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. unsigned TopLevelDeclInObjCContainer : 1; /// Whether statistic collection is enabled. static bool StatisticsEnabled; protected: friend class ASTDeclReader; friend class ASTDeclWriter; friend class ASTNodeImporter; friend class ASTReader; friend class CXXClassMemberWrapper; friend class LinkageComputer; template friend class Redeclarable; /// Access - Used by C++ decls for the access specifier. // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum unsigned Access : 2; /// Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 13; /// If 0, we have not computed the linkage of this declaration. /// Otherwise, it is the linkage + 1. mutable unsigned CacheValidAndLinkage : 3; /// Allocate memory for a deserialized declaration. /// /// This routine must be used to allocate memory for any declaration that is /// deserialized from a module file. /// /// \param Size The size of the allocated object. /// \param Ctx The context in which we will allocate memory. /// \param ID The global ID of the deserialized declaration. /// \param Extra The amount of extra space to allocate after the object. void *operator new(std::size_t Size, const ASTContext &Ctx, unsigned ID, std::size_t Extra = 0); /// Allocate memory for a non-deserialized declaration. void *operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra = 0); private: bool AccessDeclContextSanity() const; /// Get the module ownership kind to use for a local lexical child of \p DC, /// which may be either a local or (rarely) an imported declaration. static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) { if (DC) { auto *D = cast(DC); auto MOK = D->getModuleOwnershipKind(); if (MOK != ModuleOwnershipKind::Unowned && (!D->isFromASTFile() || D->hasLocalOwningModuleStorage())) return MOK; // If D is not local and we have no local module storage, then we don't // need to track module ownership at all. } return ModuleOwnershipKind::Unowned; } protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)), DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } Decl(Kind DK, EmptyShell Empty) : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } virtual ~Decl(); /// Update a potentially out-of-date declaration. void updateOutOfDate(IdentifierInfo &II) const; Linkage getCachedLinkage() const { return Linkage(CacheValidAndLinkage - 1); } void setCachedLinkage(Linkage L) const { CacheValidAndLinkage = L + 1; } bool hasCachedLinkage() const { return CacheValidAndLinkage; } public: /// Source range that this declaration covers. virtual SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocation(), getLocation()); } SourceLocation getBeginLoc() const LLVM_READONLY { return getSourceRange().getBegin(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSourceRange().getEnd(); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } Kind getKind() const { return static_cast(DeclKind); } const char *getDeclKindName() const; Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); } const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();} DeclContext *getDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->SemanticDC; } const DeclContext *getDeclContext() const { return const_cast(this)->getDeclContext(); } /// Find the innermost non-closure ancestor of this declaration, /// walking up through blocks, lambdas, etc. If that ancestor is /// not a code context (!isFunctionOrMethod()), returns null. /// /// A declaration may be its own non-closure context. Decl *getNonClosureContext(); const Decl *getNonClosureContext() const { return const_cast(this)->getNonClosureContext(); } TranslationUnitDecl *getTranslationUnitDecl(); const TranslationUnitDecl *getTranslationUnitDecl() const { return const_cast(this)->getTranslationUnitDecl(); } bool isInAnonymousNamespace() const; bool isInStdNamespace() const; ASTContext &getASTContext() const LLVM_READONLY; void setAccess(AccessSpecifier AS) { Access = AS; assert(AccessDeclContextSanity()); } AccessSpecifier getAccess() const { assert(AccessDeclContextSanity()); return AccessSpecifier(Access); } /// Retrieve the access specifier for this declaration, even though /// it may not yet have been properly set. AccessSpecifier getAccessUnsafe() const { return AccessSpecifier(Access); } bool hasAttrs() const { return HasAttrs; } void setAttrs(const AttrVec& Attrs) { return setAttrsImpl(Attrs, getASTContext()); } AttrVec &getAttrs() { return const_cast(const_cast(this)->getAttrs()); } const AttrVec &getAttrs() const; void dropAttrs(); void addAttr(Attr *A); using attr_iterator = AttrVec::const_iterator; using attr_range = llvm::iterator_range; attr_range attrs() const { return attr_range(attr_begin(), attr_end()); } attr_iterator attr_begin() const { return hasAttrs() ? getAttrs().begin() : nullptr; } attr_iterator attr_end() const { return hasAttrs() ? getAttrs().end() : nullptr; } template void dropAttr() { if (!HasAttrs) return; AttrVec &Vec = getAttrs(); Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa), Vec.end()); if (Vec.empty()) HasAttrs = false; } template llvm::iterator_range> specific_attrs() const { return llvm::make_range(specific_attr_begin(), specific_attr_end()); } template specific_attr_iterator specific_attr_begin() const { return specific_attr_iterator(attr_begin()); } template specific_attr_iterator specific_attr_end() const { return specific_attr_iterator(attr_end()); } template T *getAttr() const { return hasAttrs() ? getSpecificAttr(getAttrs()) : nullptr; } template bool hasAttr() const { return hasAttrs() && hasSpecificAttr(getAttrs()); } /// getMaxAlignment - return the maximum alignment specified by attributes /// on this decl, 0 if there are none. unsigned getMaxAlignment() const; /// setInvalidDecl - Indicates the Decl had a semantic error. This /// allows for graceful error recovery. void setInvalidDecl(bool Invalid = true); bool isInvalidDecl() const { return (bool) InvalidDecl; } /// isImplicit - Indicates whether the declaration was implicitly /// generated by the implementation. If false, this declaration /// was written explicitly in the source code. bool isImplicit() const { return Implicit; } void setImplicit(bool I = true) { Implicit = I; } /// Whether *any* (re-)declaration of the entity was used, meaning that /// a definition is required. /// /// \param CheckUsedAttr When true, also consider the "used" attribute /// (in addition to the "used" bit set by \c setUsed()) when determining /// whether the function is used. bool isUsed(bool CheckUsedAttr = true) const; /// Set whether the declaration is used, in the sense of odr-use. /// /// This should only be used immediately after creating a declaration. /// It intentionally doesn't notify any listeners. void setIsUsed() { getCanonicalDecl()->Used = true; } /// Mark the declaration used, in the sense of odr-use. /// /// This notifies any mutation listeners in addition to setting a bit /// indicating the declaration is used. void markUsed(ASTContext &C); /// Whether any declaration of this entity was referenced. bool isReferenced() const; /// Whether this declaration was referenced. This should not be relied /// upon for anything other than debugging. bool isThisDeclarationReferenced() const { return Referenced; } void setReferenced(bool R = true) { Referenced = R; } /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. bool isTopLevelDeclInObjCContainer() const { return TopLevelDeclInObjCContainer; } void setTopLevelDeclInObjCContainer(bool V = true) { TopLevelDeclInObjCContainer = V; } /// Looks on this and related declarations for an applicable /// external source symbol attribute. ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const; /// Whether this declaration was marked as being private to the /// module in which it was defined. bool isModulePrivate() const { return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } /// Whether this declaration is exported (by virtue of being lexically /// within an ExportDecl or by being a NamespaceDecl). bool isExported() const; /// Return true if this declaration has an attribute which acts as /// definition of the entity, such as 'alias' or 'ifunc'. bool hasDefiningAttr() const; /// Return this declaration's defining attribute if it has one. const Attr *getDefiningAttr() const; protected: /// Specify that this declaration was marked as being private /// to the module in which it was defined. void setModulePrivate() { // The module-private specifier has no effect on unowned declarations. // FIXME: We should track this in some way for source fidelity. if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned) return; setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } /// Set the owning module ID. void setOwningModuleID(unsigned ID) { assert(isFromASTFile() && "Only works on a deserialized declaration"); *((unsigned*)this - 2) = ID; } public: /// Determine the availability of the given declaration. /// /// This routine will determine the most restrictive availability of /// the given declaration (e.g., preferring 'unavailable' to /// 'deprecated'). /// /// \param Message If non-NULL and the result is not \c /// AR_Available, will be set to a (possibly empty) message /// describing why the declaration has not been introduced, is /// deprecated, or is unavailable. /// /// \param EnclosingVersion The version to compare with. If empty, assume the /// deployment target version. /// /// \param RealizedPlatform If non-NULL and the availability result is found /// in an available attribute it will set to the platform which is written in /// the available attribute. AvailabilityResult getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple(), StringRef *RealizedPlatform = nullptr) const; /// Retrieve the version of the target platform in which this /// declaration was introduced. /// /// \returns An empty version tuple if this declaration has no 'introduced' /// availability attributes, or the version tuple that's specified in the /// attribute otherwise. VersionTuple getVersionIntroduced() const; /// Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, /// this will be set to the message describing why the declaration /// was deprecated (which may be empty). bool isDeprecated(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Deprecated; } /// Determine whether this declaration is marked 'unavailable'. /// /// \param Message If non-NULL and the declaration is unavailable, /// this will be set to the message describing why the declaration /// was made unavailable (which may be empty). bool isUnavailable(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Unavailable; } /// Determine whether this is a weak-imported symbol. /// /// Weak-imported symbols are typically marked with the /// 'weak_import' attribute, but may also be marked with an /// 'availability' attribute where we're targing a platform prior to /// the introduction of this feature. bool isWeakImported() const; /// Determines whether this symbol can be weak-imported, /// e.g., whether it would be well-formed to add the weak_import /// attribute. /// /// \param IsDefinition Set to \c true to indicate that this /// declaration cannot be weak-imported because it has a definition. bool canBeWeakImported(bool &IsDefinition) const; /// Determine whether this declaration came from an AST file (such as /// a precompiled header or module) rather than having been parsed. bool isFromASTFile() const { return FromASTFile; } /// Retrieve the global declaration ID associated with this /// declaration, which specifies where this Decl was loaded from. unsigned getGlobalID() const { if (isFromASTFile()) return *((const unsigned*)this - 1); return 0; } /// Retrieve the global ID of the module that owns this particular /// declaration. unsigned getOwningModuleID() const { if (isFromASTFile()) return *((const unsigned*)this - 2); return 0; } private: Module *getOwningModuleSlow() const; protected: bool hasLocalOwningModuleStorage() const; public: /// Get the imported owning module, if this decl is from an imported /// (non-local) module. Module *getImportedOwningModule() const { if (!isFromASTFile() || !hasOwningModule()) return nullptr; return getOwningModuleSlow(); } /// Get the local owning module, if known. Returns nullptr if owner is /// not yet known or declaration is not from a module. Module *getLocalOwningModule() const { if (isFromASTFile() || !hasOwningModule()) return nullptr; assert(hasLocalOwningModuleStorage() && "owned local decl but no local module storage"); return reinterpret_cast(this)[-1]; } void setLocalOwningModule(Module *M) { assert(!isFromASTFile() && hasOwningModule() && hasLocalOwningModuleStorage() && "should not have a cached owning module"); reinterpret_cast(this)[-1] = M; } /// Is this declaration owned by some module? bool hasOwningModule() const { return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; } /// Get the module that owns this declaration (for visibility purposes). Module *getOwningModule() const { return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } /// Get the module that owns this declaration for linkage purposes. /// There only ever is such a module under the C++ Modules TS. /// /// \param IgnoreLinkage Ignore the linkage of the entity; assume that /// all declarations in a global module fragment are unowned. Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; /// Determine whether this declaration might be hidden from name /// lookup. Note that the declaration might be visible even if this returns /// \c false, if the owning module is visible within the query context. // FIXME: Rename this to make it clearer what it does. bool isHidden() const { return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible; } /// Set that this declaration is globally visible, even if it came from a /// module that is not visible. void setVisibleDespiteOwningModule() { if (isHidden()) setModuleOwnershipKind(ModuleOwnershipKind::Visible); } /// Get the kind of module ownership for this declaration. ModuleOwnershipKind getModuleOwnershipKind() const { return NextInContextAndBits.getInt(); } /// Set whether this declaration is hidden from name lookup. void setModuleOwnershipKind(ModuleOwnershipKind MOK) { assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned && MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() && !hasLocalOwningModuleStorage()) && "no storage available for owning module for this declaration"); NextInContextAndBits.setInt(MOK); } unsigned getIdentifierNamespace() const { return IdentifierNamespace; } bool isInIdentifierNamespace(unsigned NS) const { return getIdentifierNamespace() & NS; } static unsigned getIdentifierNamespaceForKind(Kind DK); bool hasTagIdentifierNamespace() const { return isTagIdentifierNamespace(getIdentifierNamespace()); } static bool isTagIdentifierNamespace(unsigned NS) { // TagDecls have Tag and Type set and may also have TagFriend. return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); } /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from /// getDeclContext() (SemanticDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace DeclContext *getLexicalDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->LexicalDC; } const DeclContext *getLexicalDeclContext() const { return const_cast(this)->getLexicalDeclContext(); } /// Determine whether this declaration is declared out of line (outside its /// semantic context). virtual bool isOutOfLine() const; /// setDeclContext - Set both the semantic and lexical DeclContext /// to DC. void setDeclContext(DeclContext *DC); void setLexicalDeclContext(DeclContext *DC); /// Determine whether this declaration is a templated entity (whether it is // within the scope of a template parameter). bool isTemplated() const; /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this /// scoped decl is defined outside the current function or method. This is /// roughly global variables and functions, but also handles enums (which /// could be defined inside or outside a function etc). bool isDefinedOutsideFunctionOrMethod() const { return getParentFunctionOrMethod() == nullptr; } /// Returns true if this declaration lexically is inside a function. /// It recognizes non-defining declarations as well as members of local /// classes: /// \code /// void foo() { void bar(); } /// void foo2() { class ABC { void bar(); }; } /// \endcode bool isLexicallyWithinFunctionOrMethod() const; /// If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. const DeclContext *getParentFunctionOrMethod() const; DeclContext *getParentFunctionOrMethod() { return const_cast( const_cast(this)->getParentFunctionOrMethod()); } /// Retrieves the "canonical" declaration of the given declaration. virtual Decl *getCanonicalDecl() { return this; } const Decl *getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } /// Whether this particular Decl is a canonical one. bool isCanonicalDecl() const { return getCanonicalDecl() == this; } protected: /// Returns the next redeclaration or itself if this is the only decl. /// /// Decl subclasses that can be redeclared should override this method so that /// Decl::redecl_iterator can iterate over them. virtual Decl *getNextRedeclarationImpl() { return this; } /// Implementation of getPreviousDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getPreviousDeclImpl() { return nullptr; } /// Implementation of getMostRecentDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getMostRecentDeclImpl() { return this; } public: /// Iterates through all the redeclarations of the same decl. class redecl_iterator { /// Current - The current declaration. Decl *Current = nullptr; Decl *Starter; public: using value_type = Decl *; using reference = const value_type &; using pointer = const value_type *; using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; redecl_iterator() = default; explicit redecl_iterator(Decl *C) : Current(C), Starter(C) {} reference operator*() const { return Current; } value_type operator->() const { return Current; } redecl_iterator& operator++() { assert(Current && "Advancing while iterator has reached end"); // Get either previous decl or latest decl. Decl *Next = Current->getNextRedeclarationImpl(); assert(Next && "Should return next redeclaration or itself, never null!"); Current = (Next != Starter) ? Next : nullptr; return *this; } redecl_iterator operator++(int) { redecl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(redecl_iterator x, redecl_iterator y) { return x.Current == y.Current; } friend bool operator!=(redecl_iterator x, redecl_iterator y) { return x.Current != y.Current; } }; using redecl_range = llvm::iterator_range; /// Returns an iterator range for all the redeclarations of the same /// decl. It will iterate at least once (when this decl is the only one). redecl_range redecls() const { return redecl_range(redecls_begin(), redecls_end()); } redecl_iterator redecls_begin() const { return redecl_iterator(const_cast(this)); } redecl_iterator redecls_end() const { return redecl_iterator(); } /// Retrieve the previous declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. Decl *getPreviousDecl() { return getPreviousDeclImpl(); } /// Retrieve the most recent declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. const Decl *getPreviousDecl() const { return const_cast(this)->getPreviousDeclImpl(); } /// True if this is the first declaration in its redeclaration chain. bool isFirstDecl() const { return getPreviousDecl() == nullptr; } /// Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } /// Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). const Decl *getMostRecentDecl() const { return const_cast(this)->getMostRecentDeclImpl(); } /// getBody - If this Decl represents a declaration for a body of code, /// such as a function or method definition, this method returns the /// top-level Stmt* of that body. Otherwise this method returns null. virtual Stmt* getBody() const { return nullptr; } /// Returns true if this \c Decl represents a declaration for a body of /// code, such as a function or method definition. /// Note that \c hasBody can also return true if any redeclaration of this /// \c Decl represents a declaration for a body of code. virtual bool hasBody() const { return getBody() != nullptr; } /// getBodyRBrace - Gets the right brace of the body, if a body exists. /// This works whether the body is a CompoundStmt or a CXXTryStmt. SourceLocation getBodyRBrace() const; // global temp stats (until we have a per-module visitor) static void add(Kind k); static void EnableStatistics(); static void PrintStats(); /// isTemplateParameter - Determines whether this declaration is a /// template parameter. bool isTemplateParameter() const; /// isTemplateParameter - Determines whether this declaration is a /// template parameter pack. bool isTemplateParameterPack() const; /// Whether this declaration is a parameter pack. bool isParameterPack() const; /// returns true if this declaration is a template bool isTemplateDecl() const; /// Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const { return (DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction) || DeclKind == FunctionTemplate; } /// If this is a declaration that describes some template, this /// method returns that template declaration. TemplateDecl *getDescribedTemplate() const; /// Returns the function itself, or the templated function if this is a /// function template. FunctionDecl *getAsFunction() LLVM_READONLY; const FunctionDecl *getAsFunction() const { return const_cast(this)->getAsFunction(); } /// Changes the namespace of this declaration to reflect that it's /// a function-local extern declaration. /// /// These declarations appear in the lexical context of the extern /// declaration, but in the semantic context of the enclosing namespace /// scope. void setLocalExternDecl() { Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~IDNS_Ordinary; // It's OK for the declaration to still have the "invisible friend" flag or // the "conflicts with tag declarations in this scope" flag for the outer // scope. assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 && "namespace is not ordinary"); IdentifierNamespace |= IDNS_LocalExtern; if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) IdentifierNamespace |= IDNS_Ordinary; } /// Determine whether this is a block-scope declaration with linkage. /// This will either be a local variable declaration declared 'extern', or a /// local function declaration. bool isLocalExternDecl() { return IdentifierNamespace & IDNS_LocalExtern; } /// Changes the namespace of this declaration to reflect that it's /// the object of a friend declaration. /// /// These declarations appear in the lexical context of the friending /// class, but in the semantic context of the actual entity. This property /// applies only to a specific decl object; other redeclarations of the /// same entity may not (and probably don't) share this property. void setObjectOfFriendDecl(bool PerformFriendInjection = false) { unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type); if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) IdentifierNamespace |= IDNS_Tag | IDNS_Type; } if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) IdentifierNamespace |= IDNS_Ordinary; } } enum FriendObjectKind { FOK_None, ///< Not a friend object. FOK_Declared, ///< A friend of a previously-declared entity. FOK_Undeclared ///< A friend of a previously-undeclared entity. }; /// Determines whether this declaration is the object of a /// friend declaration and, if so, what kind. /// /// There is currently no direct way to find the associated FriendDecl. FriendObjectKind getFriendObjectKind() const { unsigned mask = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); if (!mask) return FOK_None; return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared : FOK_Undeclared); } /// Specifies that this declaration is a C++ overloaded non-member. void setNonMemberOperator() { assert(getKind() == Function || getKind() == FunctionTemplate); assert((IdentifierNamespace & IDNS_Ordinary) && "visible non-member operators should be in ordinary namespace"); IdentifierNamespace |= IDNS_NonMemberOperator; } static bool classofKind(Kind K) { return true; } static DeclContext *castToDeclContext(const Decl *); static Decl *castFromDeclContext(const DeclContext *); void print(raw_ostream &Out, unsigned Indentation = 0, bool PrintInstantiation = false) const; void print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) const; static void printGroup(Decl** Begin, unsigned NumDecls, raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); // Debuggers don't usually respect default arguments. void dump() const; // Same as dump(), but forces color printing. void dumpColor() const; void dump(raw_ostream &Out, bool Deserialize = false) const; /// \return Unique reproducible object identifier int64_t getID() const; /// Looks through the Decl's underlying type to extract a FunctionType /// when possible. Will return null if the type underlying the Decl does not /// have a FunctionType. const FunctionType *getFunctionType(bool BlocksToo = true) const; private: void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, ASTContext &Ctx); protected: ASTMutationListener *getASTMutationListener() const; }; /// Determine whether two declarations declare the same entity. inline bool declaresSameEntity(const Decl *D1, const Decl *D2) { if (!D1 || !D2) return false; if (D1 == D2) return true; return D1->getCanonicalDecl() == D2->getCanonicalDecl(); } /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when /// doing something to a specific decl. class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { const Decl *TheDecl; SourceLocation Loc; SourceManager &SM; const char *Message; public: PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} void print(raw_ostream &OS) const override; }; /// The results of name lookup within a DeclContext. This is either a /// single result (with no stable storage) or a collection of results (with /// stable storage provided by the lookup table). class DeclContextLookupResult { using ResultTy = ArrayRef; ResultTy Result; // If there is only one lookup result, it would be invalidated by // reallocations of the name table, so store it separately. NamedDecl *Single = nullptr; static NamedDecl *const SingleElementDummyList; public: DeclContextLookupResult() = default; DeclContextLookupResult(ArrayRef Result) : Result(Result) {} DeclContextLookupResult(NamedDecl *Single) : Result(SingleElementDummyList), Single(Single) {} class iterator; using IteratorBase = llvm::iterator_adaptor_base; class iterator : public IteratorBase { value_type SingleElement; public: explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} reference operator*() const { return SingleElement ? SingleElement : IteratorBase::operator*(); } }; using const_iterator = iterator; using pointer = iterator::pointer; using reference = iterator::reference; iterator begin() const { return iterator(Result.begin(), Single); } iterator end() const { return iterator(Result.end(), Single); } bool empty() const { return Result.empty(); } pointer data() const { return Single ? &Single : Result.data(); } size_t size() const { return Single ? 1 : Result.size(); } reference front() const { return Single ? Single : Result.front(); } reference back() const { return Single ? Single : Result.back(); } reference operator[](size_t N) const { return Single ? Single : Result[N]; } // FIXME: Remove this from the interface DeclContextLookupResult slice(size_t N) const { DeclContextLookupResult Sliced = Result.slice(N); Sliced.Single = Single; return Sliced; } }; /// DeclContext - This is used only as base class of specific decl types that /// can act as declaration contexts. These decls are (only the top classes /// that directly derive from DeclContext are mentioned, not their subclasses): /// /// TranslationUnitDecl /// ExternCContext /// NamespaceDecl /// TagDecl /// OMPDeclareReductionDecl /// FunctionDecl /// ObjCMethodDecl /// ObjCContainerDecl /// LinkageSpecDecl /// ExportDecl /// BlockDecl /// CapturedDecl class DeclContext { /// For makeDeclVisibleInContextImpl friend class ASTDeclReader; /// For reconcileExternalVisibleStorage, CreateStoredDeclsMap, /// hasNeedToReconcileExternalVisibleStorage friend class ExternalASTSource; /// For CreateStoredDeclsMap friend class DependentDiagnostic; /// For hasNeedToReconcileExternalVisibleStorage, /// hasLazyLocalLexicalLookups, hasLazyExternalLexicalLookups friend class ASTWriter; // We use uint64_t in the bit-fields below since some bit-fields // cross the unsigned boundary and this breaks the packing. /// Stores the bits used by DeclContext. /// If modified NumDeclContextBit, the ctor of DeclContext and the accessor /// methods in DeclContext should be updated appropriately. class DeclContextBitfields { friend class DeclContext; /// DeclKind - This indicates which class this is. uint64_t DeclKind : 7; /// Whether this declaration context also has some external /// storage that contains additional declarations that are lexically /// part of this context. mutable uint64_t ExternalLexicalStorage : 1; /// Whether this declaration context also has some external /// storage that contains additional declarations that are visible /// in this context. mutable uint64_t ExternalVisibleStorage : 1; /// Whether this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. mutable uint64_t NeedToReconcileExternalVisibleStorage : 1; /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. mutable uint64_t HasLazyLocalLexicalLookups : 1; /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. mutable uint64_t HasLazyExternalLexicalLookups : 1; /// If \c true, lookups should only return identifier from /// DeclContext scope (for example TranslationUnit). Used in /// LookupQualifiedName() mutable uint64_t UseQualifiedLookup : 1; }; /// Number of bits in DeclContextBitfields. enum { NumDeclContextBits = 13 }; /// Stores the bits used by TagDecl. /// If modified NumTagDeclBits and the accessor /// methods in TagDecl should be updated appropriately. class TagDeclBitfields { friend class TagDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; /// The TagKind enum. uint64_t TagDeclKind : 3; /// True if this is a definition ("struct foo {};"), false if it is a /// declaration ("struct foo;"). It is not considered a definition /// until the definition has been fully processed. uint64_t IsCompleteDefinition : 1; /// True if this is currently being defined. uint64_t IsBeingDefined : 1; /// True if this tag declaration is "embedded" (i.e., defined or declared /// for the very first time) in the syntax of a declarator. uint64_t IsEmbeddedInDeclarator : 1; /// True if this tag is free standing, e.g. "struct foo;". uint64_t IsFreeStanding : 1; /// Indicates whether it is possible for declarations of this kind /// to have an out-of-date definition. /// /// This option is only enabled when modules are enabled. uint64_t MayHaveOutOfDateDef : 1; /// Has the full definition of this type been required by a use somewhere in /// the TU. uint64_t IsCompleteDefinitionRequired : 1; }; /// Number of non-inherited bits in TagDeclBitfields. enum { NumTagDeclBits = 9 }; /// Stores the bits used by EnumDecl. /// If modified NumEnumDeclBit and the accessor /// methods in EnumDecl should be updated appropriately. class EnumDeclBitfields { friend class EnumDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in TagDeclBitfields. uint64_t : NumTagDeclBits; /// Width in bits required to store all the non-negative /// enumerators of this enum. uint64_t NumPositiveBits : 8; /// Width in bits required to store all the negative /// enumerators of this enum. uint64_t NumNegativeBits : 8; /// True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. uint64_t IsScoped : 1; /// If this tag declaration is a scoped enum, /// then this is true if the scoped enum was declared using the class /// tag, false if it was declared with the struct tag. No meaning is /// associated if this tag declaration is not a scoped enum. uint64_t IsScopedUsingClassTag : 1; /// True if this is an enumeration with fixed underlying type. Only /// possible in C++11, Microsoft extensions, or Objective C mode. uint64_t IsFixed : 1; /// True if a valid hash is stored in ODRHash. uint64_t HasODRHash : 1; }; /// Number of non-inherited bits in EnumDeclBitfields. enum { NumEnumDeclBits = 20 }; /// Stores the bits used by RecordDecl. /// If modified NumRecordDeclBits and the accessor /// methods in RecordDecl should be updated appropriately. class RecordDeclBitfields { friend class RecordDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in TagDeclBitfields. uint64_t : NumTagDeclBits; /// This is true if this struct ends with a flexible /// array member (e.g. int X[]) or if this union contains a struct that does. /// If so, this cannot be contained in arrays or other structs as a member. uint64_t HasFlexibleArrayMember : 1; /// Whether this is the type of an anonymous struct or union. uint64_t AnonymousStructOrUnion : 1; /// This is true if this struct has at least one member /// containing an Objective-C object pointer type. uint64_t HasObjectMember : 1; /// This is true if struct has at least one member of /// 'volatile' type. uint64_t HasVolatileMember : 1; /// Whether the field declarations of this record have been loaded /// from external storage. To avoid unnecessary deserialization of /// methods/nested types we allow deserialization of just the fields /// when needed. mutable uint64_t LoadedFieldsFromExternalStorage : 1; /// Basic properties of non-trivial C structs. uint64_t NonTrivialToPrimitiveDefaultInitialize : 1; uint64_t NonTrivialToPrimitiveCopy : 1; uint64_t NonTrivialToPrimitiveDestroy : 1; /// Indicates whether this struct is destroyed in the callee. uint64_t ParamDestroyedInCallee : 1; /// Represents the way this type is passed to a function. uint64_t ArgPassingRestrictions : 2; }; /// Number of non-inherited bits in RecordDeclBitfields. enum { NumRecordDeclBits = 11 }; /// Stores the bits used by OMPDeclareReductionDecl. /// If modified NumOMPDeclareReductionDeclBits and the accessor /// methods in OMPDeclareReductionDecl should be updated appropriately. class OMPDeclareReductionDeclBitfields { friend class OMPDeclareReductionDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; /// Kind of initializer, /// function call or omp_priv initializtion. uint64_t InitializerKind : 2; }; /// Number of non-inherited bits in OMPDeclareReductionDeclBitfields. enum { NumOMPDeclareReductionDeclBits = 2 }; /// Stores the bits used by FunctionDecl. /// If modified NumFunctionDeclBits and the accessor /// methods in FunctionDecl and CXXDeductionGuideDecl /// (for IsCopyDeductionCandidate) should be updated appropriately. class FunctionDeclBitfields { friend class FunctionDecl; /// For IsCopyDeductionCandidate friend class CXXDeductionGuideDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; uint64_t SClass : 3; uint64_t IsInline : 1; uint64_t IsInlineSpecified : 1; /// This is shared by CXXConstructorDecl, /// CXXConversionDecl, and CXXDeductionGuideDecl. uint64_t IsExplicitSpecified : 1; uint64_t IsVirtualAsWritten : 1; uint64_t IsPure : 1; uint64_t HasInheritedPrototype : 1; uint64_t HasWrittenPrototype : 1; uint64_t IsDeleted : 1; /// Used by CXXMethodDecl uint64_t IsTrivial : 1; /// This flag indicates whether this function is trivial for the purpose of /// calls. This is meaningful only when this function is a copy/move /// constructor or a destructor. uint64_t IsTrivialForCall : 1; /// Used by CXXMethodDecl uint64_t IsDefaulted : 1; /// Used by CXXMethodDecl uint64_t IsExplicitlyDefaulted : 1; uint64_t HasImplicitReturnZero : 1; uint64_t IsLateTemplateParsed : 1; uint64_t IsConstexpr : 1; uint64_t InstantiationIsPending : 1; /// Indicates if the function uses __try. uint64_t UsesSEHTry : 1; /// Indicates if the function was a definition /// but its body was skipped. uint64_t HasSkippedBody : 1; /// Indicates if the function declaration will /// have a body, once we're done parsing it. uint64_t WillHaveBody : 1; /// Indicates that this function is a multiversioned /// function using attribute 'target'. uint64_t IsMultiVersion : 1; /// [C++17] Only used by CXXDeductionGuideDecl. Indicates that /// the Deduction Guide is the implicitly generated 'copy /// deduction candidate' (is used during overload resolution). uint64_t IsCopyDeductionCandidate : 1; /// Store the ODRHash after first calculation. uint64_t HasODRHash : 1; }; /// Number of non-inherited bits in FunctionDeclBitfields. enum { NumFunctionDeclBits = 25 }; /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor /// methods in CXXConstructorDecl should be updated appropriately. class CXXConstructorDeclBitfields { friend class CXXConstructorDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in FunctionDeclBitfields. uint64_t : NumFunctionDeclBits; /// 25 bits to fit in the remaining availible space. /// Note that this makes CXXConstructorDeclBitfields take /// exactly 64 bits and thus the width of NumCtorInitializers /// will need to be shrunk if some bit is added to NumDeclContextBitfields, /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. uint64_t NumCtorInitializers : 25; uint64_t IsInheritingConstructor : 1; }; /// Number of non-inherited bits in CXXConstructorDeclBitfields. enum { NumCXXConstructorDeclBits = 26 }; /// Stores the bits used by ObjCMethodDecl. /// If modified NumObjCMethodDeclBits and the accessor /// methods in ObjCMethodDecl should be updated appropriately. class ObjCMethodDeclBitfields { friend class ObjCMethodDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// The conventional meaning of this method; an ObjCMethodFamily. /// This is not serialized; instead, it is computed on demand and /// cached. mutable uint64_t Family : ObjCMethodFamilyBitWidth; /// instance (true) or class (false) method. uint64_t IsInstance : 1; uint64_t IsVariadic : 1; /// True if this method is the getter or setter for an explicit property. uint64_t IsPropertyAccessor : 1; /// Method has a definition. uint64_t IsDefined : 1; /// Method redeclaration in the same interface. uint64_t IsRedeclaration : 1; /// Is redeclared in the same interface. mutable uint64_t HasRedeclaration : 1; /// \@required/\@optional uint64_t DeclImplementation : 2; /// in, inout, etc. uint64_t objcDeclQualifier : 7; /// Indicates whether this method has a related result type. uint64_t RelatedResultType : 1; /// Whether the locations of the selector identifiers are in a /// "standard" position, a enum SelectorLocationsKind. uint64_t SelLocsKind : 2; /// Whether this method overrides any other in the class hierarchy. /// /// A method is said to override any method in the class's /// base classes, its protocols, or its categories' protocols, that has /// the same selector and is of the same kind (class or instance). /// A method in an implementation is not considered as overriding the same /// method in the interface or its categories. uint64_t IsOverriding : 1; /// Indicates if the method was a definition but its body was skipped. uint64_t HasSkippedBody : 1; }; /// Number of non-inherited bits in ObjCMethodDeclBitfields. enum { NumObjCMethodDeclBits = 24 }; /// Stores the bits used by ObjCContainerDecl. /// If modified NumObjCContainerDeclBits and the accessor /// methods in ObjCContainerDecl should be updated appropriately. class ObjCContainerDeclBitfields { friend class ObjCContainerDecl; /// For the bits in DeclContextBitfields uint32_t : NumDeclContextBits; // Not a bitfield but this saves space. // Note that ObjCContainerDeclBitfields is full. SourceLocation AtStart; }; /// Number of non-inherited bits in ObjCContainerDeclBitfields. /// Note that here we rely on the fact that SourceLocation is 32 bits /// wide. We check this with the static_assert in the ctor of DeclContext. enum { NumObjCContainerDeclBits = 64 - NumDeclContextBits }; /// Stores the bits used by LinkageSpecDecl. /// If modified NumLinkageSpecDeclBits and the accessor /// methods in LinkageSpecDecl should be updated appropriately. class LinkageSpecDeclBitfields { friend class LinkageSpecDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// The language for this linkage specification with values /// in the enum LinkageSpecDecl::LanguageIDs. uint64_t Language : 3; /// True if this linkage spec has braces. /// This is needed so that hasBraces() returns the correct result while the /// linkage spec body is being parsed. Once RBraceLoc has been set this is /// not used, so it doesn't need to be serialized. uint64_t HasBraces : 1; }; /// Number of non-inherited bits in LinkageSpecDeclBitfields. enum { NumLinkageSpecDeclBits = 4 }; /// Stores the bits used by BlockDecl. /// If modified NumBlockDeclBits and the accessor /// methods in BlockDecl should be updated appropriately. class BlockDeclBitfields { friend class BlockDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; uint64_t IsVariadic : 1; uint64_t CapturesCXXThis : 1; uint64_t BlockMissingReturnType : 1; uint64_t IsConversionFromLambda : 1; /// A bit that indicates this block is passed directly to a function as a /// non-escaping parameter. uint64_t DoesNotEscape : 1; }; /// Number of non-inherited bits in BlockDeclBitfields. enum { NumBlockDeclBits = 5 }; /// Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a /// dependent context). We maintain the invariant that, if the map /// contains an entry for a DeclarationName (and we haven't lazily /// omitted anything), then it contains all relevant entries for that /// name (modulo the hasExternalDecls() flag). mutable StoredDeclsMap *LookupPtr = nullptr; protected: /// This anonymous union stores the bits belonging to DeclContext and classes /// deriving from it. The goal is to use otherwise wasted /// space in DeclContext to store data belonging to derived classes. /// The space saved is especially significient when pointers are aligned /// to 8 bytes. In this case due to alignment requirements we have a /// little less than 8 bytes free in DeclContext which we can use. /// We check that none of the classes in this union is larger than /// 8 bytes with static_asserts in the ctor of DeclContext. union { DeclContextBitfields DeclContextBits; TagDeclBitfields TagDeclBits; EnumDeclBitfields EnumDeclBits; RecordDeclBitfields RecordDeclBits; OMPDeclareReductionDeclBitfields OMPDeclareReductionDeclBits; FunctionDeclBitfields FunctionDeclBits; CXXConstructorDeclBitfields CXXConstructorDeclBits; ObjCMethodDeclBitfields ObjCMethodDeclBits; ObjCContainerDeclBitfields ObjCContainerDeclBits; LinkageSpecDeclBitfields LinkageSpecDeclBits; BlockDeclBitfields BlockDeclBits; - - static_assert(sizeof(DeclContextBitfields) <= 8, - "DeclContextBitfields is larger than 8 bytes!"); - static_assert(sizeof(TagDeclBitfields) <= 8, - "TagDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(EnumDeclBitfields) <= 8, - "EnumDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(RecordDeclBitfields) <= 8, - "RecordDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(OMPDeclareReductionDeclBitfields) <= 8, - "OMPDeclareReductionDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(FunctionDeclBitfields) <= 8, - "FunctionDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(CXXConstructorDeclBitfields) <= 8, - "CXXConstructorDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCMethodDeclBitfields) <= 8, - "ObjCMethodDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCContainerDeclBitfields) <= 8, - "ObjCContainerDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(LinkageSpecDeclBitfields) <= 8, - "LinkageSpecDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(BlockDeclBitfields) <= 8, - "BlockDeclBitfields is larger than 8 bytes!"); }; + + static_assert(sizeof(DeclContextBitfields) <= 8, + "DeclContextBitfields is larger than 8 bytes!"); + static_assert(sizeof(TagDeclBitfields) <= 8, + "TagDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(EnumDeclBitfields) <= 8, + "EnumDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(RecordDeclBitfields) <= 8, + "RecordDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(OMPDeclareReductionDeclBitfields) <= 8, + "OMPDeclareReductionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionDeclBitfields) <= 8, + "FunctionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(CXXConstructorDeclBitfields) <= 8, + "CXXConstructorDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCMethodDeclBitfields) <= 8, + "ObjCMethodDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCContainerDeclBitfields) <= 8, + "ObjCContainerDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(LinkageSpecDeclBitfields) <= 8, + "LinkageSpecDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(BlockDeclBitfields) <= 8, + "BlockDeclBitfields is larger than 8 bytes!"); /// FirstDecl - The first declaration stored within this declaration /// context. mutable Decl *FirstDecl = nullptr; /// LastDecl - The last declaration stored within this declaration /// context. FIXME: We could probably cache this value somewhere /// outside of the DeclContext, to reduce the size of DeclContext by /// another pointer. mutable Decl *LastDecl = nullptr; /// Build up a chain of declarations. /// /// \returns the first/last pair of declarations. static std::pair BuildDeclChain(ArrayRef Decls, bool FieldsAlreadyLoaded); DeclContext(Decl::Kind K); public: ~DeclContext(); Decl::Kind getDeclKind() const { return static_cast(DeclContextBits.DeclKind); } const char *getDeclKindName() const; /// getParent - Returns the containing DeclContext. DeclContext *getParent() { return cast(this)->getDeclContext(); } const DeclContext *getParent() const { return const_cast(this)->getParent(); } /// getLexicalParent - Returns the containing lexical DeclContext. May be /// different from getParent, e.g.: /// /// namespace A { /// struct S; /// } /// struct A::S {}; // getParent() == namespace 'A' /// // getLexicalParent() == translation unit /// DeclContext *getLexicalParent() { return cast(this)->getLexicalDeclContext(); } const DeclContext *getLexicalParent() const { return const_cast(this)->getLexicalParent(); } DeclContext *getLookupParent(); const DeclContext *getLookupParent() const { return const_cast(this)->getLookupParent(); } ASTContext &getParentASTContext() const { return cast(this)->getASTContext(); } bool isClosure() const { return getDeclKind() == Decl::Block; } bool isObjCContainer() const { switch (getDeclKind()) { case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: case Decl::ObjCImplementation: case Decl::ObjCInterface: case Decl::ObjCProtocol: return true; default: return false; } } bool isFunctionOrMethod() const { switch (getDeclKind()) { case Decl::Block: case Decl::Captured: case Decl::ObjCMethod: return true; default: return getDeclKind() >= Decl::firstFunction && getDeclKind() <= Decl::lastFunction; } } /// Test whether the context supports looking up names. bool isLookupContext() const { return !isFunctionOrMethod() && getDeclKind() != Decl::LinkageSpec && getDeclKind() != Decl::Export; } bool isFileContext() const { return getDeclKind() == Decl::TranslationUnit || getDeclKind() == Decl::Namespace; } bool isTranslationUnit() const { return getDeclKind() == Decl::TranslationUnit; } bool isRecord() const { return getDeclKind() >= Decl::firstRecord && getDeclKind() <= Decl::lastRecord; } bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isStdNamespace() const; bool isInlineNamespace() const; /// Determines whether this context is dependent on a /// template parameter. bool isDependentContext() const; /// isTransparentContext - Determines whether this context is a /// "transparent" context, meaning that the members declared in this /// context are semantically declared in the nearest enclosing /// non-transparent (opaque) context but are lexically declared in /// this context. For example, consider the enumerators of an /// enumeration type: /// @code /// enum E { /// Val1 /// }; /// @endcode /// Here, E is a transparent context, so its enumerator (Val1) will /// appear (semantically) that it is in the same context of E. /// Examples of transparent contexts include: enumerations (except for /// C++0x scoped enums), and C++ linkage specifications. bool isTransparentContext() const; /// Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C linkage. bool isExternCContext() const; /// Retrieve the nearest enclosing C linkage specification context. const LinkageSpecDecl *getExternCContext() const; /// Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C++ linkage. bool isExternCXXContext() const; /// Determine whether this declaration context is equivalent /// to the declaration context DC. bool Equals(const DeclContext *DC) const { return DC && this->getPrimaryContext() == DC->getPrimaryContext(); } /// Determine whether this declaration context encloses the /// declaration context DC. bool Encloses(const DeclContext *DC) const; /// Find the nearest non-closure ancestor of this context, /// i.e. the innermost semantic parent of this context which is not /// a closure. A context may be its own non-closure ancestor. Decl *getNonClosureAncestor(); const Decl *getNonClosureAncestor() const { return const_cast(this)->getNonClosureAncestor(); } /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with /// a different set of declarations. This routine returns the /// "primary" DeclContext structure, which will contain the /// information needed to perform name lookup into this context. DeclContext *getPrimaryContext(); const DeclContext *getPrimaryContext() const { return const_cast(this)->getPrimaryContext(); } /// getRedeclContext - Retrieve the context in which an entity conflicts with /// other entities of the same name, or where it is a redeclaration if the /// two entities are compatible. This skips through transparent contexts. DeclContext *getRedeclContext(); const DeclContext *getRedeclContext() const { return const_cast(this)->getRedeclContext(); } /// Retrieve the nearest enclosing namespace context. DeclContext *getEnclosingNamespaceContext(); const DeclContext *getEnclosingNamespaceContext() const { return const_cast(this)->getEnclosingNamespaceContext(); } /// Retrieve the outermost lexically enclosing record context. RecordDecl *getOuterLexicalRecordContext(); const RecordDecl *getOuterLexicalRecordContext() const { return const_cast(this)->getOuterLexicalRecordContext(); } /// Test if this context is part of the enclosing namespace set of /// the context NS, as defined in C++0x [namespace.def]p9. If either context /// isn't a namespace, this is equivalent to Equals(). /// /// The enclosing namespace set of a namespace is the namespace and, if it is /// inline, its enclosing namespace, recursively. bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; /// Collects all of the declaration contexts that are semantically /// connected to this declaration context. /// /// For declaration contexts that have multiple semantically connected but /// syntactically distinct contexts, such as C++ namespaces, this routine /// retrieves the complete set of such declaration contexts in source order. /// For example, given: /// /// \code /// namespace N { /// int x; /// } /// namespace N { /// int y; /// } /// \endcode /// /// The \c Contexts parameter will contain both definitions of N. /// /// \param Contexts Will be cleared and set to the set of declaration /// contexts that are semanticaly connected to this declaration context, /// in source order, including this context (which may be the only result, /// for non-namespace contexts). void collectAllContexts(SmallVectorImpl &Contexts); /// decl_iterator - Iterates through the declarations stored /// within this context. class decl_iterator { /// Current - The current declaration. Decl *Current = nullptr; public: using value_type = Decl *; using reference = const value_type &; using pointer = const value_type *; using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; decl_iterator() = default; explicit decl_iterator(Decl *C) : Current(C) {} reference operator*() const { return Current; } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return Current; } decl_iterator& operator++() { Current = Current->getNextDeclInContext(); return *this; } decl_iterator operator++(int) { decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(decl_iterator x, decl_iterator y) { return x.Current == y.Current; } friend bool operator!=(decl_iterator x, decl_iterator y) { return x.Current != y.Current; } }; using decl_range = llvm::iterator_range; /// decls_begin/decls_end - Iterate over the declarations stored in /// this context. decl_range decls() const { return decl_range(decls_begin(), decls_end()); } decl_iterator decls_begin() const; decl_iterator decls_end() const { return decl_iterator(); } bool decls_empty() const; /// noload_decls_begin/end - Iterate over the declarations stored in this /// context that are currently loaded; don't attempt to retrieve anything /// from an external source. decl_range noload_decls() const { return decl_range(noload_decls_begin(), noload_decls_end()); } decl_iterator noload_decls_begin() const { return decl_iterator(FirstDecl); } decl_iterator noload_decls_end() const { return decl_iterator(); } /// specific_decl_iterator - Iterates over a subrange of /// declarations stored in a DeclContext, providing only those that /// are of type SpecificDecl (or a class derived from it). This /// iterator is used, for example, to provide iteration over just /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). template class specific_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && !isa(*Current)) ++Current; } public: using value_type = SpecificDecl *; // TODO: Add reference and pointer types (with some appropriate proxy type) // if we ever have a need for them. using reference = void; using pointer = void; using difference_type = std::iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; specific_decl_iterator() = default; /// specific_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return **this; } specific_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } specific_decl_iterator operator++(int) { specific_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current != y.Current; } }; /// Iterates over a filtered subrange of declarations stored /// in a DeclContext. /// /// This iterator visits only those declarations that are of type /// SpecificDecl (or a class derived from it) and that meet some /// additional run-time criteria. This iterator is used, for /// example, to provide access to the instance methods within an /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and /// Acceptable = ObjCMethodDecl::isInstanceMethod). template class filtered_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && (!isa(*Current) || (Acceptable && !(cast(*Current)->*Acceptable)()))) ++Current; } public: using value_type = SpecificDecl *; // TODO: Add reference and pointer types (with some appropriate proxy type) // if we ever have a need for them. using reference = void; using pointer = void; using difference_type = std::iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; filtered_decl_iterator() = default; /// filtered_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } value_type operator->() const { return cast(*Current); } filtered_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } filtered_decl_iterator operator++(int) { filtered_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current != y.Current; } }; /// Add the declaration D into this context. /// /// This routine should be invoked when the declaration D has first /// been declared, to place D into the context where it was /// (lexically) defined. Every declaration must be added to one /// (and only one!) context, where it can be visited via /// [decls_begin(), decls_end()). Once a declaration has been added /// to its lexical context, the corresponding DeclContext owns the /// declaration. /// /// If D is also a NamedDecl, it will be made visible within its /// semantic context via makeDeclVisibleInContext. void addDecl(Decl *D); /// Add the declaration D into this context, but suppress /// searches for external declarations with the same name. /// /// Although analogous in function to addDecl, this removes an /// important check. This is only useful if the Decl is being /// added in response to an external search; in all other cases, /// addDecl() is the right function to use. /// See the ASTImporter for use cases. void addDeclInternal(Decl *D); /// Add the declaration D to this context without modifying /// any lookup tables. /// /// This is useful for some operations in dependent contexts where /// the semantic context might not be dependent; this basically /// only happens with friends. void addHiddenDecl(Decl *D); /// Removes a declaration from this context. void removeDecl(Decl *D); /// Checks whether a declaration is in this context. bool containsDecl(Decl *D) const; /// Checks whether a declaration is in this context. /// This also loads the Decls from the external source before the check. bool containsDeclAndLoad(Decl *D) const; using lookup_result = DeclContextLookupResult; using lookup_iterator = lookup_result::iterator; /// lookup - Find the declarations (if any) with the given Name in /// this context. Returns a range of iterators that contains all of /// the declarations with this name, with object, function, member, /// and enumerator names preceding any tag name. Note that this /// routine will not look into parent contexts. lookup_result lookup(DeclarationName Name) const; /// Find the declarations with the given name that are visible /// within this context; don't attempt to retrieve anything from an /// external source. lookup_result noload_lookup(DeclarationName Name); /// A simplistic name lookup mechanism that performs name lookup /// into this declaration context without consulting the external source. /// /// This function should almost never be used, because it subverts the /// usual relationship between a DeclContext and the external source. /// See the ASTImporter for the (few, but important) use cases. /// /// FIXME: This is very inefficient; replace uses of it with uses of /// noload_lookup. void localUncachedLookup(DeclarationName Name, SmallVectorImpl &Results); /// Makes a declaration visible within this context. /// /// This routine makes the declaration D visible to name lookup /// within this context and, if this is a transparent context, /// within its parent contexts up to the first enclosing /// non-transparent context. Making a declaration visible within a /// context does not transfer ownership of a declaration, and a /// declaration can be visible in many contexts that aren't its /// lexical context. /// /// If D is a redeclaration of an existing declaration that is /// visible from this context, as determined by /// NamedDecl::declarationReplaces, the previous declaration will be /// replaced with D. void makeDeclVisibleInContext(NamedDecl *D); /// all_lookups_iterator - An iterator that provides a view over the results /// of looking up every possible name. class all_lookups_iterator; using lookups_range = llvm::iterator_range; lookups_range lookups() const; // Like lookups(), but avoids loading external declarations. // If PreserveInternalState, avoids building lookup data structures too. lookups_range noload_lookups(bool PreserveInternalState) const; /// Iterators over all possible lookups within this context. all_lookups_iterator lookups_begin() const; all_lookups_iterator lookups_end() const; /// Iterators over all possible lookups within this context that are /// currently loaded; don't attempt to retrieve anything from an external /// source. all_lookups_iterator noload_lookups_begin() const; all_lookups_iterator noload_lookups_end() const; struct udir_iterator; using udir_iterator_base = llvm::iterator_adaptor_base; struct udir_iterator : udir_iterator_base { udir_iterator(lookup_iterator I) : udir_iterator_base(I) {} UsingDirectiveDecl *operator*() const; }; using udir_range = llvm::iterator_range; udir_range using_directives() const; // These are all defined in DependentDiagnostic.h. class ddiag_iterator; using ddiag_range = llvm::iterator_range; inline ddiag_range ddiags() const; // Low-level accessors /// Mark that there are external lexical declarations that we need /// to include in our lookup table (and that are not available as external /// visible lookups). These extra lookup results will be found by walking /// the lexical declarations of this context. This should be used only if /// setHasExternalLexicalStorage() has been called on any decl context for /// which this is the primary context. void setMustBuildLookupTable() { assert(this == getPrimaryContext() && "should only be called on primary context"); DeclContextBits.HasLazyExternalLexicalLookups = true; } /// Retrieve the internal representation of the lookup structure. /// This may omit some names if we are lazily building the structure. StoredDeclsMap *getLookupPtr() const { return LookupPtr; } /// Ensure the lookup structure is fully-built and return it. StoredDeclsMap *buildLookup(); /// Whether this DeclContext has external storage containing /// additional declarations that are lexically in this context. bool hasExternalLexicalStorage() const { return DeclContextBits.ExternalLexicalStorage; } /// State whether this DeclContext has external storage for /// declarations lexically in this context. void setHasExternalLexicalStorage(bool ES = true) const { DeclContextBits.ExternalLexicalStorage = ES; } /// Whether this DeclContext has external storage containing /// additional declarations that are visible in this context. bool hasExternalVisibleStorage() const { return DeclContextBits.ExternalVisibleStorage; } /// State whether this DeclContext has external storage for /// declarations visible in this context. void setHasExternalVisibleStorage(bool ES = true) const { DeclContextBits.ExternalVisibleStorage = ES; if (ES && LookupPtr) DeclContextBits.NeedToReconcileExternalVisibleStorage = true; } /// Determine whether the given declaration is stored in the list of /// declarations lexically within this context. bool isDeclInLexicalTraversal(const Decl *D) const { return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl || D == LastDecl); } bool setUseQualifiedLookup(bool use = true) const { bool old_value = DeclContextBits.UseQualifiedLookup; DeclContextBits.UseQualifiedLookup = use; return old_value; } bool shouldUseQualifiedLookup() const { return DeclContextBits.UseQualifiedLookup; } static bool classof(const Decl *D); static bool classof(const DeclContext *D) { return true; } void dumpDeclContext() const; void dumpLookups() const; void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false, bool Deserialize = false) const; private: /// Whether this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. bool hasNeedToReconcileExternalVisibleStorage() const { return DeclContextBits.NeedToReconcileExternalVisibleStorage; } /// State that this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. void setNeedToReconcileExternalVisibleStorage(bool Need = true) const { DeclContextBits.NeedToReconcileExternalVisibleStorage = Need; } /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. bool hasLazyLocalLexicalLookups() const { return DeclContextBits.HasLazyLocalLexicalLookups; } /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. void setHasLazyLocalLexicalLookups(bool HasLLLL = true) const { DeclContextBits.HasLazyLocalLexicalLookups = HasLLLL; } /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. bool hasLazyExternalLexicalLookups() const { return DeclContextBits.HasLazyExternalLexicalLookups; } /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. void setHasLazyExternalLexicalLookups(bool HasLELL = true) const { DeclContextBits.HasLazyExternalLexicalLookups = HasLELL; } void reconcileExternalVisibleStorage() const; bool LoadLexicalDeclsFromExternalStorage() const; /// Makes a declaration visible within this context, but /// suppresses searches for external declarations with the same /// name. /// /// Analogous to makeDeclVisibleInContext, but for the exclusive /// use of addDeclInternal(). void makeDeclVisibleInContextInternal(NamedDecl *D); StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; void loadLazyLocalLexicalLookups(); void buildLookupImpl(DeclContext *DCtx, bool Internal); void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Rediscoverable); void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); }; inline bool Decl::isTemplateParameter() const { return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || getKind() == TemplateTemplateParm; } // Specialization selected when ToTy is not a known subclass of DeclContext. template ::value> struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } static ToTy *doit(DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } }; // Specialization selected when ToTy is a known subclass of DeclContext. template struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Val); } static ToTy *doit(DeclContext *Val) { return static_cast(Val); } }; } // namespace clang namespace llvm { /// isa(DeclContext*) template struct isa_impl { static bool doit(const ::clang::DeclContext &Val) { return To::classofKind(Val.getDeclKind()); } }; /// cast(DeclContext*) template struct cast_convert_val { static const ToTy &doit(const ::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static ToTy &doit(::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static const ToTy *doit(const ::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; template struct cast_convert_val { static ToTy *doit(::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; /// Implement cast_convert_val for Decl -> DeclContext conversions. template struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { static ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { static ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { static const ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { static const ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; } // namespace llvm #endif // LLVM_CLANG_AST_DECLBASE_H Index: stable/11/contrib/llvm/tools/clang/include/clang/AST/Type.h =================================================================== --- stable/11/contrib/llvm/tools/clang/include/clang/AST/Type.h (revision 349966) +++ stable/11/contrib/llvm/tools/clang/include/clang/AST/Type.h (revision 349967) @@ -1,6849 +1,6849 @@ //===- Type.h - C Language Family Type Representation -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// C Language Family Type Representation /// /// This file defines the clang::Type interface and subclasses, used to /// represent types for languages in the C family. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPE_H #define LLVM_CLANG_AST_TYPE_H #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" #include "llvm/Support/TrailingObjects.h" #include #include #include #include #include #include #include namespace clang { class ExtQuals; class QualType; class TagDecl; class Type; enum { TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits }; } // namespace clang namespace llvm { template struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits< ::clang::Type*> { static inline void *getAsVoidPointer(::clang::Type *P) { return P; } static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template<> struct PointerLikeTypeTraits< ::clang::ExtQuals*> { static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { return static_cast< ::clang::ExtQuals*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template <> struct isPodLike { static const bool value = true; }; } // namespace llvm namespace clang { class ASTContext; template class CanQual; class CXXRecordDecl; class DeclContext; class EnumDecl; class Expr; class ExtQualsTypeCommonBase; class FunctionDecl; class IdentifierInfo; class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; struct PrintingPolicy; class RecordDecl; class Stmt; class TagDecl; class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; class TemplateTypeParmDecl; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; using CanQualType = CanQual; // Provide forward declarations for all of the *Type classes. #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" /// The collection of all-type qualifiers we support. /// Clang supports five independent qualifiers: /// * C99: const, volatile, and restrict /// * MS: __unaligned /// * Embedded C (TR18037): address spaces /// * Objective C: the GC attributes (none, weak, or strong) class Qualifiers { public: enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, Restrict = 0x2, Volatile = 0x4, CVRMask = Const | Volatile | Restrict }; enum GC { GCNone = 0, Weak, Strong }; enum ObjCLifetime { /// There is no lifetime qualification on this type. OCL_None, /// This object can be modified without requiring retains or /// releases. OCL_ExplicitNone, /// Assigning into this object requires the old value to be /// released and the new value to be retained. The timing of the /// release of the old value is inexact: it may be moved to /// immediately after the last known point where the value is /// live. OCL_Strong, /// Reading or writing from this object requires a barrier call. OCL_Weak, /// Assigning into this object requires a lifetime extension. OCL_Autoreleasing }; enum { /// The maximum supported address space number. /// 23 bits should be enough for anyone. MaxAddressSpace = 0x7fffffu, /// The width of the "fast" qualifier mask. FastWidth = 3, /// The fast qualifier mask. FastMask = (1 << FastWidth) - 1 }; /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { // If both are only CVR-qualified, bit operations are sufficient. if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { Qualifiers Q; Q.Mask = L.Mask & R.Mask; L.Mask &= ~Q.Mask; R.Mask &= ~Q.Mask; return Q; } Qualifiers Q; unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); Q.addCVRQualifiers(CommonCRV); L.removeCVRQualifiers(CommonCRV); R.removeCVRQualifiers(CommonCRV); if (L.getObjCGCAttr() == R.getObjCGCAttr()) { Q.setObjCGCAttr(L.getObjCGCAttr()); L.removeObjCGCAttr(); R.removeObjCGCAttr(); } if (L.getObjCLifetime() == R.getObjCLifetime()) { Q.setObjCLifetime(L.getObjCLifetime()); L.removeObjCLifetime(); R.removeObjCLifetime(); } if (L.getAddressSpace() == R.getAddressSpace()) { Q.setAddressSpace(L.getAddressSpace()); L.removeAddressSpace(); R.removeAddressSpace(); } return Q; } static Qualifiers fromFastMask(unsigned Mask) { Qualifiers Qs; Qs.addFastQualifiers(Mask); return Qs; } static Qualifiers fromCVRMask(unsigned CVR) { Qualifiers Qs; Qs.addCVRQualifiers(CVR); return Qs; } static Qualifiers fromCVRUMask(unsigned CVRU) { Qualifiers Qs; Qs.addCVRUQualifiers(CVRU); return Qs; } // Deserialize qualifiers from an opaque representation. static Qualifiers fromOpaqueValue(unsigned opaque) { Qualifiers Qs; Qs.Mask = opaque; return Qs; } // Serialize these qualifiers into an opaque representation. unsigned getAsOpaqueValue() const { return Mask; } bool hasConst() const { return Mask & Const; } bool hasOnlyConst() const { return Mask == Const; } void removeConst() { Mask &= ~Const; } void addConst() { Mask |= Const; } bool hasVolatile() const { return Mask & Volatile; } bool hasOnlyVolatile() const { return Mask == Volatile; } void removeVolatile() { Mask &= ~Volatile; } void addVolatile() { Mask |= Volatile; } bool hasRestrict() const { return Mask & Restrict; } bool hasOnlyRestrict() const { return Mask == Restrict; } void removeRestrict() { Mask &= ~Restrict; } void addRestrict() { Mask |= Restrict; } bool hasCVRQualifiers() const { return getCVRQualifiers(); } unsigned getCVRQualifiers() const { return Mask & CVRMask; } unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } void setCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask = (Mask & ~CVRMask) | mask; } void removeCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask &= ~mask; } void removeCVRQualifiers() { removeCVRQualifiers(CVRMask); } void addCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask |= mask; } void addCVRUQualifiers(unsigned mask) { assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits"); Mask |= mask; } bool hasUnaligned() const { return Mask & UMask; } void setUnaligned(bool flag) { Mask = (Mask & ~UMask) | (flag ? UMask : 0); } void removeUnaligned() { Mask &= ~UMask; } void addUnaligned() { Mask |= UMask; } bool hasObjCGCAttr() const { return Mask & GCAttrMask; } GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } void setObjCGCAttr(GC type) { Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); } void removeObjCGCAttr() { setObjCGCAttr(GCNone); } void addObjCGCAttr(GC type) { assert(type); setObjCGCAttr(type); } Qualifiers withoutObjCGCAttr() const { Qualifiers qs = *this; qs.removeObjCGCAttr(); return qs; } Qualifiers withoutObjCLifetime() const { Qualifiers qs = *this; qs.removeObjCLifetime(); return qs; } bool hasObjCLifetime() const { return Mask & LifetimeMask; } ObjCLifetime getObjCLifetime() const { return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); } void setObjCLifetime(ObjCLifetime type) { Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); } void removeObjCLifetime() { setObjCLifetime(OCL_None); } void addObjCLifetime(ObjCLifetime type) { assert(type); assert(!hasObjCLifetime()); Mask |= (type << LifetimeShift); } /// True if the lifetime is neither None or ExplicitNone. bool hasNonTrivialObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime > OCL_ExplicitNone); } /// True if the lifetime is either strong or weak. bool hasStrongOrWeakObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime == OCL_Strong || lifetime == OCL_Weak); } bool hasAddressSpace() const { return Mask & AddressSpaceMask; } LangAS getAddressSpace() const { return static_cast(Mask >> AddressSpaceShift); } bool hasTargetSpecificAddressSpace() const { return isTargetAddressSpace(getAddressSpace()); } /// Get the address space attribute value to be printed by diagnostics. unsigned getAddressSpaceAttributePrintValue() const { auto Addr = getAddressSpace(); // This function is not supposed to be used with language specific // address spaces. If that happens, the diagnostic message should consider // printing the QualType instead of the address space value. assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); if (Addr != LangAS::Default) return toTargetAddressSpace(Addr); // TODO: The diagnostic messages where Addr may be 0 should be fixed // since it cannot differentiate the situation where 0 denotes the default // address space or user specified __attribute__((address_space(0))). return 0; } void setAddressSpace(LangAS space) { assert((unsigned)space <= MaxAddressSpace); Mask = (Mask & ~AddressSpaceMask) | (((uint32_t) space) << AddressSpaceShift); } void removeAddressSpace() { setAddressSpace(LangAS::Default); } void addAddressSpace(LangAS space) { assert(space != LangAS::Default); setAddressSpace(space); } // Fast qualifiers are those that can be allocated directly // on a QualType object. bool hasFastQualifiers() const { return getFastQualifiers(); } unsigned getFastQualifiers() const { return Mask & FastMask; } void setFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask = (Mask & ~FastMask) | mask; } void removeFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask &= ~mask; } void removeFastQualifiers() { removeFastQualifiers(FastMask); } void addFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask |= mask; } /// Return true if the set contains any qualifiers which require an ExtQuals /// node to be allocated. bool hasNonFastQualifiers() const { return Mask & ~FastMask; } Qualifiers getNonFastQualifiers() const { Qualifiers Quals = *this; Quals.setFastQualifiers(0); return Quals; } /// Return true if the set contains any qualifiers. bool hasQualifiers() const { return Mask; } bool empty() const { return !Mask; } /// Add the qualifiers from the given set to this set. void addQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-or it in. if (!(Q.Mask & ~CVRMask)) Mask |= Q.Mask; else { Mask |= (Q.Mask & CVRMask); if (Q.hasAddressSpace()) addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) addObjCGCAttr(Q.getObjCGCAttr()); if (Q.hasObjCLifetime()) addObjCLifetime(Q.getObjCLifetime()); } } /// Remove the qualifiers from the given set from this set. void removeQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-and the inverse in. if (!(Q.Mask & ~CVRMask)) Mask &= ~Q.Mask; else { Mask &= ~(Q.Mask & CVRMask); if (getObjCGCAttr() == Q.getObjCGCAttr()) removeObjCGCAttr(); if (getObjCLifetime() == Q.getObjCLifetime()) removeObjCLifetime(); if (getAddressSpace() == Q.getAddressSpace()) removeAddressSpace(); } } /// Add the qualifiers from the given set to this set, given that /// they don't conflict. void addConsistentQualifiers(Qualifiers qs) { assert(getAddressSpace() == qs.getAddressSpace() || !hasAddressSpace() || !qs.hasAddressSpace()); assert(getObjCGCAttr() == qs.getObjCGCAttr() || !hasObjCGCAttr() || !qs.hasObjCGCAttr()); assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() || !qs.hasObjCLifetime()); Mask |= qs.Mask; } /// Returns true if this address space is a superset of the other one. /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of /// overlapping address spaces. /// CL1.1 or CL1.2: /// every address space is a superset of itself. /// CL2.0 adds: /// __generic is a superset of any address space except for __constant. bool isAddressSpaceSupersetOf(Qualifiers other) const { return // Address spaces must match exactly. getAddressSpace() == other.getAddressSpace() || // Otherwise in OpenCLC v2.0 s6.5.5: every address space except // for __constant can be used as __generic. (getAddressSpace() == LangAS::opencl_generic && other.getAddressSpace() != LangAS::opencl_constant); } /// Determines if these qualifiers compatibly include another set. /// Generally this answers the question of whether an object with the other /// qualifiers can be safely used as an object with these qualifiers. bool compatiblyIncludes(Qualifiers other) const { return isAddressSpaceSupersetOf(other) && // ObjC GC qualifiers can match, be added, or be removed, but can't // be changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || !other.hasObjCGCAttr()) && // ObjC lifetime qualifiers must match exactly. getObjCLifetime() == other.getObjCLifetime() && // CVR qualifiers may subset. (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && // U qualifier may superset. (!other.hasUnaligned() || hasUnaligned()); } /// Determines if these qualifiers compatibly include another set of /// qualifiers from the narrow perspective of Objective-C ARC lifetime. /// /// One set of Objective-C lifetime qualifiers compatibly includes the other /// if the lifetime qualifiers match, or if both are non-__weak and the /// including set also contains the 'const' qualifier, or both are non-__weak /// and one is None (which can only happen in non-ARC modes). bool compatiblyIncludesObjCLifetime(Qualifiers other) const { if (getObjCLifetime() == other.getObjCLifetime()) return true; if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) return false; if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) return true; return hasConst(); } /// Determine whether this set of qualifiers is a strict superset of /// another set of qualifiers, not considering qualifier compatibility. bool isStrictSupersetOf(Qualifiers Other) const; bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } explicit operator bool() const { return hasQualifiers(); } Qualifiers &operator+=(Qualifiers R) { addQualifiers(R); return *this; } // Union two qualifier sets. If an enumerated qualifier appears // in both sets, use the one from the right. friend Qualifiers operator+(Qualifiers L, Qualifiers R) { L += R; return L; } Qualifiers &operator-=(Qualifiers R) { removeQualifiers(R); return *this; } /// Compute the difference between two qualifier sets. friend Qualifiers operator-(Qualifiers L, Qualifiers R) { L -= R; return L; } std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, bool appendSpaceIfNonEmpty = false) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } private: // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| // |C R V|U|GCAttr|Lifetime|AddressSpace| uint32_t Mask = 0; static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; static const uint32_t GCAttrMask = 0x30; static const uint32_t GCAttrShift = 4; static const uint32_t LifetimeMask = 0x1C0; static const uint32_t LifetimeShift = 6; static const uint32_t AddressSpaceMask = ~(CVRMask | UMask | GCAttrMask | LifetimeMask); static const uint32_t AddressSpaceShift = 9; }; /// A std::pair-like structure for storing a qualified type split /// into its local qualifiers and its locally-unqualified type. struct SplitQualType { /// The locally-unqualified type. const Type *Ty = nullptr; /// The local qualifiers. Qualifiers Quals; SplitQualType() = default; SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} SplitQualType getSingleStepDesugaredType() const; // end of this file // Make std::tie work. std::pair asPair() const { return std::pair(Ty, Quals); } friend bool operator==(SplitQualType a, SplitQualType b) { return a.Ty == b.Ty && a.Quals == b.Quals; } friend bool operator!=(SplitQualType a, SplitQualType b) { return a.Ty != b.Ty || a.Quals != b.Quals; } }; /// The kind of type we are substituting Objective-C type arguments into. /// /// The kind of substitution affects the replacement of type parameters when /// no concrete type information is provided, e.g., when dealing with an /// unspecialized type. enum class ObjCSubstitutionContext { /// An ordinary type. Ordinary, /// The result type of a method or function. Result, /// The parameter type of a method or function. Parameter, /// The type of a property. Property, /// The superclass of a type. Superclass, }; /// A (possibly-)qualified type. /// /// For efficiency, we don't store CV-qualified types as nodes on their /// own: instead each reference to a type stores the qualifiers. This /// greatly reduces the number of nodes we need to allocate for types (for /// example we only need one for 'int', 'const int', 'volatile int', /// 'const volatile int', etc). /// /// As an added efficiency bonus, instead of making this a pair, we /// just store the two bits we care about in the low bits of the /// pointer. To handle the packing/unpacking, we make QualType be a /// simple wrapper class that acts like a smart pointer. A third bit /// indicates whether there are extended qualifiers present, in which /// case the pointer points to a special structure. class QualType { friend class QualifierCollector; // Thankfully, these are efficiently composable. llvm::PointerIntPair, Qualifiers::FastWidth> Value; const ExtQuals *getExtQualsUnsafe() const { return Value.getPointer().get(); } const Type *getTypePtrUnsafe() const { return Value.getPointer().get(); } const ExtQualsTypeCommonBase *getCommonPtr() const { assert(!isNull() && "Cannot retrieve a NULL type pointer"); auto CommonPtrVal = reinterpret_cast(Value.getOpaqueValue()); CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); return reinterpret_cast(CommonPtrVal); } public: QualType() = default; QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} unsigned getLocalFastQualifiers() const { return Value.getInt(); } void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } /// Retrieves a pointer to the underlying (unqualified) type. /// /// This function requires that the type not be NULL. If the type might be /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). const Type *getTypePtr() const; const Type *getTypePtrOrNull() const; /// Retrieves a pointer to the name of the base type. const IdentifierInfo *getBaseTypeIdentifier() const; /// Divides a QualType into its unqualified type and a set of local /// qualifiers. SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(const void *Ptr) { QualType T; T.Value.setFromOpaqueValue(const_cast(Ptr)); return T; } const Type &operator*() const { return *getTypePtr(); } const Type *operator->() const { return getTypePtr(); } bool isCanonical() const; bool isCanonicalAsParam() const; /// Return true if this QualType doesn't point to a type yet. bool isNull() const { return Value.getPointer().isNull(); } /// Determine whether this particular QualType instance has the /// "const" qualifier set, without looking through typedefs that may have /// added "const" at a different level. bool isLocalConstQualified() const { return (getLocalFastQualifiers() & Qualifiers::Const); } /// Determine whether this type is const-qualified. bool isConstQualified() const; /// Determine whether this particular QualType instance has the /// "restrict" qualifier set, without looking through typedefs that may have /// added "restrict" at a different level. bool isLocalRestrictQualified() const { return (getLocalFastQualifiers() & Qualifiers::Restrict); } /// Determine whether this type is restrict-qualified. bool isRestrictQualified() const; /// Determine whether this particular QualType instance has the /// "volatile" qualifier set, without looking through typedefs that may have /// added "volatile" at a different level. bool isLocalVolatileQualified() const { return (getLocalFastQualifiers() & Qualifiers::Volatile); } /// Determine whether this type is volatile-qualified. bool isVolatileQualified() const; /// Determine whether this particular QualType instance has any /// qualifiers, without looking through any typedefs that might add /// qualifiers at a different level. bool hasLocalQualifiers() const { return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); } /// Determine whether this type has any qualifiers. bool hasQualifiers() const; /// Determine whether this particular QualType instance has any /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType /// instance. bool hasLocalNonFastQualifiers() const { return Value.getPointer().is(); } /// Retrieve the set of qualifiers local to this particular QualType /// instance, not including any qualifiers acquired through typedefs or /// other sugar. Qualifiers getLocalQualifiers() const; /// Retrieve the set of qualifiers applied to this type. Qualifiers getQualifiers() const; /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// local to this particular QualType instance, not including any qualifiers /// acquired through typedefs or other sugar. unsigned getLocalCVRQualifiers() const { return getLocalFastQualifiers(); } /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// applied to this type. unsigned getCVRQualifiers() const; bool isConstant(const ASTContext& Ctx) const { return QualType::isConstant(*this, Ctx); } /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). bool isPODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the rules of the C++98 /// standard, regardless of the current compilation's language. bool isCXX98PODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the more relaxed rules /// of the C++11 standard, regardless of the current compilation's language. /// (C++0x [basic.types]p9). Note that, unlike /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account. bool isCXX11PODType(const ASTContext &Context) const; /// Return true if this is a trivial type per (C++0x [basic.types]p9) bool isTrivialType(const ASTContext &Context) const; /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; /// Returns true if it is a class and it might be dynamic. bool mayBeDynamicClass() const; /// Returns true if it is not a class or if the class might not be dynamic. bool mayBeNotDynamicClass() const; // Don't promise in the API that anything besides 'const' can be // easily added. /// Add the `const` type qualifier to this QualType. void addConst() { addFastQualifiers(Qualifiers::Const); } QualType withConst() const { return withFastQualifiers(Qualifiers::Const); } /// Add the `volatile` type qualifier to this QualType. void addVolatile() { addFastQualifiers(Qualifiers::Volatile); } QualType withVolatile() const { return withFastQualifiers(Qualifiers::Volatile); } /// Add the `restrict` qualifier to this QualType. void addRestrict() { addFastQualifiers(Qualifiers::Restrict); } QualType withRestrict() const { return withFastQualifiers(Qualifiers::Restrict); } QualType withCVRQualifiers(unsigned CVR) const { return withFastQualifiers(CVR); } void addFastQualifiers(unsigned TQs) { assert(!(TQs & ~Qualifiers::FastMask) && "non-fast qualifier bits set in mask!"); Value.setInt(Value.getInt() | TQs); } void removeLocalConst(); void removeLocalVolatile(); void removeLocalRestrict(); void removeLocalCVRQualifiers(unsigned Mask); void removeLocalFastQualifiers() { Value.setInt(0); } void removeLocalFastQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); Value.setInt(Value.getInt() & ~Mask); } // Creates a type with the given qualifiers in addition to any // qualifiers already on this type. QualType withFastQualifiers(unsigned TQs) const { QualType T = *this; T.addFastQualifiers(TQs); return T; } // Creates a type with exactly the given fast qualifiers, removing // any existing fast qualifiers. QualType withExactLocalFastQualifiers(unsigned TQs) const { return withoutLocalFastQualifiers().withFastQualifiers(TQs); } // Removes fast qualifiers, but leaves any extended qualifiers in place. QualType withoutLocalFastQualifiers() const { QualType T = *this; T.removeLocalFastQualifiers(); return T; } QualType getCanonicalType() const; /// Return this type with all of the instance-specific qualifiers /// removed, but without removing any qualifiers that may have been applied /// through typedefs. QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } /// Retrieve the unqualified variant of the given type, /// removing as little sugar as possible. /// /// This routine looks through various kinds of sugar to find the /// least-desugared type that is unqualified. For example, given: /// /// \code /// typedef int Integer; /// typedef const Integer CInteger; /// typedef CInteger DifferenceType; /// \endcode /// /// Executing \c getUnqualifiedType() on the type \c DifferenceType will /// desugar until we hit the type \c Integer, which has no qualifiers on it. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline QualType getUnqualifiedType() const; /// Retrieve the unqualified variant of the given type, removing as little /// sugar as possible. /// /// Like getUnqualifiedType(), but also returns the set of /// qualifiers that were built up. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline SplitQualType getSplitUnqualifiedType() const; /// Determine whether this type is more qualified than the other /// given type, requiring exact equality for non-CVR qualifiers. bool isMoreQualifiedThan(QualType Other) const; /// Determine whether this type is at least as qualified as the other /// given type, requiring exact equality for non-CVR qualifiers. bool isAtLeastAsQualifiedAs(QualType Other) const; QualType getNonReferenceType() const; /// Determine the type of a (typically non-lvalue) expression with the /// specified result type. /// /// This routine should be used for expressions for which the return type is /// explicitly specified (e.g., in a cast or call) and isn't necessarily /// an lvalue. It removes a top-level reference (since there are no /// expressions of reference type) and deletes top-level cvr-qualifiers /// from non-class types (in C++) or all types (in C). QualType getNonLValueExprType(const ASTContext &Context) const; /// Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. /// /// Qualifiers are left in place. QualType getDesugaredType(const ASTContext &Context) const { return getDesugaredType(*this, Context); } SplitQualType getSplitDesugaredType() const { return getSplitDesugaredType(*this); } /// Return the specified type with one level of "sugar" removed from /// the type. /// /// This routine takes off the first typedef, typeof, etc. If the outer level /// of the type is already concrete, it returns it unmodified. QualType getSingleStepDesugaredType(const ASTContext &Context) const { return getSingleStepDesugaredTypeImpl(*this, Context); } /// Returns the specified type after dropping any /// outer-level parentheses. QualType IgnoreParens() const { if (isa(*this)) return QualType::IgnoreParens(*this); return *this; } /// Indicate whether the specified types and qualifiers are identical. friend bool operator==(const QualType &LHS, const QualType &RHS) { return LHS.Value == RHS.Value; } friend bool operator!=(const QualType &LHS, const QualType &RHS) { return LHS.Value != RHS.Value; } static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy) { return getAsString(split.Ty, split.Quals, Policy); } static std::string getAsString(const Type *ty, Qualifiers qs, const PrintingPolicy &Policy); std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const; static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0) { return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); } static void print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0); void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { return getAsStringInternal(split.Ty, split.Quals, out, policy); } static void getAsStringInternal(const Type *ty, Qualifiers qs, std::string &out, const PrintingPolicy &policy); class StreamedQualTypeHelper { const QualType &T; const PrintingPolicy &Policy; const Twine &PlaceHolder; unsigned Indentation; public: StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, const Twine &PlaceHolder, unsigned Indentation) : T(T), Policy(Policy), PlaceHolder(PlaceHolder), Indentation(Indentation) {} friend raw_ostream &operator<<(raw_ostream &OS, const StreamedQualTypeHelper &SQT) { SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); return OS; } }; StreamedQualTypeHelper stream(const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const { return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); } void dump(const char *s) const; void dump() const; void dump(llvm::raw_ostream &OS) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(getAsOpaquePtr()); } /// Return the address space of this type. inline LangAS getAddressSpace() const; /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; /// true when Type is objc's weak. bool isObjCGCWeak() const { return getObjCGCAttr() == Qualifiers::Weak; } /// true when Type is objc's strong. bool isObjCGCStrong() const { return getObjCGCAttr() == Qualifiers::Strong; } /// Returns lifetime attribute of this type. Qualifiers::ObjCLifetime getObjCLifetime() const { return getQualifiers().getObjCLifetime(); } bool hasNonTrivialObjCLifetime() const { return getQualifiers().hasNonTrivialObjCLifetime(); } bool hasStrongOrWeakObjCLifetime() const { return getQualifiers().hasStrongOrWeakObjCLifetime(); } // true when Type is objc's weak and weak is enabled but ARC isn't. bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PDIK_Trivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PDIK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PDIK_ARCWeak, /// The type is a struct containing a field whose type is not PCK_Trivial. PDIK_Struct }; /// Functions to query basic properties of non-trivial C struct types. /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to default initialize /// and return the kind. PrimitiveDefaultInitializeKind isNonTrivialToPrimitiveDefaultInitialize() const; enum PrimitiveCopyKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PCK_Trivial, /// The type would be trivial except that it is volatile-qualified. Types /// that fall into one of the other non-trivial cases may additionally be /// volatile-qualified. PCK_VolatileTrivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PCK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PCK_ARCWeak, /// The type is a struct containing a field whose type is neither /// PCK_Trivial nor PCK_VolatileTrivial. /// Note that a C++ struct type does not necessarily match this; C++ copying /// semantics are too complex to express here, in part because they depend /// on the exact constructor or assignment operator that is chosen by /// overload resolution to do the copy. PCK_Struct }; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to copy and return the /// kind. PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to destructively /// move and return the kind. Destructive move in this context is a C++-style /// move in which the source object is placed in a valid but unspecified state /// after it is moved, as opposed to a truly destructive move in which the /// source object is placed in an uninitialized state. PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const; enum DestructionKind { DK_none, DK_cxx_destructor, DK_objc_strong_lifetime, DK_objc_weak_lifetime, DK_nontrivial_c_struct }; /// Returns a nonzero value if objects of this type require /// non-trivial work to clean up after. Non-zero because it's /// conceivable that qualifiers (objc_gc(weak)?) could make /// something require destruction. DestructionKind isDestructedType() const { return isDestructedTypeImpl(*this); } /// Determine whether expressions of the given type are forbidden /// from being lvalues in C. /// /// The expression types that are forbidden to be lvalues are: /// - 'void', but not qualified void /// - function types /// /// The exact rule here is C99 6.3.2.1: /// An lvalue is an expression with an object type or an incomplete /// type other than void. bool isCForbiddenLValueType() const; /// Substitute type arguments for the Objective-C type parameters used in the /// subject type. /// /// \param ctx ASTContext in which the type exists. /// /// \param typeArgs The type arguments that will be substituted for the /// Objective-C type parameters in the subject type, which are generally /// computed via \c Type::getObjCSubstitutions. If empty, the type /// parameters will be replaced with their bounds or id/Class, as appropriate /// for the context. /// /// \param context The context in which the subject type was written. /// /// \returns the resulting type. QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef typeArgs, ObjCSubstitutionContext context) const; /// Substitute type arguments from an object type for the Objective-C type /// parameters used in the subject type. /// /// This operation combines the computation of type arguments for /// substitution (\c Type::getObjCSubstitutions) with the actual process of /// substitution (\c QualType::substObjCTypeArgs) for the convenience of /// callers that need to perform a single substitution in isolation. /// /// \param objectType The type of the object whose member type we're /// substituting into. For example, this might be the receiver of a message /// or the base of a property access. /// /// \param dc The declaration context from which the subject type was /// retrieved, which indicates (for example) which type parameters should /// be substituted. /// /// \param context The context in which the subject type was written. /// /// \returns the subject type after replacing all of the Objective-C type /// parameters with their corresponding arguments. QualType substObjCMemberType(QualType objectType, const DeclContext *dc, ObjCSubstitutionContext context) const; /// Strip Objective-C "__kindof" types from the given type. QualType stripObjCKindOfType(const ASTContext &ctx) const; /// Remove all qualifiers including _Atomic. QualType getAtomicUnqualifiedType() const; private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the // caller. static bool isConstant(QualType T, const ASTContext& Ctx); static QualType getDesugaredType(QualType T, const ASTContext &Context); static SplitQualType getSplitDesugaredType(QualType T); static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); static QualType getSingleStepDesugaredTypeImpl(QualType type, const ASTContext &C); static QualType IgnoreParens(QualType T); static DestructionKind isDestructedTypeImpl(QualType type); }; } // namespace clang namespace llvm { /// Implement simplify_type for QualType, so that we can dyn_cast from QualType /// to a specific Type class. template<> struct simplify_type< ::clang::QualType> { using SimpleType = const ::clang::Type *; static SimpleType getSimplifiedValue(::clang::QualType Val) { return Val.getTypePtr(); } }; // Teach SmallPtrSet that QualType is "basically a pointer". template<> struct PointerLikeTypeTraits { static inline void *getAsVoidPointer(clang::QualType P) { return P.getAsOpaquePtr(); } static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; } // namespace llvm namespace clang { /// Base class that is common to both the \c ExtQuals and \c Type /// classes, which allows \c QualType to access the common fields between the /// two. class ExtQualsTypeCommonBase { friend class ExtQuals; friend class QualType; friend class Type; /// The "base" type of an extended qualifiers type (\c ExtQuals) or /// a self-referential pointer (for \c Type). /// /// This pointer allows an efficient mapping from a QualType to its /// underlying type pointer. const Type *const BaseType; /// The canonical type of this type. A QualType. QualType CanonicalType; ExtQualsTypeCommonBase(const Type *baseType, QualType canon) : BaseType(baseType), CanonicalType(canon) {} }; /// We can encode up to four bits in the low bits of a /// type pointer, but there are many more type qualifiers that we want /// to be able to apply to an arbitrary type. Therefore we have this /// struct, intended to be heap-allocated and used by QualType to /// store qualifiers. /// /// The current design tags the 'const', 'restrict', and 'volatile' qualifiers /// in three low bits on the QualType pointer; a fourth bit records whether /// the pointer is an ExtQuals node. The extended qualifiers (address spaces, /// Objective-C GC attributes) are much more rare. class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { // NOTE: changing the fast qualifiers should be straightforward as // long as you don't make 'const' non-fast. // 1. Qualifiers: // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). // Fast qualifiers must occupy the low-order bits. // b) Update Qualifiers::FastWidth and FastMask. // 2. QualType: // a) Update is{Volatile,Restrict}Qualified(), defined inline. // b) Update remove{Volatile,Restrict}, defined near the end of // this header. // 3. ASTContext: // a) Update get{Volatile,Restrict}Type. /// The immutable set of qualifiers applied by this node. Always contains /// extended qualifiers. Qualifiers Quals; ExtQuals *this_() { return this; } public: ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) : ExtQualsTypeCommonBase(baseType, canon.isNull() ? QualType(this_(), 0) : canon), Quals(quals) { assert(Quals.hasNonFastQualifiers() && "ExtQuals created with no fast qualifiers"); assert(!Quals.hasFastQualifiers() && "ExtQuals created with fast qualifiers"); } Qualifiers getQualifiers() const { return Quals; } bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } Qualifiers::ObjCLifetime getObjCLifetime() const { return Quals.getObjCLifetime(); } bool hasAddressSpace() const { return Quals.hasAddressSpace(); } LangAS getAddressSpace() const { return Quals.getAddressSpace(); } const Type *getBaseType() const { return BaseType; } public: void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, getBaseType(), Quals); } static void Profile(llvm::FoldingSetNodeID &ID, const Type *BaseType, Qualifiers Quals) { assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); ID.AddPointer(BaseType); Quals.Profile(ID); } }; /// The kind of C++11 ref-qualifier associated with a function type. /// This determines whether a member function's "this" object can be an /// lvalue, rvalue, or neither. enum RefQualifierKind { /// No ref-qualifier was provided. RQ_None = 0, /// An lvalue ref-qualifier was provided (\c &). RQ_LValue, /// An rvalue ref-qualifier was provided (\c &&). RQ_RValue }; /// Which keyword(s) were used to create an AutoType. enum class AutoTypeKeyword { /// auto Auto, /// decltype(auto) DecltypeAuto, /// __auto_type (GNU extension) GNUAutoType }; /// The base class of the type hierarchy. /// /// A central concept with types is that each type always has a canonical /// type. A canonical type is the type with any typedef names stripped out /// of it or the types it references. For example, consider: /// /// typedef int foo; /// typedef foo* bar; /// 'int *' 'foo *' 'bar' /// /// There will be a Type object created for 'int'. Since int is canonical, its /// CanonicalType pointer points to itself. There is also a Type for 'foo' (a /// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next /// there is a PointerType that represents 'int*', which, like 'int', is /// canonical. Finally, there is a PointerType type for 'foo*' whose canonical /// type is 'int*', and there is a TypedefType for 'bar', whose canonical type /// is also 'int*'. /// /// Non-canonical types are useful for emitting diagnostics, without losing /// information about typedefs being used. Canonical types are useful for type /// comparisons (they allow by-pointer equality tests) and useful for reasoning /// about whether something has a particular form (e.g. is a function type), /// because they implicitly, recursively, strip all typedefs out of a type. /// /// Types, once created, are immutable. /// class Type : public ExtQualsTypeCommonBase { public: enum TypeClass { #define TYPE(Class, Base) Class, #define LAST_TYPE(Class) TypeLast = Class, #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" TagFirst = Record, TagLast = Enum }; private: /// Bitfields required by the Type class. class TypeBitfields { friend class Type; template friend class TypePropertyCache; /// TypeClass bitfield - Enum that specifies what subclass this belongs to. unsigned TC : 8; /// Whether this type is a dependent type (C++ [temp.dep.type]). unsigned Dependent : 1; /// Whether this type somehow involves a template parameter, even /// if the resolution of the type does not depend on a template parameter. unsigned InstantiationDependent : 1; /// Whether this type is a variably-modified type (C99 6.7.5). unsigned VariablyModified : 1; /// Whether this type contains an unexpanded parameter pack /// (for C++11 variadic templates). unsigned ContainsUnexpandedParameterPack : 1; /// True if the cache (i.e. the bitfields here starting with /// 'Cache') is valid. mutable unsigned CacheValid : 1; /// Linkage of this type. mutable unsigned CachedLinkage : 3; /// Whether this type involves and local or unnamed types. mutable unsigned CachedLocalOrUnnamed : 1; /// Whether this type comes from an AST file. mutable unsigned FromAST : 1; bool isCacheValid() const { return CacheValid; } Linkage getLinkage() const { assert(isCacheValid() && "getting linkage from invalid cache"); return static_cast(CachedLinkage); } bool hasLocalOrUnnamedType() const { assert(isCacheValid() && "getting linkage from invalid cache"); return CachedLocalOrUnnamed; } }; enum { NumTypeBits = 18 }; protected: // These classes allow subclasses to somewhat cleanly pack bitfields // into Type. class ArrayTypeBitfields { friend class ArrayType; unsigned : NumTypeBits; /// CVR qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. unsigned IndexTypeQuals : 3; /// Storage class qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. /// Actually an ArrayType::ArraySizeModifier. unsigned SizeModifier : 3; }; class BuiltinTypeBitfields { friend class BuiltinType; unsigned : NumTypeBits; /// The kind (BuiltinType::Kind) of builtin type this is. unsigned Kind : 8; }; /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. /// Only common bits are stored here. Additional uncommon bits are stored /// in a trailing object after FunctionProtoType. class FunctionTypeBitfields { friend class FunctionProtoType; friend class FunctionType; unsigned : NumTypeBits; /// Extra information which affects how the function is called, like /// regparm and the calling convention. unsigned ExtInfo : 12; /// The ref-qualifier associated with a \c FunctionProtoType. /// /// This is a value of type \c RefQualifierKind. unsigned RefQualifier : 2; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. /// The qualifiers are part of FunctionProtoType because... /// /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. unsigned FastTypeQuals : Qualifiers::FastWidth; /// Whether this function has extended Qualifiers. unsigned HasExtQuals : 1; /// The number of parameters this function has, not counting '...'. /// According to [implimits] 8 bits should be enough here but this is /// somewhat easy to exceed with metaprogramming and so we would like to /// keep NumParams as wide as reasonably possible. unsigned NumParams : 16; /// The type of exception specification this function has. unsigned ExceptionSpecType : 4; /// Whether this function has extended parameter information. unsigned HasExtParameterInfos : 1; /// Whether the function is variadic. unsigned Variadic : 1; /// Whether this function has a trailing return type. unsigned HasTrailingReturn : 1; }; class ObjCObjectTypeBitfields { friend class ObjCObjectType; unsigned : NumTypeBits; /// The number of type arguments stored directly on this object type. unsigned NumTypeArgs : 7; /// The number of protocols stored directly on this object type. unsigned NumProtocols : 6; /// Whether this is a "kindof" type. unsigned IsKindOf : 1; }; class ReferenceTypeBitfields { friend class ReferenceType; unsigned : NumTypeBits; /// True if the type was originally spelled with an lvalue sigil. /// This is never true of rvalue references but can also be false /// on lvalue references because of C++0x [dcl.typedef]p9, /// as follows: /// /// typedef int &ref; // lvalue, spelled lvalue /// typedef int &&rvref; // rvalue /// ref &a; // lvalue, inner ref, spelled lvalue /// ref &&a; // lvalue, inner ref /// rvref &a; // lvalue, inner ref, spelled lvalue /// rvref &&a; // rvalue, inner ref unsigned SpelledAsLValue : 1; /// True if the inner type is a reference type. This only happens /// in non-canonical forms. unsigned InnerRef : 1; }; class TypeWithKeywordBitfields { friend class TypeWithKeyword; unsigned : NumTypeBits; /// An ElaboratedTypeKeyword. 8 bits for efficient access. unsigned Keyword : 8; }; enum { NumTypeWithKeywordBits = 8 }; class ElaboratedTypeBitfields { friend class ElaboratedType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// Whether the ElaboratedType has a trailing OwnedTagDecl. unsigned HasOwnedTagDecl : 1; }; class VectorTypeBitfields { friend class VectorType; friend class DependentVectorType; unsigned : NumTypeBits; /// The kind of vector, either a generic vector type or some /// target-specific vector type such as for AltiVec or Neon. unsigned VecKind : 3; /// The number of elements in the vector. unsigned NumElements : 29 - NumTypeBits; enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; }; class AttributedTypeBitfields { friend class AttributedType; unsigned : NumTypeBits; /// An AttributedType::Kind unsigned AttrKind : 32 - NumTypeBits; }; class AutoTypeBitfields { friend class AutoType; unsigned : NumTypeBits; /// Was this placeholder type spelled as 'auto', 'decltype(auto)', /// or '__auto_type'? AutoTypeKeyword value. unsigned Keyword : 2; }; class SubstTemplateTypeParmPackTypeBitfields { friend class SubstTemplateTypeParmPackType; unsigned : NumTypeBits; /// The number of template arguments in \c Arguments, which is /// expected to be able to hold at least 1024 according to [implimits]. /// However as this limit is somewhat easy to hit with template /// metaprogramming we'd prefer to keep it as large as possible. /// At the moment it has been left as a non-bitfield since this type /// safely fits in 64 bits as an unsigned, so there is no reason to /// introduce the performance impact of a bitfield. unsigned NumArgs; }; class TemplateSpecializationTypeBitfields { friend class TemplateSpecializationType; unsigned : NumTypeBits; /// Whether this template specialization type is a substituted type alias. unsigned TypeAlias : 1; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class DependentTemplateSpecializationTypeBitfields { friend class DependentTemplateSpecializationType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class PackExpansionTypeBitfields { friend class PackExpansionType; unsigned : NumTypeBits; /// The number of expansions that this pack expansion will /// generate when substituted (+1), which is expected to be able to /// hold at least 1024 according to [implimits]. However, as this limit /// is somewhat easy to hit with template metaprogramming we'd prefer to /// keep it as large as possible. At the moment it has been left as a /// non-bitfield since this type safely fits in 64 bits as an unsigned, so /// there is no reason to introduce the performance impact of a bitfield. /// /// This field will only have a non-zero value when some of the parameter /// packs that occur within the pattern have been substituted but others /// have not. unsigned NumExpansions; }; union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; ElaboratedTypeBitfields ElaboratedTypeBits; VectorTypeBitfields VectorTypeBits; SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; DependentTemplateSpecializationTypeBitfields DependentTemplateSpecializationTypeBits; PackExpansionTypeBitfields PackExpansionTypeBits; - - static_assert(sizeof(TypeBitfields) <= 8, - "TypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ArrayTypeBitfields) <= 8, - "ArrayTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AttributedTypeBitfields) <= 8, - "AttributedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AutoTypeBitfields) <= 8, - "AutoTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(BuiltinTypeBitfields) <= 8, - "BuiltinTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(FunctionTypeBitfields) <= 8, - "FunctionTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, - "ObjCObjectTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ReferenceTypeBitfields) <= 8, - "ReferenceTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(TypeWithKeywordBitfields) <= 8, - "TypeWithKeywordBitfields is larger than 8 bytes!"); - static_assert(sizeof(ElaboratedTypeBitfields) <= 8, - "ElaboratedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(VectorTypeBitfields) <= 8, - "VectorTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, - "SubstTemplateTypeParmPackTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, - "TemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, - "DependentTemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(PackExpansionTypeBitfields) <= 8, - "PackExpansionTypeBitfields is larger than 8 bytes"); }; + + static_assert(sizeof(TypeBitfields) <= 8, + "TypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ArrayTypeBitfields) <= 8, + "ArrayTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AttributedTypeBitfields) <= 8, + "AttributedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AutoTypeBitfields) <= 8, + "AutoTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(BuiltinTypeBitfields) <= 8, + "BuiltinTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionTypeBitfields) <= 8, + "FunctionTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, + "ObjCObjectTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ReferenceTypeBitfields) <= 8, + "ReferenceTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(TypeWithKeywordBitfields) <= 8, + "TypeWithKeywordBitfields is larger than 8 bytes!"); + static_assert(sizeof(ElaboratedTypeBitfields) <= 8, + "ElaboratedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(VectorTypeBitfields) <= 8, + "VectorTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, + "SubstTemplateTypeParmPackTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, + "TemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, + "DependentTemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(PackExpansionTypeBitfields) <= 8, + "PackExpansionTypeBitfields is larger than 8 bytes"); private: template friend class TypePropertyCache; /// Set whether this type comes from an AST file. void setFromAST(bool V = true) const { TypeBits.FromAST = V; } protected: friend class ASTContext; Type(TypeClass tc, QualType canon, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; TypeBits.InstantiationDependent = Dependent || InstantiationDependent; TypeBits.VariablyModified = VariablyModified; TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; TypeBits.CacheValid = false; TypeBits.CachedLocalOrUnnamed = false; TypeBits.CachedLinkage = NoLinkage; TypeBits.FromAST = false; } // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } void setDependent(bool D = true) { TypeBits.Dependent = D; if (D) TypeBits.InstantiationDependent = true; } void setInstantiationDependent(bool D = true) { TypeBits.InstantiationDependent = D; } void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } void setContainsUnexpandedParameterPack(bool PP = true) { TypeBits.ContainsUnexpandedParameterPack = PP; } public: friend class ASTReader; friend class ASTWriter; Type(const Type &) = delete; Type &operator=(const Type &) = delete; TypeClass getTypeClass() const { return static_cast(TypeBits.TC); } /// Whether this type comes from an AST file. bool isFromAST() const { return TypeBits.FromAST; } /// Whether this type is or contains an unexpanded parameter /// pack, used to support C++0x variadic templates. /// /// A type that contains a parameter pack shall be expanded by the /// ellipsis operator at some point. For example, the typedef in the /// following example contains an unexpanded parameter pack 'T': /// /// \code /// template /// struct X { /// typedef T* pointer_types; // ill-formed; T is a parameter pack. /// }; /// \endcode /// /// Note that this routine does not specify which bool containsUnexpandedParameterPack() const { return TypeBits.ContainsUnexpandedParameterPack; } /// Determines if this type would be canonical if it had no further /// qualification. bool isCanonicalUnqualified() const { return CanonicalType == QualType(this, 0); } /// Pull a single level of sugar off of this locally-unqualified type. /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() /// or QualType::getSingleStepDesugaredType(const ASTContext&). QualType getLocallyUnqualifiedSingleStepDesugaredType() const; /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. /// Return true if this is an incomplete type. /// A type that can describe objects, but which lacks information needed to /// determine its size (e.g. void, or a fwd declared struct). Clients of this /// routine will need to determine if the size is actually required. /// /// Def If non-null, and the type refers to some kind of declaration /// that can be completed (such as a C struct, C++ class, or Objective-C /// class), will be set to the declaration. bool isIncompleteType(NamedDecl **Def = nullptr) const; /// Return true if this is an incomplete or object /// type, in other words, not a function type. bool isIncompleteOrObjectType() const { return !isFunctionType(); } /// Determine whether this type is an object type. bool isObjectType() const { // C++ [basic.types]p8: // An object type is a (possibly cv-qualified) type that is not a // function type, not a reference type, and not a void type. return !isReferenceType() && !isFunctionType() && !isVoidType(); } /// Return true if this is a literal type /// (C++11 [basic.types]p10) bool isLiteralType(const ASTContext &Ctx) const; /// Test if this type is a standard-layout type. /// (C++0x [basic.type]p9) bool isStandardLayoutType() const; /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. /// Returns true if the type is a builtin type. bool isBuiltinType() const; /// Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; /// Test for a type which does not represent an actual type-system type but /// is instead used as a placeholder for various convenient purposes within /// Clang. All such types are BuiltinTypes. bool isPlaceholderType() const; const BuiltinType *getAsPlaceholderType() const; /// Test for a specific placeholder type. bool isSpecificPlaceholderType(unsigned K) const; /// Test for a placeholder type other than Overload; see /// BuiltinType::isNonOverloadPlaceholderType. bool isNonOverloadPlaceholderType() const; /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) bool isEnumeralType() const; /// Determine whether this type is a scoped enumeration type. bool isScopedEnumeralType() const; bool isBooleanType() const; bool isCharType() const; bool isWideCharType() const; bool isChar8Type() const; bool isChar16Type() const; bool isChar32Type() const; bool isAnyCharacterType() const; bool isIntegralType(const ASTContext &Ctx) const; /// Determine whether this type is an integral or enumeration type. bool isIntegralOrEnumerationType() const; /// Determine whether this type is an integral or unscoped enumeration type. bool isIntegralOrUnscopedEnumerationType() const; /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isComplexType() const; // C99 6.2.5p11 (complex) bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isFloat128Type() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) bool isAggregateType() const; bool isFundamentalType() const; bool isCompoundType() const; // Type Predicates: Check to see if this type is structurally the specified // type, ignoring typedefs and qualifiers. bool isFunctionType() const; bool isFunctionNoProtoType() const { return getAs(); } bool isFunctionProtoType() const { return getAs(); } bool isPointerType() const; bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isBlockPointerType() const; bool isVoidPointerType() const; bool isReferenceType() const; bool isLValueReferenceType() const; bool isRValueReferenceType() const; bool isFunctionPointerType() const; bool isMemberPointerType() const; bool isMemberFunctionPointerType() const; bool isMemberDataPointerType() const; bool isArrayType() const; bool isConstantArrayType() const; bool isIncompleteArrayType() const; bool isVariableArrayType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; bool isClassType() const; bool isStructureType() const; bool isObjCBoxableRecordType() const; bool isInterfaceType() const; bool isStructureOrClassType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type bool isObjCNSObjectType() const; // __attribute__((NSObject)) bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) // FIXME: change this to 'raw' interface type, so we can used 'interface' type // for the common case. bool isObjCObjectType() const; // NSString or typeof(*(id)0) bool isObjCQualifiedInterfaceType() const; // NSString bool isObjCQualifiedIdType() const; // id bool isObjCQualifiedClassType() const; // Class bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id /// Was this type written with the special inert-in-ARC __unsafe_unretained /// qualifier? /// /// This approximates the answer to the following question: if this /// translation unit were compiled in ARC, would this type be qualified /// with __unsafe_unretained? bool isObjCInertUnsafeUnretainedType() const { return hasAttr(attr::ObjCInertUnsafeUnretained); } /// Whether the type is Objective-C 'id' or a __kindof type of an /// object type, e.g., __kindof NSView * or __kindof id /// . /// /// \param bound Will be set to the bound on non-id subtype types, /// which will be (possibly specialized) Objective-C class type, or /// null for 'id. bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, const ObjCObjectType *&bound) const; bool isObjCClassType() const; // Class /// Whether the type is Objective-C 'Class' or a __kindof type of an /// Class type, e.g., __kindof Class . /// /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound /// here because Objective-C's type system cannot express "a class /// object for a subclass of NSFoo". bool isObjCClassOrClassKindOfType() const; bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isObjCARCBridgableType() const; bool isCARCBridgableType() const; bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++11 std::nullptr_t bool isAlignValT() const; // C++17 std::align_val_t bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLImageTypes.def" bool isImageType() const; // Any OpenCL image type bool isSamplerT() const; // OpenCL sampler_t bool isEventT() const; // OpenCL event_t bool isClkEventT() const; // OpenCL clk_event_t bool isQueueT() const; // OpenCL queue_t bool isReserveIDT() const; // OpenCL reserve_id_t #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLExtensionTypes.def" // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension bool isOCLIntelSubgroupAVCType() const; bool isOCLExtOpaqueType() const; // Any OpenCL extension type bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type /// Determines if this type, which must satisfy /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather /// than implicitly __strong. bool isObjCARCImplicitlyUnretainedType() const; /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; enum ScalarTypeKind { STK_CPointer, STK_BlockPointer, STK_ObjCObjectPointer, STK_MemberPointer, STK_Bool, STK_Integral, STK_Floating, STK_IntegralComplex, STK_FloatingComplex, STK_FixedPoint }; /// Given that this is a scalar type, classify it. ScalarTypeKind getScalarTypeKind() const; /// Whether this type is a dependent type, meaning that its definition /// somehow depends on a template parameter (C++ [temp.dep.type]). bool isDependentType() const { return TypeBits.Dependent; } /// Determine whether this type is an instantiation-dependent type, /// meaning that the type involves a template parameter (even if the /// definition does not actually depend on the type substituted for that /// template parameter). bool isInstantiationDependentType() const { return TypeBits.InstantiationDependent; } /// Determine whether this type is an undeduced type, meaning that /// it somehow involves a C++11 'auto' type or similar which has not yet been /// deduced. bool isUndeducedType() const; /// Whether this type is a variably-modified type (C99 6.7.5). bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } /// Whether this type involves a variable-length array type /// with a definite size. bool hasSizedVLAType() const; /// Whether this type is or contains a local or unnamed type. bool hasUnnamedOrLocalType() const; bool isOverloadableType() const; /// Determine wither this type is a C++ elaborated-type-specifier. bool isElaboratedTypeSpecifier() const; bool canDecayToPointerType() const; /// Whether this type is represented natively as a pointer. This includes /// pointers, references, block pointers, and Objective-C interface, /// qualified id, and qualified interface types, as well as nullptr_t. bool hasPointerRepresentation() const; /// Whether this type can represent an objective pointer type for the /// purpose of GC'ability bool hasObjCPointerRepresentation() const; /// Determine whether this type has an integer representation /// of some sort, e.g., it is an integer type or a vector. bool hasIntegerRepresentation() const; /// Determine whether this type has an signed integer representation /// of some sort, e.g., it is an signed integer type or a vector. bool hasSignedIntegerRepresentation() const; /// Determine whether this type has an unsigned integer representation /// of some sort, e.g., it is an unsigned integer type or a vector. bool hasUnsignedIntegerRepresentation() const; /// Determine whether this type has a floating-point representation /// of some sort, e.g., it is a floating-point type or a vector thereof. bool hasFloatingRepresentation() const; // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. const RecordType *getAsStructureType() const; /// NOTE: getAs*ArrayType are methods on ASTContext. const RecordType *getAsUnionType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. const ObjCObjectType *getAsObjCInterfaceType() const; // The following is a convenience method that returns an ObjCObjectPointerType // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; /// Retrieves the CXXRecordDecl that this type refers to, either /// because the type is a RecordType or because it is the injected-class-name /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; /// Retrieves the RecordDecl this type refers to. RecordDecl *getAsRecordDecl() const; /// Retrieves the TagDecl that this type refers to, either /// because the type is a TagType or because it is the injected-class-name /// type of a class template or class template partial specialization. TagDecl *getAsTagDecl() const; /// If this is a pointer or reference to a RecordType, return the /// CXXRecordDecl that the type refers to. /// /// If this is not a pointer or reference, or the type being pointed to does /// not refer to a CXXRecordDecl, returns NULL. const CXXRecordDecl *getPointeeCXXRecordDecl() const; /// Get the DeducedType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. DeducedType *getContainedDeducedType() const; /// Get the AutoType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. AutoType *getContainedAutoType() const { return dyn_cast_or_null(getContainedDeducedType()); } /// Determine whether this type was written with a leading 'auto' /// corresponding to a trailing return type (possibly for a nested /// function type within a pointer to function type or similar). bool hasAutoForTrailingReturnType() const; /// Member-template getAs'. Look through sugar for /// an instance of \. This scheme will eventually /// replace the specific getAsXXXX methods above. /// /// There are some specializations of this member template listed /// immediately following this class. template const T *getAs() const; /// Member-template getAsAdjusted. Look through specific kinds /// of sugar (parens, attributes, etc) for an instance of \. /// This is used when you need to walk over sugar nodes that represent some /// kind of type adjustment from a type that was written as a \ /// to another type that is still canonically a \. template const T *getAsAdjusted() const; /// A variant of getAs<> for array types which silently discards /// qualifiers from the outermost type. const ArrayType *getAsArrayTypeUnsafe() const; /// Member-template castAs. Look through sugar for /// the underlying instance of \. /// /// This method has the same relationship to getAs as cast has /// to dyn_cast; which is to say, the underlying type *must* /// have the intended type, and this method will never return null. template const T *castAs() const; /// A variant of castAs<> for array type which silently discards /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; /// Determine whether this type had the specified attribute applied to it /// (looking through top-level type sugar). bool hasAttr(attr::Kind AK) const; /// Get the base element type of this type, potentially discarding type /// qualifiers. This should never be used when type qualifiers /// are meaningful. const Type *getBaseElementTypeUnsafe() const; /// If this is an array type, return the element type of the array, /// potentially with type qualifiers missing. /// This should never be used when type qualifiers are meaningful. const Type *getArrayElementTypeNoTypeQual() const; /// If this is a pointer type, return the pointee type. /// If this is an array type, return the array element type. /// This should never be used when type qualifiers are meaningful. const Type *getPointeeOrArrayElementType() const; /// If this is a pointer, ObjC object pointer, or block /// pointer, this returns the respective pointee. QualType getPointeeType() const; /// Return the specified type with any "sugar" removed from the type, /// removing any typedefs, typeofs, etc., as well as any qualifiers. const Type *getUnqualifiedDesugaredType() const; /// More type predicates useful for type checking/promotion bool isPromotableIntegerType() const; // C99 6.3.1.1p2 /// Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// or an enum decl which has a signed representation. bool isSignedIntegerType() const; /// Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], /// or an enum decl which has an unsigned representation. bool isUnsignedIntegerType() const; /// Determines whether this is an integer type that is signed or an /// enumeration types whose underlying type is a signed integer type. bool isSignedIntegerOrEnumerationType() const; /// Determines whether this is an integer type that is unsigned or an /// enumeration types whose underlying type is a unsigned integer type. bool isUnsignedIntegerOrEnumerationType() const; /// Return true if this is a fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. bool isFixedPointType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isSaturatedFixedPointType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isUnsaturatedFixedPointType() const; /// Return true if this is a fixed point type that is signed according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isSignedFixedPointType() const; /// Return true if this is a fixed point type that is unsigned according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isUnsignedFixedPointType() const; /// Return true if this is not a variable sized type, /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. bool isConstantSizeType() const; /// Returns true if this type can be represented by some /// set of type specifiers. bool isSpecifierType() const; /// Determine the linkage of this type. Linkage getLinkage() const; /// Determine the visibility of this type. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); } /// Return true if the visibility was explicitly set is the code. bool isVisibilityExplicit() const { return getLinkageAndVisibility().isVisibilityExplicit(); } /// Determine the linkage and visibility of this type. LinkageInfo getLinkageAndVisibility() const; /// True if the computed linkage is valid. Used for consistency /// checking. Should always return true. bool isLinkageValid() const; /// Determine the nullability of the given type. /// /// Note that nullability is only captured as sugar within the type /// system, not as part of the canonical type, so nullability will /// be lost by canonicalization and desugaring. Optional getNullability(const ASTContext &context) const; /// Determine whether the given type can have a nullability /// specifier applied to it, i.e., if it is any kind of pointer type. /// /// \param ResultIfUnknown The value to return if we don't yet know whether /// this type can have nullability because it is dependent. bool canHaveNullability(bool ResultIfUnknown = true) const; /// Retrieve the set of substitutions required when accessing a member /// of the Objective-C receiver type that is declared in the given context. /// /// \c *this is the type of the object we're operating on, e.g., the /// receiver for a message send or the base of a property access, and is /// expected to be of some object or object pointer type. /// /// \param dc The declaration context for which we are building up a /// substitution mapping, which should be an Objective-C class, extension, /// category, or method within. /// /// \returns an array of type arguments that can be substituted for /// the type parameters of the given declaration context in any type described /// within that context, or an empty optional to indicate that no /// substitution is required. Optional> getObjCSubstitutions(const DeclContext *dc) const; /// Determines if this is an ObjC interface type that may accept type /// parameters. bool acceptsObjCTypeParams() const; const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { return CanonicalType; } CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; void dump(llvm::raw_ostream &OS) const; }; /// This will check for a TypedefType by removing any existing sugar /// until it reaches a TypedefType or a non-sugared type. template <> const TypedefType *Type::getAs() const; /// This will check for a TemplateSpecializationType by removing any /// existing sugar until it reaches a TemplateSpecializationType or a /// non-sugared type. template <> const TemplateSpecializationType *Type::getAs() const; /// This will check for an AttributedType by removing any existing sugar /// until it reaches an AttributedType or a non-sugared type. template <> const AttributedType *Type::getAs() const; // We can do canonical leaf types faster, because we don't have to // worry about preserving child type decoration. #define TYPE(Class, Base) #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ return dyn_cast(CanonicalType); \ } \ template <> inline const Class##Type *Type::castAs() const { \ return cast(CanonicalType); \ } #include "clang/AST/TypeNodes.def" /// This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { public: enum Kind { // OpenCL image types #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, #include "clang/Basic/OpenCLImageTypes.def" // OpenCL extension types #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, #include "clang/Basic/OpenCLExtensionTypes.def" // All other builtin types #define BUILTIN_TYPE(Id, SingletonId) Id, #define LAST_BUILTIN_TYPE(Id) LastKind = Id #include "clang/AST/BuiltinTypes.def" }; private: friend class ASTContext; // ASTContext creates these. BuiltinType(Kind K) : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), /*InstantiationDependent=*/(K == Dependent), /*VariablyModified=*/false, /*Unexpanded parameter pack=*/false) { BuiltinTypeBits.Kind = K; } public: Kind getKind() const { return static_cast(BuiltinTypeBits.Kind); } StringRef getName(const PrintingPolicy &Policy) const; const char *getNameAsCString(const PrintingPolicy &Policy) const { // The StringRef is null-terminated. StringRef str = getName(Policy); assert(!str.empty() && str.data()[str.size()] == '\0'); return str.data(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } bool isInteger() const { return getKind() >= Bool && getKind() <= Int128; } bool isSignedInteger() const { return getKind() >= Char_S && getKind() <= Int128; } bool isUnsignedInteger() const { return getKind() >= Bool && getKind() <= UInt128; } bool isFloatingPoint() const { return getKind() >= Half && getKind() <= Float128; } /// Determines whether the given kind corresponds to a placeholder type. static bool isPlaceholderTypeKind(Kind K) { return K >= Overload; } /// Determines whether this type is a placeholder type, i.e. a type /// which cannot appear in arbitrary positions in a fully-formed /// expression. bool isPlaceholderType() const { return isPlaceholderTypeKind(getKind()); } /// Determines whether this type is a placeholder type other than /// Overload. Most placeholder types require only syntactic /// information about their context in order to be resolved (e.g. /// whether it is a call expression), which means they can (and /// should) be resolved in an earlier "phase" of analysis. /// Overload expressions sometimes pick up further information /// from their context, like whether the context expects a /// specific function-pointer type, and so frequently need /// special treatment. bool isNonOverloadPlaceholderType() const { return getKind() > Overload; } static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } }; /// Complex values, per C99 6.2.5p11. This supports the C99 complex /// types (_Complex float etc) as well as the GCC integer complex extensions. class ComplexType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) : Type(Complex, CanonicalPtr, Element->isDependentType(), Element->isInstantiationDependentType(), Element->isVariablyModifiedType(), Element->containsUnexpandedParameterPack()), ElementType(Element) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { ID.AddPointer(Element.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Complex; } }; /// Sugar for parentheses used when specifying types. class ParenType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType Inner; ParenType(QualType InnerType, QualType CanonType) : Type(Paren, CanonType, InnerType->isDependentType(), InnerType->isInstantiationDependentType(), InnerType->isVariablyModifiedType(), InnerType->containsUnexpandedParameterPack()), Inner(InnerType) {} public: QualType getInnerType() const { return Inner; } bool isSugared() const { return true; } QualType desugar() const { return getInnerType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInnerType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { Inner.Profile(ID); } static bool classof(const Type *T) { return T->getTypeClass() == Paren; } }; /// PointerType - C99 6.7.5.1 - Pointer Declarators. class PointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr) : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if address spaces of pointers overlap. /// OpenCL v2.0 defines conversion rules for pointers to different /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping /// address spaces. /// CL1.1 or CL1.2: /// address spaces overlap iff they are they same. /// CL2.0 adds: /// __generic overlaps with any address space except for __constant. bool isAddressSpaceOverlapping(const PointerType &other) const { Qualifiers thisQuals = PointeeType.getQualifiers(); Qualifiers otherQuals = other.getPointeeType().getQualifiers(); // Address spaces overlap if at least one of them is a superset of another return thisQuals.isAddressSpaceSupersetOf(otherQuals) || otherQuals.isAddressSpaceSupersetOf(thisQuals); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } }; /// Represents a type which was implicitly adjusted by the semantic /// engine for arbitrary reasons. For example, array and function types can /// decay, and function types can have their calling conventions adjusted. class AdjustedType : public Type, public llvm::FoldingSetNode { QualType OriginalTy; QualType AdjustedTy; protected: friend class ASTContext; // ASTContext creates these. AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, QualType CanonicalPtr) : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), OriginalTy->isInstantiationDependentType(), OriginalTy->isVariablyModifiedType(), OriginalTy->containsUnexpandedParameterPack()), OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} public: QualType getOriginalType() const { return OriginalTy; } QualType getAdjustedType() const { return AdjustedTy; } bool isSugared() const { return true; } QualType desugar() const { return AdjustedTy; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, OriginalTy, AdjustedTy); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { ID.AddPointer(Orig.getAsOpaquePtr()); ID.AddPointer(New.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; } }; /// Represents a pointer type decayed from an array or function type. class DecayedType : public AdjustedType { friend class ASTContext; // ASTContext creates these. inline DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); public: QualType getDecayedType() const { return getAdjustedType(); } inline QualType getPointeeType() const; static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } }; /// Pointer to a block type. /// This type is to represent types syntactically represented as /// "void (^)(int)", etc. Pointee is required to always be a function type. class BlockPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. // Block is some kind of pointer type QualType PointeeType; BlockPointerType(QualType Pointee, QualType CanonicalCls) : Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: // Get the pointee type. Pointee is required to always be a function type. QualType getPointeeType() const { return PointeeType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == BlockPointer; } }; /// Base for LValueReferenceType and RValueReferenceType class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : Type(tc, CanonicalRef, Referencee->isDependentType(), Referencee->isInstantiationDependentType(), Referencee->isVariablyModifiedType(), Referencee->containsUnexpandedParameterPack()), PointeeType(Referencee) { ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } public: bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } QualType getPointeeTypeAsWritten() const { return PointeeType; } QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; while (T->isInnerRef()) T = T->PointeeType->castAs(); return T->PointeeType; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, PointeeType, isSpelledAsLValue()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, bool SpelledAsLValue) { ID.AddPointer(Referencee.getAsOpaquePtr()); ID.AddBoolean(SpelledAsLValue); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference || T->getTypeClass() == RValueReference; } }; /// An lvalue reference type, per C++11 [dcl.ref]. class LValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these LValueReferenceType(QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference; } }; /// An rvalue reference type, per C++11 [dcl.ref]. class RValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these RValueReferenceType(QualType Referencee, QualType CanonicalRef) : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == RValueReference; } }; /// A pointer to member type per C++ 8.3.3 - Pointers to members. /// /// This includes both pointers to data members and pointer to member functions. class MemberPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; /// The class of which the pointee is a member. Must ultimately be a /// RecordType, but could be a typedef or a template parameter too. const Type *Class; MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, Cls->isDependentType() || Pointee->isDependentType(), (Cls->isInstantiationDependentType() || Pointee->isInstantiationDependentType()), Pointee->isVariablyModifiedType(), (Cls->containsUnexpandedParameterPack() || Pointee->containsUnexpandedParameterPack())), PointeeType(Pointee), Class(Cls) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if the member type (i.e. the pointee type) is a /// function type rather than a data-member type. bool isMemberFunctionPointer() const { return PointeeType->isFunctionProtoType(); } /// Returns true if the member type (i.e. the pointee type) is a /// data type rather than a function type. bool isMemberDataPointer() const { return !PointeeType->isFunctionProtoType(); } const Type *getClass() const { return Class; } CXXRecordDecl *getMostRecentCXXRecordDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), getClass()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, const Type *Class) { ID.AddPointer(Pointee.getAsOpaquePtr()); ID.AddPointer(Class); } static bool classof(const Type *T) { return T->getTypeClass() == MemberPointer; } }; /// Represents an array type, per C99 6.7.5.2 - Array Declarators. class ArrayType : public Type, public llvm::FoldingSetNode { public: /// Capture whether this is a normal array (e.g. int X[4]) /// an array with a static size (e.g. int X[static 4]), or an array /// with a star size (e.g. int X[*]). /// 'static' is only allowed on function parameters. enum ArraySizeModifier { Normal, Static, Star }; private: /// The element type of the array. QualType ElementType; protected: friend class ASTContext; // ASTContext creates these. // C++ [temp.dep.type]p1: // A type is dependent if it is... // - an array type constructed from any dependent type or whose // size is specified by a constant expression that is // value-dependent, ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, bool ContainsUnexpandedParameterPack) : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, et->isInstantiationDependentType() || tc == DependentSizedArray, (tc == VariableArray || et->isVariablyModifiedType()), ContainsUnexpandedParameterPack), ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; } public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(ArrayTypeBits.SizeModifier); } Qualifiers getIndexTypeQualifiers() const { return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); } unsigned getIndexTypeCVRQualifiers() const { return ArrayTypeBits.IndexTypeQuals; } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || T->getTypeClass() == DependentSizedArray; } }; /// Represents the canonical version of C arrays with a specified constant size. /// For example, the canonical type for 'int A[4 + 4*100]' is a /// ConstantArrayType where the element type is 'int' and the size is 404. class ConstantArrayType : public ArrayType { llvm::APInt Size; // Allows us to unique the type. ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) : ArrayType(ConstantArray, et, can, sm, tq, et->containsUnexpandedParameterPack()), Size(size) {} protected: friend class ASTContext; // ASTContext creates these. ConstantArrayType(TypeClass tc, QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), Size(size) {} public: const llvm::APInt &getSize() const { return Size; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Determine the number of bits required to address a member of // an array with the given element type and number of elements. static unsigned getNumAddressingBits(const ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements); /// Determine the maximum number of active bits that an array's size /// can require, which limits the maximum size of the array. static unsigned getMaxSizeBits(const ASTContext &Context); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSize(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(ArraySize.getZExtValue()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray; } }; /// Represents a C array with an unspecified size. For example 'int A[]' has /// an IncompleteArrayType where the element type is 'int' and the size is /// unspecified. class IncompleteArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, unsigned tq) : ArrayType(IncompleteArray, et, can, sm, tq, et->containsUnexpandedParameterPack()) {} public: friend class StmtIteratorBase; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == IncompleteArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } }; /// Represents a C array with a specified size that is not an /// integer-constant-expression. For example, 'int s[x+foo()]'. /// Since the size expression is an arbitrary expression, we store it as such. /// /// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and /// should not be: two lexically equivalent variable array types could mean /// different things, for example, these variables do not have the same type /// dynamically: /// /// void foo(int x) { /// int Y[x]; /// ++x; /// int Z[x]; /// } class VariableArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. /// An assignment-expression. VLA's are only permitted within /// a function block. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) : ArrayType(VariableArray, et, can, sm, tq, et->containsUnexpandedParameterPack()), SizeExpr((Stmt*) e), Brackets(brackets) {} public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == VariableArray; } void Profile(llvm::FoldingSetNodeID &ID) { llvm_unreachable("Cannot unique VariableArrayTypes."); } }; /// Represents an array type in C++ whose size is a value-dependent expression. /// /// For example: /// \code /// template /// class array { /// T data[Size]; /// }; /// \endcode /// /// For these types, we won't actually know what the array bound is /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. const ASTContext &Context; /// An assignment expression that will instantiate to the /// size of the array. /// /// The expression itself might be null, in which case the array /// type will have its size deduced from an initializer. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets); public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E); }; /// Represents an extended address space qualifier where the input address space /// value is dependent. Non-dependent address spaces are not represented with a /// special Type subclass; they are stored on an ExtQuals node as part of a QualType. /// /// For example: /// \code /// template /// class AddressSpace { /// typedef T __attribute__((address_space(AddrSpace))) type; /// } /// \endcode class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *AddrSpaceExpr; QualType PointeeType; SourceLocation loc; DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, QualType can, Expr *AddrSpaceExpr, SourceLocation loc); public: Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } QualType getPointeeType() const { return PointeeType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentAddressSpace; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType PointeeType, Expr *AddrSpaceExpr); }; /// Represents an extended vector type where either the type or size is /// dependent. /// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((ext_vector_type(Size))) type; /// } /// \endcode class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *SizeExpr; /// The element type of the array. QualType ElementType; SourceLocation loc; DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, QualType can, Expr *SizeExpr, SourceLocation loc); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedExtVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, Expr *SizeExpr); }; /// Represents a GCC generic vector type. This type is created using /// __attribute__((vector_size(n)), where "n" specifies the vector size in /// bytes; or from an Altivec __vector or vector declaration. /// Since the constructor takes the number of vector elements, the /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { public: enum VectorKind { /// not a target-specific vector type GenericVector, /// is AltiVec vector AltiVecVector, /// is AltiVec 'vector Pixel' AltiVecPixel, /// is AltiVec 'vector bool ...' AltiVecBool, /// is ARM Neon vector NeonVector, /// is ARM Neon polynomial vector NeonPolyVector }; protected: friend class ASTContext; // ASTContext creates these. /// The element type of the vector. QualType ElementType; VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); public: QualType getElementType() const { return ElementType; } unsigned getNumElements() const { return VectorTypeBits.NumElements; } static bool isVectorSizeTooLarge(unsigned NumElements) { return NumElements > VectorTypeBitfields::MaxNumElements; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } VectorKind getVectorKind() const { return VectorKind(VectorTypeBits.VecKind); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass, VectorKind VecKind) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); ID.AddInteger(VecKind); } static bool classof(const Type *T) { return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } }; /// Represents a vector type where either the type or size is dependent. //// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((vector_size(Size))) type; /// } /// \endcode class DependentVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; QualType ElementType; Expr *SizeExpr; SourceLocation Loc; DependentVectorType(const ASTContext &Context, QualType ElementType, QualType CanonType, Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind vecKind); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return Loc; } VectorType::VectorKind getVectorKind() const { return VectorType::VectorKind(VectorTypeBits.VecKind); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, const Expr *SizeExpr, VectorType::VectorKind VecKind); }; /// ExtVectorType - Extended vector type. This type is created using /// __attribute__((ext_vector_type(n)), where "n" is the number of elements. /// Unlike vector_size, ext_vector_type is only allowed on typedef's. This /// class enables syntactic extensions, like Vector Components for accessing /// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL /// Shading Language). class ExtVectorType : public VectorType { friend class ASTContext; // ASTContext creates these. ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} public: static int getPointAccessorIdx(char c) { switch (c) { default: return -1; case 'x': case 'r': return 0; case 'y': case 'g': return 1; case 'z': case 'b': return 2; case 'w': case 'a': return 3; } } static int getNumericAccessorIdx(char c) { switch (c) { default: return -1; case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } } static int getAccessorIdx(char c, bool isNumericAccessor) { if (isNumericAccessor) return getNumericAccessorIdx(c); else return getPointAccessorIdx(c); } bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const { if (int idx = getAccessorIdx(c, isNumericAccessor)+1) return unsigned(idx-1) < getNumElements(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ExtVector; } }; /// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base /// class of FunctionNoProtoType and FunctionProtoType. class FunctionType : public Type { // The type returned by the function. QualType ResultType; public: /// Interesting information about a specific parameter that can't simply /// be reflected in parameter's type. This is only used by FunctionProtoType /// but is in FunctionType to make this class available during the /// specification of the bases of FunctionProtoType. /// /// It makes sense to model language features this way when there's some /// sort of parameter-specific override (such as an attribute) that /// affects how the function is called. For example, the ARC ns_consumed /// attribute changes whether a parameter is passed at +0 (the default) /// or +1 (ns_consumed). This must be reflected in the function type, /// but isn't really a change to the parameter type. /// /// One serious disadvantage of modelling language features this way is /// that they generally do not work with language features that attempt /// to destructure types. For example, template argument deduction will /// not be able to match a parameter declared as /// T (*)(U) /// against an argument of type /// void (*)(__attribute__((ns_consumed)) id) /// because the substitution of T=void, U=id into the former will /// not produce the latter. class ExtParameterInfo { enum { ABIMask = 0x0F, IsConsumed = 0x10, HasPassObjSize = 0x20, IsNoEscape = 0x40, }; unsigned char Data = 0; public: ExtParameterInfo() = default; /// Return the ABI treatment of this parameter. ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } ExtParameterInfo withABI(ParameterABI kind) const { ExtParameterInfo copy = *this; copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); return copy; } /// Is this parameter considered "consumed" by Objective-C ARC? /// Consumed parameters must have retainable object type. bool isConsumed() const { return (Data & IsConsumed); } ExtParameterInfo withIsConsumed(bool consumed) const { ExtParameterInfo copy = *this; if (consumed) copy.Data |= IsConsumed; else copy.Data &= ~IsConsumed; return copy; } bool hasPassObjectSize() const { return Data & HasPassObjSize; } ExtParameterInfo withHasPassObjectSize() const { ExtParameterInfo Copy = *this; Copy.Data |= HasPassObjSize; return Copy; } bool isNoEscape() const { return Data & IsNoEscape; } ExtParameterInfo withIsNoEscape(bool NoEscape) const { ExtParameterInfo Copy = *this; if (NoEscape) Copy.Data |= IsNoEscape; else Copy.Data &= ~IsNoEscape; return Copy; } unsigned char getOpaqueValue() const { return Data; } static ExtParameterInfo getFromOpaqueValue(unsigned char data) { ExtParameterInfo result; result.Data = data; return result; } friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data == rhs.Data; } friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data != rhs.Data; } }; /// A class which abstracts out some details necessary for /// making a call. /// /// It is not actually used directly for storing this information in /// a FunctionType, although FunctionType does currently use the /// same bit-pattern. /// // If you add a field (say Foo), other than the obvious places (both, // constructors, compile failures), what you need to update is // * Operator== // * getFoo // * withFoo // * functionType. Add Foo, getFoo. // * ASTContext::getFooType // * ASTContext::mergeFunctionTypes // * FunctionNoProtoType::Profile // * FunctionProtoType::Profile // * TypePrinter::PrintFunctionProto // * AST read and write // * Codegen class ExtInfo { friend class FunctionType; // Feel free to rearrange or add bits, but if you go over 12, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck| // |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 | // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; enum { NoCallerSavedRegsMask = 0x80 }; enum { NoCfCheckMask = 0x800 }; enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | NoCallerSavedRegsMask | NoCfCheckMask), RegParmOffset = 8 }; // Assumed to be the last field uint16_t Bits = CC_C; ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs, bool NoCfCheck) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | (producesResult ? ProducesResultMask : 0) | (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | (NoCfCheck ? NoCfCheckMask : 0); } // Constructor with all defaults. Use when for example creating a // function known to use defaults. ExtInfo() = default; // Constructor with just the calling convention, which is an important part // of the canonical type. ExtInfo(CallingConv CC) : Bits(CC) {} bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getNoCfCheck() const { return Bits & NoCfCheckMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset; if (RegParm > 0) --RegParm; return RegParm; } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } bool operator==(ExtInfo Other) const { return Bits == Other.Bits; } bool operator!=(ExtInfo Other) const { return Bits != Other.Bits; } // Note that we don't have setters. That is by design, use // the following with methods instead of mutating these objects. ExtInfo withNoReturn(bool noReturn) const { if (noReturn) return ExtInfo(Bits | NoReturnMask); else return ExtInfo(Bits & ~NoReturnMask); } ExtInfo withProducesResult(bool producesResult) const { if (producesResult) return ExtInfo(Bits | ProducesResultMask); else return ExtInfo(Bits & ~ProducesResultMask); } ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { if (noCallerSavedRegs) return ExtInfo(Bits | NoCallerSavedRegsMask); else return ExtInfo(Bits & ~NoCallerSavedRegsMask); } ExtInfo withNoCfCheck(bool noCfCheck) const { if (noCfCheck) return ExtInfo(Bits | NoCfCheckMask); else return ExtInfo(Bits & ~NoCfCheckMask); } ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | ((RegParm + 1) << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } }; /// A simple holder for a QualType representing a type in an /// exception specification. Unfortunately needed by FunctionProtoType /// because TrailingObjects cannot handle repeated types. struct ExceptionType { QualType Type; }; /// A simple holder for various uncommon bits which do not fit in /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the /// alignment of subsequent objects in TrailingObjects. You must update /// hasExtraBitfields in FunctionProtoType after adding extra data here. struct alignas(void *) FunctionTypeExtraBitfields { /// The number of types in the exception specification. /// A whole unsigned is not needed here and according to /// [implimits] 8 bits would be enough here. unsigned NumExceptionType; }; protected: FunctionType(TypeClass tc, QualType res, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; } Qualifiers getFastTypeQuals() const { return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); } public: QualType getReturnType() const { return ResultType; } bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } /// Determine whether this function type includes the GNU noreturn /// attribute. The C++11 [[noreturn]] attribute does not affect the function /// type. bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, "Const, volatile and restrict are assumed to be a subset of " "the fast qualifiers."); bool isConst() const { return getFastTypeQuals().hasConst(); } bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } /// Determine the type of an expression that calls a function of /// this type. QualType getCallResultType(const ASTContext &Context) const { return getReturnType().getNonLValueExprType(Context); } static StringRef getNameForCallConv(CallingConv CC); static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; } }; /// Represents a K&R-style 'int foo()' function, which has /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) : FunctionType(FunctionNoProto, Result, Canonical, /*Dependent=*/false, /*InstantiationDependent=*/false, Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} public: // No additional state past what FunctionType provides. bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReturnType(), getExtInfo()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, ExtInfo Info) { Info.Profile(ID); ID.AddPointer(ResultType.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } }; /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no /// parameters, not as having a single void parameter. Such a type can have /// an exception specification, but this specification is not part of the /// canonical type. FunctionProtoType has several trailing objects, some of /// which optional. For more information about the trailing objects see /// the first comment inside FunctionProtoType. class FunctionProtoType final : public FunctionType, public llvm::FoldingSetNode, private llvm::TrailingObjects< FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; // FunctionProtoType is followed by several trailing objects, some of // which optional. They are in order: // // * An array of getNumParams() QualType holding the parameter types. // Always present. Note that for the vast majority of FunctionProtoType, // these will be the only trailing objects. // // * Optionally if some extra data is stored in FunctionTypeExtraBitfields // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): // a single FunctionTypeExtraBitfields. Present if and only if // hasExtraBitfields() is true. // // * Optionally exactly one of: // * an array of getNumExceptions() ExceptionType, // * a single Expr *, // * a pair of FunctionDecl *, // * a single FunctionDecl * // used to store information about the various types of exception // specification. See getExceptionSpecSize for the details. // // * Optionally an array of getNumParams() ExtParameterInfo holding // an ExtParameterInfo for each of the parameters. Present if and // only if hasExtParameterInfos() is true. // // * Optionally a Qualifiers object to represent extra qualifiers that can't // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only // if hasExtQualifiers() is true. // // The optional FunctionTypeExtraBitfields has to be before the data // related to the exception specification since it contains the number // of exception types. // // We put the ExtParameterInfos last. If all were equal, it would make // more sense to put these before the exception specification, because // it's much easier to skip past them compared to the elaborate switch // required to skip the exception specification. However, all is not // equal; ExtParameterInfos are used to model very uncommon features, // and it's better not to burden the more common paths. public: /// Holds information about the various types of exception specification. /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is /// used to group together the various bits of information about the /// exception specification. struct ExceptionSpecInfo { /// The kind of exception specification this is. ExceptionSpecificationType Type = EST_None; /// Explicitly-specified list of exception types. ArrayRef Exceptions; /// Noexcept expression, if this is a computed noexcept specification. Expr *NoexceptExpr = nullptr; /// The function whose exception specification this is, for /// EST_Unevaluated and EST_Uninstantiated. FunctionDecl *SourceDecl = nullptr; /// The function template whose exception specification this is instantiated /// from, for EST_Uninstantiated. FunctionDecl *SourceTemplate = nullptr; ExceptionSpecInfo() = default; ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; /// Extra information about a function prototype. ExtProtoInfo is not /// stored as such in FunctionProtoType but is used to group together /// the various bits of extra information about a function prototype. struct ExtProtoInfo { FunctionType::ExtInfo ExtInfo; bool Variadic : 1; bool HasTrailingReturn : 1; Qualifiers TypeQuals; RefQualifierKind RefQualifier = RQ_None; ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { ExtProtoInfo Result(*this); Result.ExceptionSpec = ESI; return Result; } }; private: unsigned numTrailingObjects(OverloadToken) const { return getNumParams(); } unsigned numTrailingObjects(OverloadToken) const { return hasExtraBitfields(); } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExceptionType; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExprPtr; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumFunctionDeclPtr; } unsigned numTrailingObjects(OverloadToken) const { return hasExtParameterInfos() ? getNumParams() : 0; } /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, unsigned numArgs) { for (unsigned Idx = 0; Idx < numArgs; ++Idx) if (ArgArray[Idx]->containsUnexpandedParameterPack()) return true; return false; } FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi); /// This struct is returned by getExceptionSpecSize and is used to /// translate an ExceptionSpecificationType to the number and kind /// of trailing objects related to the exception specification. struct ExceptionSpecSizeHolder { unsigned NumExceptionType; unsigned NumExprPtr; unsigned NumFunctionDeclPtr; }; /// Return the number and kind of trailing objects /// related to the exception specification. static ExceptionSpecSizeHolder getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { switch (EST) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_Unparsed: return {0, 0, 0}; case EST_Dynamic: return {NumExceptions, 0, 0}; case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: return {0, 1, 0}; case EST_Uninstantiated: return {0, 0, 2}; case EST_Unevaluated: return {0, 0, 1}; } llvm_unreachable("bad exception specification kind"); } /// Return the number and kind of trailing objects /// related to the exception specification. ExceptionSpecSizeHolder getExceptionSpecSize() const { return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); } /// Whether the trailing FunctionTypeExtraBitfields is present. static bool hasExtraBitfields(ExceptionSpecificationType EST) { // If the exception spec type is EST_Dynamic then we have > 0 exception // types and the exact number is stored in FunctionTypeExtraBitfields. return EST == EST_Dynamic; } /// Whether the trailing FunctionTypeExtraBitfields is present. bool hasExtraBitfields() const { return hasExtraBitfields(getExceptionSpecType()); } bool hasExtQualifiers() const { return FunctionTypeBits.HasExtQuals; } public: unsigned getNumParams() const { return FunctionTypeBits.NumParams; } QualType getParamType(unsigned i) const { assert(i < getNumParams() && "invalid parameter index"); return param_type_begin()[i]; } ArrayRef getParamTypes() const { return llvm::makeArrayRef(param_type_begin(), param_type_end()); } ExtProtoInfo getExtProtoInfo() const { ExtProtoInfo EPI; EPI.ExtInfo = getExtInfo(); EPI.Variadic = isVariadic(); EPI.HasTrailingReturn = hasTrailingReturn(); EPI.ExceptionSpec.Type = getExceptionSpecType(); EPI.TypeQuals = getTypeQuals(); EPI.RefQualifier = getRefQualifier(); if (EPI.ExceptionSpec.Type == EST_Dynamic) { EPI.ExceptionSpec.Exceptions = exceptions(); } else if (isComputedNoexcept(EPI.ExceptionSpec.Type)) { EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr(); } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate(); } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } EPI.ExtParameterInfos = getExtParameterInfosOrNull(); return EPI; } /// Get the kind of exception specification on this function. ExceptionSpecificationType getExceptionSpecType() const { return static_cast( FunctionTypeBits.ExceptionSpecType); } /// Return whether this function has any kind of exception spec. bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { return isDynamicExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a noexcept exception spec. bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a dependent exception spec. bool hasDependentExceptionSpec() const; /// Return whether this function has an instantiation-dependent exception /// spec. bool hasInstantiationDependentExceptionSpec() const; /// Return the number of types in the exception specification. unsigned getNumExceptions() const { return getExceptionSpecType() == EST_Dynamic ? getTrailingObjects() ->NumExceptionType : 0; } /// Return the ith exception type, where 0 <= i < getNumExceptions(). QualType getExceptionType(unsigned i) const { assert(i < getNumExceptions() && "Invalid exception number!"); return exception_begin()[i]; } /// Return the expression inside noexcept(expression), or a null pointer /// if there is none (because the exception spec is not of this form). Expr *getNoexceptExpr() const { if (!isComputedNoexcept(getExceptionSpecType())) return nullptr; return *getTrailingObjects(); } /// If this function type has an exception specification which hasn't /// been determined yet (either because it has not been evaluated or because /// it has not been instantiated), this is the function whose exception /// specification is represented by this type. FunctionDecl *getExceptionSpecDecl() const { if (getExceptionSpecType() != EST_Uninstantiated && getExceptionSpecType() != EST_Unevaluated) return nullptr; return getTrailingObjects()[0]; } /// If this function type has an uninstantiated exception /// specification, this is the function whose exception specification /// should be instantiated to find the exception specification for /// this type. FunctionDecl *getExceptionSpecTemplate() const { if (getExceptionSpecType() != EST_Uninstantiated) return nullptr; return getTrailingObjects()[1]; } /// Determine whether this function type has a non-throwing exception /// specification. CanThrowResult canThrow() const; /// Determine whether this function type has a non-throwing exception /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. bool isNothrow(bool ResultIfDependent = false) const { return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; } /// Whether this function prototype is variadic. bool isVariadic() const { return FunctionTypeBits.Variadic; } /// Determines whether this function prototype contains a /// parameter pack at the end. /// /// A function template whose last parameter is a parameter pack can be /// called with an arbitrary number of arguments, much like a variadic /// function. bool isTemplateVariadic() const; /// Whether this function prototype has a trailing return type. bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } Qualifiers getTypeQuals() const { if (hasExtQualifiers()) return *getTrailingObjects(); else return getFastTypeQuals(); } /// Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { return static_cast(FunctionTypeBits.RefQualifier); } using param_type_iterator = const QualType *; using param_type_range = llvm::iterator_range; param_type_range param_types() const { return param_type_range(param_type_begin(), param_type_end()); } param_type_iterator param_type_begin() const { return getTrailingObjects(); } param_type_iterator param_type_end() const { return param_type_begin() + getNumParams(); } using exception_iterator = const QualType *; ArrayRef exceptions() const { return llvm::makeArrayRef(exception_begin(), exception_end()); } exception_iterator exception_begin() const { return reinterpret_cast( getTrailingObjects()); } exception_iterator exception_end() const { return exception_begin() + getNumExceptions(); } /// Is there any interesting extra information for any of the parameters /// of this function type? bool hasExtParameterInfos() const { return FunctionTypeBits.HasExtParameterInfos; } ArrayRef getExtParameterInfos() const { assert(hasExtParameterInfos()); return ArrayRef(getTrailingObjects(), getNumParams()); } /// Return a pointer to the beginning of the array of extra parameter /// information, if present, or else null if none of the parameters /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. const ExtParameterInfo *getExtParameterInfosOrNull() const { if (!hasExtParameterInfos()) return nullptr; return getTrailingObjects(); } ExtParameterInfo getExtParameterInfo(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I]; return ExtParameterInfo(); } ParameterABI getParameterABI(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].getABI(); return ParameterABI::Ordinary; } bool isParamConsumed(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].isConsumed(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void printExceptionSpecification(raw_ostream &OS, const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, param_type_iterator ArgTys, unsigned NumArgs, const ExtProtoInfo &EPI, const ASTContext &Context, bool Canonical); }; /// Represents the dependent type named by a dependently-scoped /// typename using declaration, e.g. /// using typename Base::foo; /// /// Template instantiation turns these into the underlying type. class UnresolvedUsingType : public Type { friend class ASTContext; // ASTContext creates these. UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) : Type(UnresolvedUsing, QualType(), true, true, false, /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) {} public: UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == UnresolvedUsing; } void Profile(llvm::FoldingSetNodeID &ID) { return Profile(ID, Decl); } static void Profile(llvm::FoldingSetNodeID &ID, UnresolvedUsingTypenameDecl *D) { ID.AddPointer(D); } }; class TypedefType : public Type { TypedefNameDecl *Decl; protected: friend class ASTContext; // ASTContext creates these. TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) : Type(tc, can, can->isDependentType(), can->isInstantiationDependentType(), can->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } public: TypedefNameDecl *getDecl() const { return Decl; } bool isSugared() const { return true; } QualType desugar() const; static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } }; /// Represents a `typeof` (or __typeof__) expression (a GCC extension). class TypeOfExprType : public Type { Expr *TOExpr; protected: friend class ASTContext; // ASTContext creates these. TypeOfExprType(Expr *E, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return TOExpr; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } }; /// Internal representation of canonical, dependent /// `typeof(expr)` types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via TypeOfExprType nodes. class DependentTypeOfExprType : public TypeOfExprType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentTypeOfExprType(const ASTContext &Context, Expr *E) : TypeOfExprType(E), Context(Context) {} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// Represents `typeof(type)`, a GCC extension. class TypeOfType : public Type { friend class ASTContext; // ASTContext creates these. QualType TOType; TypeOfType(QualType T, QualType can) : Type(TypeOf, can, T->isDependentType(), T->isInstantiationDependentType(), T->isVariablyModifiedType(), T->containsUnexpandedParameterPack()), TOType(T) { assert(!isa(can) && "Invalid canonical type"); } public: QualType getUnderlyingType() const { return TOType; } /// Remove a single level of sugar. QualType desugar() const { return getUnderlyingType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } }; /// Represents the type `decltype(expr)` (C++11). class DecltypeType : public Type { Expr *E; QualType UnderlyingType; protected: friend class ASTContext; // ASTContext creates these. DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return E; } QualType getUnderlyingType() const { return UnderlyingType; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } }; /// Internal representation of canonical, dependent /// decltype(expr) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentDecltypeType(const ASTContext &Context, Expr *E); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// A unary type transform, which is a type constructed from another. class UnaryTransformType : public Type { public: enum UTTKind { EnumUnderlyingType }; private: /// The untransformed type. QualType BaseType; /// The transformed type if not dependent, otherwise the same as BaseType. QualType UnderlyingType; UTTKind UKind; protected: friend class ASTContext; UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, QualType CanonicalTy); public: bool isSugared() const { return !isDependentType(); } QualType desugar() const { return UnderlyingType; } QualType getUnderlyingType() const { return UnderlyingType; } QualType getBaseType() const { return BaseType; } UTTKind getUTTKind() const { return UKind; } static bool classof(const Type *T) { return T->getTypeClass() == UnaryTransform; } }; /// Internal representation of canonical, dependent /// __underlying_type(type) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via UnaryTransformType nodes. class DependentUnaryTransformType : public UnaryTransformType, public llvm::FoldingSetNode { public: DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), getUTTKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, UTTKind UKind) { ID.AddPointer(BaseType.getAsOpaquePtr()); ID.AddInteger((unsigned)UKind); } }; class TagType : public Type { friend class ASTReader; /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. TagDecl *decl; protected: TagType(TypeClass TC, const TagDecl *D, QualType can); public: TagDecl *getDecl() const; /// Determines whether this type is in the process of being defined. bool isBeingDefined() const; static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of structs/unions/classes. class RecordType : public TagType { protected: friend class ASTContext; // ASTContext creates these. explicit RecordType(const RecordDecl *D) : TagType(Record, reinterpret_cast(D), QualType()) {} explicit RecordType(TypeClass TC, RecordDecl *D) : TagType(TC, reinterpret_cast(D), QualType()) {} public: RecordDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } /// Recursively check all fields in the record for const-ness. If any field /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Record; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. class EnumType : public TagType { friend class ASTContext; // ASTContext creates these. explicit EnumType(const EnumDecl *D) : TagType(Enum, reinterpret_cast(D), QualType()) {} public: EnumDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Enum; } }; /// An attributed type is a type to which a type attribute has been applied. /// /// The "modified type" is the fully-sugared type to which the attributed /// type was applied; generally it is not canonically equivalent to the /// attributed type. The "equivalent type" is the minimally-desugared type /// which the type is canonically equivalent to. /// /// For example, in the following attributed type: /// int32_t __attribute__((vector_size(16))) /// - the modified type is the TypedefType for int32_t /// - the equivalent type is VectorType(16, int32_t) /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: using Kind = attr::Kind; private: friend class ASTContext; // ASTContext creates these QualType ModifiedType; QualType EquivalentType; AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), equivalent->isVariablyModifiedType(), equivalent->containsUnexpandedParameterPack()), ModifiedType(modified), EquivalentType(equivalent) { AttributedTypeBits.AttrKind = attrKind; } public: Kind getAttrKind() const { return static_cast(AttributedTypeBits.AttrKind); } QualType getModifiedType() const { return ModifiedType; } QualType getEquivalentType() const { return EquivalentType; } bool isSugared() const { return true; } QualType desugar() const { return getEquivalentType(); } /// Does this attribute behave like a type qualifier? /// /// A type qualifier adjusts a type to provide specialized rules for /// a specific object, like the standard const and volatile qualifiers. /// This includes attributes controlling things like nullability, /// address spaces, and ARC ownership. The value of the object is still /// largely described by the modified type. /// /// In contrast, many type attributes "rewrite" their modified type to /// produce a fundamentally different type, not necessarily related in any /// formalizable way to the original type. For example, calling convention /// and vector attributes are not simple type qualifiers. /// /// Type qualifiers are often, but not always, reflected in the canonical /// type. bool isQualifier() const; bool isMSTypeSpec() const; bool isCallingConv() const; llvm::Optional getImmediateNullability() const; /// Retrieve the attribute kind corresponding to the given /// nullability kind. static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: return attr::TypeNonNull; case NullabilityKind::Nullable: return attr::TypeNullable; case NullabilityKind::Unspecified: return attr::TypeNullUnspecified; } llvm_unreachable("Unknown nullability kind."); } /// Strip off the top-level nullability annotation on the given /// type, if it's there. /// /// \param T The type to strip. If the type is exactly an /// AttributedType specifying nullability (without looking through /// type sugar), the nullability is returned and this type changed /// to the underlying modified type. /// /// \returns the top-level nullability, if present. static Optional stripOuterNullability(QualType &T); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAttrKind(), ModifiedType, EquivalentType); } static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, QualType modified, QualType equivalent) { ID.AddInteger(attrKind); ID.AddPointer(modified.getAsOpaquePtr()); ID.AddPointer(equivalent.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Attributed; } }; class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these // Helper data collector for canonical types. struct CanonicalTTPTInfo { unsigned Depth : 15; unsigned ParameterPack : 1; unsigned Index : 16; }; union { // Info for the canonical type. CanonicalTTPTInfo CanTTPTInfo; // Info for the non-canonical type. TemplateTypeParmDecl *TTPDecl; }; /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) : Type(TemplateTypeParm, Canon, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, Canon->containsUnexpandedParameterPack()), TTPDecl(TTPDecl) {} /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, PP) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; CanTTPTInfo.ParameterPack = PP; } const CanonicalTTPTInfo& getCanTTPTInfo() const { QualType Can = getCanonicalTypeInternal(); return Can->castAs()->CanTTPTInfo; } public: unsigned getDepth() const { return getCanTTPTInfo().Depth; } unsigned getIndex() const { return getCanTTPTInfo().Index; } bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; } TemplateTypeParmDecl *getDecl() const { return isCanonicalUnqualified() ? nullptr : TTPDecl; } IdentifierInfo *getIdentifier() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, unsigned Index, bool ParameterPack, TemplateTypeParmDecl *TTPDecl) { ID.AddInteger(Depth); ID.AddInteger(Index); ID.AddBoolean(ParameterPack); ID.AddPointer(TTPDecl); } static bool classof(const Type *T) { return T->getTypeClass() == TemplateTypeParm; } }; /// Represents the result of substituting a type for a template /// type parameter. /// /// Within an instantiated template, all template type parameters have /// been replaced with these. They are used solely to record that a /// type was originally written as a template type parameter; /// therefore they are never canonical. class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // The original type parameter. const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), Canon->isInstantiationDependentType(), Canon->isVariablyModifiedType(), Canon->containsUnexpandedParameterPack()), Replaced(Param) {} public: /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } /// Gets the type that was substituted for the template /// parameter. QualType getReplacementType() const { return getCanonicalTypeInternal(); } bool isSugared() const { return true; } QualType desugar() const { return getReplacementType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacedParameter(), getReplacementType()); } static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, QualType Replacement) { ID.AddPointer(Replaced); ID.AddPointer(Replacement.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParm; } }; /// Represents the result of substituting a set of types for a template /// type parameter pack. /// /// When a pack expansion in the source code contains multiple parameter packs /// and those parameter packs correspond to different levels of template /// parameter lists, this type node is used to represent a template type /// parameter pack from an outer level, which has already had its argument pack /// substituted but that still lives within a pack expansion that itself /// could not be instantiated. When actually performing a substitution into /// that pack expansion (e.g., when all template parameters have corresponding /// arguments), this type will be replaced with the \c SubstTemplateTypeParmType /// at the current pack substitution index. class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { friend class ASTContext; /// The original type parameter. const TemplateTypeParmType *Replaced; /// A pointer to the set of template arguments that this /// parameter pack is instantiated with. const TemplateArgument *Arguments; SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack); public: IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } TemplateArgument getArgumentPack() const; void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, const TemplateArgument &ArgPack); static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParmPack; } }; /// Common base class for placeholders for types that get replaced by /// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced /// class template types, and (eventually) constrained type names from the C++ /// Concepts TS. /// /// These types are usually a placeholder for a deduced type. However, before /// the initializer is attached, or (usually) if the initializer is /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { protected: DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent, bool IsInstantiationDependent, bool ContainsParameterPack) : Type(TC, // FIXME: Retain the sugared deduced type? DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType.getCanonicalType(), IsDependent, IsInstantiationDependent, /*VariablyModified=*/false, ContainsParameterPack) { if (!DeducedAsType.isNull()) { if (DeducedAsType->isDependentType()) setDependent(); if (DeducedAsType->isInstantiationDependentType()) setInstantiationDependent(); if (DeducedAsType->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); } } public: bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } /// Get the type deduced for this placeholder type, or null if it's /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); } bool isDeduced() const { return !isCanonicalUnqualified() || isDependentType(); } static bool classof(const Type *T) { return T->getTypeClass() == Auto || T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a C++11 auto or C++14 decltype(auto) type. class AutoType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, bool IsDeducedAsDependent) : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, IsDeducedAsDependent, /*ContainsPack=*/false) { AutoTypeBits.Keyword = (unsigned)Keyword; } public: bool isDecltypeAuto() const { return getKeyword() == AutoTypeKeyword::DecltypeAuto; } AutoTypeKeyword getKeyword() const { return (AutoTypeKeyword)AutoTypeBits.Keyword; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDeducedType(), getKeyword(), isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, AutoTypeKeyword Keyword, bool IsDependent) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); } static bool classof(const Type *T) { return T->getTypeClass() == Auto; } }; /// Represents a C++17 deduced template specialization type. class DeducedTemplateSpecializationType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template whose arguments will be deduced. TemplateName Template; DeducedTemplateSpecializationType(TemplateName Template, QualType DeducedAsType, bool IsDeducedAsDependent) : DeducedType(DeducedTemplateSpecialization, DeducedAsType, IsDeducedAsDependent || Template.isDependent(), IsDeducedAsDependent || Template.isInstantiationDependent(), Template.containsUnexpandedParameterPack()), Template(Template) {} public: /// Retrieve the name of the template that we are deducing. TemplateName getTemplateName() const { return Template;} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getTemplateName(), getDeducedType(), isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, QualType Deduced, bool IsDependent) { Template.Profile(ID); ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddBoolean(IsDependent); } static bool classof(const Type *T) { return T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a type template specialization; the template /// must be a class template, a type alias template, or a template /// template parameter. A template which cannot be resolved to one of /// these, e.g. because it is written with a dependent scope /// specifier, is instead represented as a /// @c DependentTemplateSpecializationType. /// /// A non-dependent template specialization type is always "sugar", /// typically for a \c RecordType. For example, a class template /// specialization type of \c vector will refer to a tag type for /// the instantiation \c std::vector> /// /// Template specializations are dependent if either the template or /// any of the template arguments are dependent, in which case the /// type may also be canonical. /// /// Instances of this type are allocated with a trailing array of /// TemplateArguments, followed by a QualType representing the /// non-canonical aliased type when the template is a type alias /// template. class alignas(8) TemplateSpecializationType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a /// TypeAliasTemplateDecl*), a /// TemplateName::SubstTemplateTemplateParmPack, or a /// TemplateName::SubstTemplateTemplateParm (in which case the /// replacement must, recursively, be one of these). TemplateName Template; TemplateSpecializationType(TemplateName T, ArrayRef Args, QualType Canon, QualType Aliased); public: /// Determine whether any of the given template arguments are dependent. static bool anyDependentTemplateArguments(ArrayRef Args, bool &InstantiationDependent); static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, bool &InstantiationDependent); /// True if this template specialization type matches a current /// instantiation in the context in which it is found. bool isCurrentInstantiation() const { return isa(getCanonicalTypeInternal()); } /// Determine if this template specialization type is for a type alias /// template that has been substituted. /// /// Nearly every template specialization type whose template is an alias /// template will be substituted. However, this is not the case when /// the specialization contains a pack expansion but the template alias /// does not have a corresponding parameter pack, e.g., /// /// \code /// template struct S; /// template using A = S; /// template struct X { /// typedef A type; // not a type alias /// }; /// \endcode bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } /// Get the aliased type, if this is a specialization of a type alias /// template. QualType getAliasedType() const { assert(isTypeAlias() && "not a type alias template specialization"); return *reinterpret_cast(end()); } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // defined inline in TemplateBase.h /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return reinterpret_cast(this + 1); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return TemplateSpecializationTypeBits.NumArgs; } /// Retrieve a specific template argument as a type. /// \pre \c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } QualType desugar() const { return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, template_arguments(), Ctx); if (isTypeAlias()) getAliasedType().Profile(ID); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, ArrayRef Args, const ASTContext &Context); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; } }; /// Print a template argument list, including the '<' and '>' /// enclosing the template arguments. void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, const TemplateArgumentListInfo &Args, const PrintingPolicy &Policy); /// The injected class name of a C++ class template or class /// template partial specialization. Used to record that a type was /// spelled with a bare identifier rather than as a template-id; the /// equivalent for non-templated classes is just RecordType. /// /// Injected class name types are always dependent. Template /// instantiation turns these into RecordTypes. /// /// Injected class name types are always canonical. This works /// because it is impossible to compare an injected class name type /// with the corresponding non-injected template type, for the same /// reason that it is impossible to directly compare template /// parameters from different dependent contexts: injected class name /// types can only occur within the scope of a particular templated /// declaration, and within that scope every template specialization /// will canonicalize to the injected class name (when appropriate /// according to the rules of the language). class InjectedClassNameType : public Type { friend class ASTContext; // ASTContext creates these. friend class ASTNodeImporter; friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not // currently suitable for AST reading, too much // interdependencies. CXXRecordDecl *Decl; /// The template specialization which this type represents. /// For example, in /// template class A { ... }; /// this is A, whereas in /// template class A > { ... }; /// this is A >. /// /// It is always unqualified, always a template specialization type, /// and always dependent. QualType InjectedType; InjectedClassNameType(CXXRecordDecl *D, QualType TST) : Type(InjectedClassName, QualType(), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, /*ContainsUnexpandedParameterPack=*/false), Decl(D), InjectedType(TST) { assert(isa(TST)); assert(!TST.hasQualifiers()); assert(TST->isDependentType()); } public: QualType getInjectedSpecializationType() const { return InjectedType; } const TemplateSpecializationType *getInjectedTST() const { return cast(InjectedType.getTypePtr()); } TemplateName getTemplateName() const { return getInjectedTST()->getTemplateName(); } CXXRecordDecl *getDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == InjectedClassName; } }; /// The kind of a tag type. enum TagTypeKind { /// The "struct" keyword. TTK_Struct, /// The "__interface" keyword. TTK_Interface, /// The "union" keyword. TTK_Union, /// The "class" keyword. TTK_Class, /// The "enum" keyword. TTK_Enum }; /// The elaboration keyword that precedes a qualified type name or /// introduces an elaborated-type-specifier. enum ElaboratedTypeKeyword { /// The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, /// The "__interface" keyword introduces the elaborated-type-specifier. ETK_Interface, /// The "union" keyword introduces the elaborated-type-specifier. ETK_Union, /// The "class" keyword introduces the elaborated-type-specifier. ETK_Class, /// The "enum" keyword introduces the elaborated-type-specifier. ETK_Enum, /// The "typename" keyword precedes the qualified type name, e.g., /// \c typename T::type. ETK_Typename, /// No keyword precedes the qualified type name. ETK_None }; /// A helper class for Type nodes having an ElaboratedTypeKeyword. /// The keyword in stored in the free bits of the base class. /// Also provides a few static helpers for converting and printing /// elaborated type keyword and tag type kind enumerations. class TypeWithKeyword : public Type { protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack) { TypeWithKeywordBits.Keyword = Keyword; } public: ElaboratedTypeKeyword getKeyword() const { return static_cast(TypeWithKeywordBits.Keyword); } /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); /// Converts a type specifier (DeclSpec::TST) into a tag type kind. /// It is an error to provide a type specifier which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); /// Converts a TagTypeKind into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); /// Converts an elaborated type keyword into a TagTypeKind. /// It is an error to provide an elaborated type keyword /// which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); static StringRef getTagTypeKindName(TagTypeKind Kind) { return getKeywordName(getKeywordForTagTypeKind(Kind)); } class CannotCastToThisType {}; static CannotCastToThisType classof(const Type *); }; /// Represents a type that was referred to using an elaborated type /// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, /// or both. /// /// This type is used to keep track of a type name as written in the /// source code, including tag keywords and any nested-name-specifiers. /// The type itself is always "sugar", used to express what was written /// in the source code but containing no additional semantic information. class ElaboratedType final : public TypeWithKeyword, public llvm::FoldingSetNode, private llvm::TrailingObjects { friend class ASTContext; // ASTContext creates these friend TrailingObjects; /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this qualified name refers to. QualType NamedType; /// The (re)declaration of this tag type owned by this occurrence is stored /// as a trailing object if there is one. Use getOwnedTagDecl to obtain /// it, or obtain a null pointer if there is none. ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, NamedType->isDependentType(), NamedType->isInstantiationDependentType(), NamedType->isVariablyModifiedType(), NamedType->containsUnexpandedParameterPack()), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { ElaboratedTypeBits.HasOwnedTagDecl = true; *getTrailingObjects() = OwnedTagDecl; } assert(!(Keyword == ETK_None && NNS == nullptr) && "ElaboratedType cannot have elaborated type keyword " "and name qualifier both null."); } public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the qualified-id. QualType getNamedType() const { return NamedType; } /// Remove a single level of sugar. QualType desugar() const { return getNamedType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } /// Return the (re)declaration of this type owned by this occurrence of this /// type, or nullptr if there is none. TagDecl *getOwnedTagDecl() const { return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, TagDecl *OwnedTagDecl) { ID.AddInteger(Keyword); ID.AddPointer(NNS); NamedType.Profile(ID); ID.AddPointer(OwnedTagDecl); } static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } }; /// Represents a qualified type name for which the type name is /// dependent. /// /// DependentNameType represents a class of dependent types that involve a /// possibly dependent nested-name-specifier (e.g., "T::") followed by a /// name of a type. The DependentNameType may start with a "typename" (for a /// typename-specifier), "class", "struct", "union", or "enum" (for a /// dependent elaborated-type-specifier), or nothing (in contexts where we /// know that we must be referring to a type, e.g., in a base class specifier). /// Typically the nested-name-specifier is dependent, but in MSVC compatibility /// mode, this type is used with non-dependent names to delay name lookup until /// instantiation. class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this typename specifier refers to. const IdentifierInfo *Name; DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name) {} public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the typename specifier as an identifier. /// /// This routine will return a non-NULL identifier pointer when the /// form of the original typename was terminated by an identifier, /// e.g., "typename T::type". const IdentifierInfo *getIdentifier() const { return Name; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, Name); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name) { ID.AddInteger(Keyword); ID.AddPointer(NNS); ID.AddPointer(Name); } static bool classof(const Type *T) { return T->getTypeClass() == DependentName; } }; /// Represents a template specialization type whose template cannot be /// resolved, e.g. /// A::template B class alignas(8) DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The identifier of the template. const IdentifierInfo *Name; DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args, QualType Canon); const TemplateArgument *getArgBuffer() const { return reinterpret_cast(this+1); } TemplateArgument *getArgBuffer() { return reinterpret_cast(this+1); } public: NestedNameSpecifier *getQualifier() const { return NNS; } const IdentifierInfo *getIdentifier() const { return Name; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return getArgBuffer(); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return DependentTemplateSpecializationTypeBits.NumArgs; } const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // inline in TemplateBase.h bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getKeyword(), NNS, Name, {getArgs(), getNumArgs()}); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, ArrayRef Args); static bool classof(const Type *T) { return T->getTypeClass() == DependentTemplateSpecialization; } }; /// Represents a pack expansion of types. /// /// Pack expansions are part of C++11 variadic templates. A pack /// expansion contains a pattern, which itself contains one or more /// "unexpanded" parameter packs. When instantiated, a pack expansion /// produces a series of types, each instantiated from the pattern of /// the expansion, where the Ith instantiation of the pattern uses the /// Ith arguments bound to each of the unexpanded parameter packs. The /// pack expansion is considered to "expand" these unexpanded /// parameter packs. /// /// \code /// template struct tuple; /// /// template /// struct tuple_of_references { /// typedef tuple type; /// }; /// \endcode /// /// Here, the pack expansion \c Types&... is represented via a /// PackExpansionType whose pattern is Types&. class PackExpansionType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The pattern of the pack expansion. QualType Pattern; PackExpansionType(QualType Pattern, QualType Canon, Optional NumExpansions) : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), /*InstantiationDependent=*/true, /*VariablyModified=*/Pattern->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Pattern(Pattern) { PackExpansionTypeBits.NumExpansions = NumExpansions ? *NumExpansions + 1 : 0; } public: /// Retrieve the pattern of this pack expansion, which is the /// type that will be repeatedly instantiated when instantiating the /// pack expansion itself. QualType getPattern() const { return Pattern; } /// Retrieve the number of expansions that this pack expansion will /// generate, if known. Optional getNumExpansions() const { if (PackExpansionTypeBits.NumExpansions) return PackExpansionTypeBits.NumExpansions - 1; return None; } bool isSugared() const { return !Pattern->isDependentType(); } QualType desugar() const { return isSugared() ? Pattern : QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPattern(), getNumExpansions()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, Optional NumExpansions) { ID.AddPointer(Pattern.getAsOpaquePtr()); ID.AddBoolean(NumExpansions.hasValue()); if (NumExpansions) ID.AddInteger(*NumExpansions); } static bool classof(const Type *T) { return T->getTypeClass() == PackExpansion; } }; /// This class wraps the list of protocol qualifiers. For types that can /// take ObjC protocol qualifers, they can subclass this class. template class ObjCProtocolQualifiers { protected: ObjCProtocolQualifiers() = default; ObjCProtocolDecl * const *getProtocolStorage() const { return const_cast(this)->getProtocolStorage(); } ObjCProtocolDecl **getProtocolStorage() { return static_cast(this)->getProtocolStorageImpl(); } void setNumProtocols(unsigned N) { static_cast(this)->setNumProtocolsImpl(N); } void initialize(ArrayRef protocols) { setNumProtocols(protocols.size()); assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); if (!protocols.empty()) memcpy(getProtocolStorage(), protocols.data(), protocols.size() * sizeof(ObjCProtocolDecl*)); } public: using qual_iterator = ObjCProtocolDecl * const *; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getProtocolStorage(); } qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } bool qual_empty() const { return getNumProtocols() == 0; } /// Return the number of qualifying protocols in this type, or 0 if /// there are none. unsigned getNumProtocols() const { return static_cast(this)->getNumProtocolsImpl(); } /// Fetch a protocol by index. ObjCProtocolDecl *getProtocol(unsigned I) const { assert(I < getNumProtocols() && "Out-of-range protocol access"); return qual_begin()[I]; } /// Retrieve all of the protocol qualifiers. ArrayRef getProtocols() const { return ArrayRef(qual_begin(), getNumProtocols()); } }; /// Represents a type parameter type in Objective C. It can take /// a list of protocols. class ObjCTypeParamType : public Type, public ObjCProtocolQualifiers, public llvm::FoldingSetNode { friend class ASTContext; friend class ObjCProtocolQualifiers; /// The number of protocols stored on this type. unsigned NumProtocols : 6; ObjCTypeParamDecl *OTPDecl; /// The protocols are stored after the ObjCTypeParamType node. In the /// canonical type, the list of protocols are sorted alphabetically /// and uniqued. ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return NumProtocols; } void setNumProtocolsImpl(unsigned N) { NumProtocols = N; } ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols); public: bool isSugared() const { return true; } QualType desugar() const { return getCanonicalTypeInternal(); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCTypeParam; } void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const ObjCTypeParamDecl *OTPDecl, ArrayRef protocols); ObjCTypeParamDecl *getDecl() const { return OTPDecl; } }; /// Represents a class type in Objective C. /// /// Every Objective C type is a combination of a base type, a set of /// type arguments (optional, for parameterized classes) and a list of /// protocols. /// /// Given the following declarations: /// \code /// \@class C; /// \@protocol P; /// \endcode /// /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType /// with base C and no protocols. /// /// 'C

' is an unspecialized ObjCObjectType with base C and protocol list [P]. /// 'C' is a specialized ObjCObjectType with type arguments 'C*' and no /// protocol list. /// 'C

' is a specialized ObjCObjectType with base C, type arguments 'C*', /// and protocol list [P]. /// /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType /// and no protocols. /// /// 'id

' is an ObjCObjectPointerType whose pointee is an ObjCObjectType /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type, public ObjCProtocolQualifiers { friend class ObjCProtocolQualifiers; // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. // ObjCObjectType.NumProtocols - the number of protocols stored // after the type arguments of ObjCObjectPointerType node. // // These protocols are those written directly on the type. If // protocol qualifiers ever become additive, the iterators will need // to get kindof complicated. // // In the canonical object type, these are sorted alphabetically // and uniqued. /// Either a BuiltinType or an InterfaceType or sugar for either. QualType BaseType; /// Cached superclass type. mutable llvm::PointerIntPair CachedSuperClassType; QualType *getTypeArgStorage(); const QualType *getTypeArgStorage() const { return const_cast(this)->getTypeArgStorage(); } ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return ObjCObjectTypeBits.NumProtocols; } void setNumProtocolsImpl(unsigned N) { ObjCObjectTypeBits.NumProtocols = N; } protected: enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; ObjCObjectTypeBits.NumTypeArgs = 0; ObjCObjectTypeBits.IsKindOf = 0; } void computeSuperClassTypeSlow() const; public: /// Gets the base type of this object type. This is always (possibly /// sugar for) one of: /// - the 'id' builtin type (as opposed to the 'id' type visible to the /// user, which is a typedef for an ObjCObjectPointerType) /// - the 'Class' builtin type (same caveat) /// - an ObjCObjectType (currently always an ObjCInterfaceType) QualType getBaseType() const { return BaseType; } bool isObjCId() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); } bool isObjCClass() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); } bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } bool isObjCUnqualifiedIdOrClass() const { if (!qual_empty()) return false; if (const BuiltinType *T = getBaseType()->getAs()) return T->getKind() == BuiltinType::ObjCId || T->getKind() == BuiltinType::ObjCClass; return false; } bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } /// Gets the interface declaration for this object type, if the base type /// really is an interface. ObjCInterfaceDecl *getInterface() const; /// Determine whether this object type is "specialized", meaning /// that it has type arguments. bool isSpecialized() const; /// Determine whether this object type was written with type arguments. bool isSpecializedAsWritten() const { return ObjCObjectTypeBits.NumTypeArgs > 0; } /// Determine whether this object type is "unspecialized", meaning /// that it has no type arguments. bool isUnspecialized() const { return !isSpecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments of this object type (semantically). ArrayRef getTypeArgs() const; /// Retrieve the type arguments of this object type as they were /// written. ArrayRef getTypeArgsAsWritten() const { return llvm::makeArrayRef(getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs); } /// Whether this is a "__kindof" type as written. bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } /// Whether this ia a "__kindof" type (semantically). bool isKindOfType() const; /// Retrieve the type of the superclass of this object type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// specialization of the superclass type. Produces a null type if /// there is no superclass. QualType getSuperClassType() const { if (!CachedSuperClassType.getInt()) computeSuperClassTypeSlow(); assert(CachedSuperClassType.getInt() && "Superclass not set?"); return QualType(CachedSuperClassType.getPointer(), 0); } /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObject || T->getTypeClass() == ObjCInterface; } }; /// A class providing a concrete implementation /// of ObjCObjectType, so as to not increase the footprint of /// ObjCInterfaceType. Code outside of ASTContext and the core type /// system should not reference this type. class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { friend class ASTContext; // If anyone adds fields here, ObjCObjectType::getProtocolStorage() // will need to be modified. ObjCObjectTypeImpl(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); }; inline QualType *ObjCObjectType::getTypeArgStorage() { return reinterpret_cast(static_cast(this)+1); } inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { return reinterpret_cast( getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); } inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { return reinterpret_cast( static_cast(this)+1); } /// Interfaces are the core concept in Objective-C for object oriented design. /// They basically correspond to C++ classes. There are two kinds of interface /// types: normal interfaces like `NSString`, and qualified interfaces, which /// are qualified with a protocol list like `NSString`. /// /// ObjCInterfaceType guarantees the following properties when considered /// as a subtype of its superclass, ObjCObjectType: /// - There are no protocol qualifiers. To reinforce this, code which /// tries to invoke the protocol methods via an ObjCInterfaceType will /// fail to compile. /// - It is its own base type. That is, if T is an ObjCInterfaceType*, /// T->getBaseType() == QualType(T, 0). class ObjCInterfaceType : public ObjCObjectType { friend class ASTContext; // ASTContext creates these. friend class ASTReader; friend class ObjCInterfaceDecl; mutable ObjCInterfaceDecl *Decl; ObjCInterfaceType(const ObjCInterfaceDecl *D) : ObjCObjectType(Nonce_ObjCInterface), Decl(const_cast(D)) {} public: /// Get the declaration of this interface. ObjCInterfaceDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCInterface; } // Nonsense to "hide" certain members of ObjCObjectType within this // class. People asking for protocols on an ObjCInterfaceType are // not going to get what they want: ObjCInterfaceTypes are // guaranteed to have no protocols. enum { qual_iterator, qual_begin, qual_end, getNumProtocols, getProtocol }; }; inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { QualType baseType = getBaseType(); while (const auto *ObjT = baseType->getAs()) { if (const auto *T = dyn_cast(ObjT)) return T->getDecl(); baseType = ObjT->getBaseType(); } return nullptr; } /// Represents a pointer to an Objective C object. /// /// These are constructed from pointer declarators when the pointee type is /// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' /// types are typedefs for these, and the protocol-qualified types 'id

' /// and 'Class

' are translated into these. /// /// Pointers to pointers to Objective C objects are still PointerTypes; /// only the first level of pointer gets it own type implementation. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) : Type(ObjCObjectPointer, Canonical, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: /// Gets the type pointed to by this ObjC pointer. /// The result will always be an ObjCObjectType or sugar thereof. QualType getPointeeType() const { return PointeeType; } /// Gets the type pointed to by this ObjC pointer. Always returns non-null. /// /// This method is equivalent to getPointeeType() except that /// it discards any typedefs (or other sugar) between this /// type and the "outermost" object type. So for: /// \code /// \@class A; \@protocol P; \@protocol Q; /// typedef A

AP; /// typedef A A1; /// typedef A1

A1P; /// typedef A1P A1PQ; /// \endcode /// For 'A*', getObjectType() will return 'A'. /// For 'A

*', getObjectType() will return 'A

'. /// For 'AP*', getObjectType() will return 'A

'. /// For 'A1*', getObjectType() will return 'A'. /// For 'A1

*', getObjectType() will return 'A1

'. /// For 'A1P*', getObjectType() will return 'A1

'. /// For 'A1PQ*', getObjectType() will return 'A1', because /// adding protocols to a protocol-qualified base discards the /// old qualifiers (for now). But if it didn't, getObjectType() /// would return 'A1P' (and we'd have to make iterating over /// qualifiers more complicated). const ObjCObjectType *getObjectType() const { return PointeeType->castAs(); } /// If this pointer points to an Objective C /// \@interface type, gets the type for that interface. Any protocol /// qualifiers on the interface are ignored. /// /// \return null if the base type for this pointer is 'id' or 'Class' const ObjCInterfaceType *getInterfaceType() const; /// If this pointer points to an Objective \@interface /// type, gets the declaration for that interface. /// /// \return null if the base type for this pointer is 'id' or 'Class' ObjCInterfaceDecl *getInterfaceDecl() const { return getObjectType()->getInterface(); } /// True if this is equivalent to the 'id' type, i.e. if /// its object type is the primitive 'id' type with no protocols. bool isObjCIdType() const { return getObjectType()->isObjCUnqualifiedId(); } /// True if this is equivalent to the 'Class' type, /// i.e. if its object tive is the primitive 'Class' type with no protocols. bool isObjCClassType() const { return getObjectType()->isObjCUnqualifiedClass(); } /// True if this is equivalent to the 'id' or 'Class' type, bool isObjCIdOrClassType() const { return getObjectType()->isObjCUnqualifiedIdOrClass(); } /// True if this is equivalent to 'id

' for some non-empty set of /// protocols. bool isObjCQualifiedIdType() const { return getObjectType()->isObjCQualifiedId(); } /// True if this is equivalent to 'Class

' for some non-empty set of /// protocols. bool isObjCQualifiedClassType() const { return getObjectType()->isObjCQualifiedClass(); } /// Whether this is a "__kindof" type. bool isKindOfType() const { return getObjectType()->isKindOfType(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecialized() const { return getObjectType()->isSpecialized(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecializedAsWritten() const { return getObjectType()->isSpecializedAsWritten(); } /// Whether this type is unspecialized, meaning that is has no type arguments. bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgs() const { return getObjectType()->getTypeArgs(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgsAsWritten() const { return getObjectType()->getTypeArgsAsWritten(); } /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. using qual_iterator = ObjCObjectType::qual_iterator; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getObjectType()->qual_begin(); } qual_iterator qual_end() const { return getObjectType()->qual_end(); } bool qual_empty() const { return getObjectType()->qual_empty(); } /// Return the number of qualifying protocols on the object type. unsigned getNumProtocols() const { return getObjectType()->getNumProtocols(); } /// Retrieve a qualifying protocol by index on the object type. ObjCProtocolDecl *getProtocol(unsigned I) const { return getObjectType()->getProtocol(I); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Retrieve the type of the superclass of this object pointer type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// pointer to a specialization of the superclass type. Produces a /// null type if there is no superclass. QualType getSuperClassType() const; /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const; void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } }; class AtomicType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ValueType; AtomicType(QualType ValTy, QualType Canonical) : Type(Atomic, Canonical, ValTy->isDependentType(), ValTy->isInstantiationDependentType(), ValTy->isVariablyModifiedType(), ValTy->containsUnexpandedParameterPack()), ValueType(ValTy) {} public: /// Gets the type contained by this atomic type, i.e. /// the type returned by performing an atomic load of this atomic type. QualType getValueType() const { return ValueType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getValueType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Atomic; } }; /// PipeType - OpenCL20. class PipeType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; bool isRead; PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) : Type(Pipe, CanonicalPtr, elemType->isDependentType(), elemType->isInstantiationDependentType(), elemType->isVariablyModifiedType(), elemType->containsUnexpandedParameterPack()), ElementType(elemType), isRead(isRead) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), isReadOnly()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { ID.AddPointer(T.getAsOpaquePtr()); ID.AddBoolean(isRead); } static bool classof(const Type *T) { return T->getTypeClass() == Pipe; } bool isReadOnly() const { return isRead; } }; /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} /// Collect any qualifiers on the given type and return an /// unqualified type. The qualifiers are assumed to be consistent /// with those already in the type. const Type *strip(QualType type) { addFastQualifiers(type.getLocalFastQualifiers()); if (!type.hasLocalNonFastQualifiers()) return type.getTypePtrUnsafe(); const ExtQuals *extQuals = type.getExtQualsUnsafe(); addConsistentQualifiers(extQuals->getQualifiers()); return extQuals->getBaseType(); } /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, QualType QT) const; /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, const Type* T) const; }; // Inline function definitions. inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { SplitQualType desugar = Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); desugar.Quals.addConsistentQualifiers(Quals); return desugar; } inline const Type *QualType::getTypePtr() const { return getCommonPtr()->BaseType; } inline const Type *QualType::getTypePtrOrNull() const { return (isNull() ? nullptr : getCommonPtr()->BaseType); } inline SplitQualType QualType::split() const { if (!hasLocalNonFastQualifiers()) return SplitQualType(getTypePtrUnsafe(), Qualifiers::fromFastMask(getLocalFastQualifiers())); const ExtQuals *eq = getExtQualsUnsafe(); Qualifiers qs = eq->getQualifiers(); qs.addFastQualifiers(getLocalFastQualifiers()); return SplitQualType(eq->getBaseType(), qs); } inline Qualifiers QualType::getLocalQualifiers() const { Qualifiers Quals; if (hasLocalNonFastQualifiers()) Quals = getExtQualsUnsafe()->getQualifiers(); Quals.addFastQualifiers(getLocalFastQualifiers()); return Quals; } inline Qualifiers QualType::getQualifiers() const { Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); quals.addFastQualifiers(getLocalFastQualifiers()); return quals; } inline unsigned QualType::getCVRQualifiers() const { unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); cvr |= getLocalCVRQualifiers(); return cvr; } inline QualType QualType::getCanonicalType() const { QualType canon = getCommonPtr()->CanonicalType; return canon.withFastQualifiers(getLocalFastQualifiers()); } inline bool QualType::isCanonical() const { return getTypePtr()->isCanonicalUnqualified(); } inline bool QualType::isCanonicalAsParam() const { if (!isCanonical()) return false; if (hasLocalQualifiers()) return false; const Type *T = getTypePtr(); if (T->isVariablyModifiedType() && T->hasSizedVLAType()) return false; return !isa(T) && !isa(T); } inline bool QualType::isConstQualified() const { return isLocalConstQualified() || getCommonPtr()->CanonicalType.isLocalConstQualified(); } inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || getCommonPtr()->CanonicalType.isLocalRestrictQualified(); } inline bool QualType::isVolatileQualified() const { return isLocalVolatileQualified() || getCommonPtr()->CanonicalType.isLocalVolatileQualified(); } inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || getCommonPtr()->CanonicalType.hasLocalQualifiers(); } inline QualType QualType::getUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return QualType(getTypePtr(), 0); return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); } inline SplitQualType QualType::getSplitUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return split(); return getSplitUnqualifiedTypeImpl(*this); } inline void QualType::removeLocalConst() { removeLocalFastQualifiers(Qualifiers::Const); } inline void QualType::removeLocalRestrict() { removeLocalFastQualifiers(Qualifiers::Restrict); } inline void QualType::removeLocalVolatile() { removeLocalFastQualifiers(Qualifiers::Volatile); } inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); static_assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask, "Fast bits differ from CVR bits!"); // Fast path: we don't need to touch the slow qualifiers. removeLocalFastQualifiers(Mask); } /// Return the address space of this type. inline LangAS QualType::getAddressSpace() const { return getQualifiers().getAddressSpace(); } /// Return the gc attribute of this type. inline Qualifiers::GC QualType::getObjCGCAttr() const { return getQualifiers().getObjCGCAttr(); } inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { if (const auto *PT = t.getAs()) { if (const auto *FT = PT->getPointeeType()->getAs()) return FT->getExtInfo(); } else if (const auto *FT = t.getAs()) return FT->getExtInfo(); return FunctionType::ExtInfo(); } inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { return getFunctionExtInfo(*t); } /// Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and /// "int". However, it is not more qualified than "const volatile /// int". inline bool QualType::isMoreQualifiedThan(QualType other) const { Qualifiers MyQuals = getQualifiers(); Qualifiers OtherQuals = other.getQualifiers(); return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals)); } /// Determine whether this type is at last /// as qualified as the Other type. For example, "const volatile /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { Qualifiers OtherQuals = other.getQualifiers(); // Ignore __unaligned qualifier if this type is a void. if (getUnqualifiedType()->isVoidType()) OtherQuals.removeUnaligned(); return getQualifiers().compatiblyIncludes(OtherQuals); } /// If Type is a reference type (e.g., const /// int&), returns the type that the reference refers to ("const /// int"). Otherwise, returns the type itself. This routine is used /// throughout Sema to implement C++ 5p6: /// /// If an expression initially has the type "reference to T" (8.3.2, /// 8.5.3), the type is adjusted to "T" prior to any further /// analysis, the expression designates the object or function /// denoted by the reference, and the expression is an lvalue. inline QualType QualType::getNonReferenceType() const { if (const auto *RefType = (*this)->getAs()) return RefType->getPointeeType(); else return *this; } inline bool QualType::isCForbiddenLValueType() const { return ((getTypePtr()->isVoidType() && !hasQualifiers()) || getTypePtr()->isFunctionType()); } /// Tests whether the type is categorized as a fundamental type. /// /// \returns True for types specified in C++0x [basic.fundamental]. inline bool Type::isFundamentalType() const { return isVoidType() || // FIXME: It's really annoying that we don't have an // 'isArithmeticType()' which agrees with the standard definition. (isArithmeticType() && !isEnumeralType()); } /// Tests whether the type is categorized as a compound type. /// /// \returns True for types specified in C++0x [basic.compound]. inline bool Type::isCompoundType() const { // C++0x [basic.compound]p1: // Compound types can be constructed in the following ways: // -- arrays of objects of a given type [...]; return isArrayType() || // -- functions, which have parameters of given types [...]; isFunctionType() || // -- pointers to void or objects or functions [...]; isPointerType() || // -- references to objects or functions of a given type. [...] isReferenceType() || // -- classes containing a sequence of objects of various types, [...]; isRecordType() || // -- unions, which are classes capable of containing objects of different // types at different times; isUnionType() || // -- enumerations, which comprise a set of named constant values. [...]; isEnumeralType() || // -- pointers to non-static class members, [...]. isMemberPointerType(); } inline bool Type::isFunctionType() const { return isa(CanonicalType); } inline bool Type::isPointerType() const { return isa(CanonicalType); } inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } inline bool Type::isBlockPointerType() const { return isa(CanonicalType); } inline bool Type::isReferenceType() const { return isa(CanonicalType); } inline bool Type::isLValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isRValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isFunctionPointerType() const { if (const auto *T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; } inline bool Type::isMemberPointerType() const { return isa(CanonicalType); } inline bool Type::isMemberFunctionPointerType() const { if (const auto *T = getAs()) return T->isMemberFunctionPointer(); else return false; } inline bool Type::isMemberDataPointerType() const { if (const auto *T = getAs()) return T->isMemberDataPointer(); else return false; } inline bool Type::isArrayType() const { return isa(CanonicalType); } inline bool Type::isConstantArrayType() const { return isa(CanonicalType); } inline bool Type::isIncompleteArrayType() const { return isa(CanonicalType); } inline bool Type::isVariableArrayType() const { return isa(CanonicalType); } inline bool Type::isDependentSizedArrayType() const { return isa(CanonicalType); } inline bool Type::isBuiltinType() const { return isa(CanonicalType); } inline bool Type::isRecordType() const { return isa(CanonicalType); } inline bool Type::isEnumeralType() const { return isa(CanonicalType); } inline bool Type::isAnyComplexType() const { return isa(CanonicalType); } inline bool Type::isVectorType() const { return isa(CanonicalType); } inline bool Type::isExtVectorType() const { return isa(CanonicalType); } inline bool Type::isDependentAddressSpaceType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectPointerType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectOrInterfaceType() const { return isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isAtomicType() const { return isa(CanonicalType); } inline bool Type::isObjCQualifiedIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedIdType(); return false; } inline bool Type::isObjCQualifiedClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedClassType(); return false; } inline bool Type::isObjCIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCIdType(); return false; } inline bool Type::isObjCClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCClassType(); return false; } inline bool Type::isObjCSelType() const { if (const auto *OPT = getAs()) return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); return false; } inline bool Type::isObjCBuiltinType() const { return isObjCIdType() || isObjCClassType() || isObjCSelType(); } #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLImageTypes.def" inline bool Type::isSamplerT() const { return isSpecificBuiltinType(BuiltinType::OCLSampler); } inline bool Type::isEventT() const { return isSpecificBuiltinType(BuiltinType::OCLEvent); } inline bool Type::isClkEventT() const { return isSpecificBuiltinType(BuiltinType::OCLClkEvent); } inline bool Type::isQueueT() const { return isSpecificBuiltinType(BuiltinType::OCLQueue); } inline bool Type::isReserveIDT() const { return isSpecificBuiltinType(BuiltinType::OCLReserveID); } inline bool Type::isImageType() const { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || return #include "clang/Basic/OpenCLImageTypes.def" false; // end boolean or operation } inline bool Type::isPipeType() const { return isa(CanonicalType); } #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLExtensionTypes.def" inline bool Type::isOCLIntelSubgroupAVCType() const { #define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ isOCLIntelSubgroupAVC##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOCLExtOpaqueType() const { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); } inline bool Type::isTemplateTypeParmType() const { return isa(CanonicalType); } inline bool Type::isSpecificBuiltinType(unsigned K) const { if (const BuiltinType *BT = getAs()) if (BT->getKind() == (BuiltinType::Kind) K) return true; return false; } inline bool Type::isPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isPlaceholderType(); return false; } inline const BuiltinType *Type::getAsPlaceholderType() const { if (const auto *BT = dyn_cast(this)) if (BT->isPlaceholderType()) return BT; return nullptr; } inline bool Type::isSpecificPlaceholderType(unsigned K) const { assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); if (const auto *BT = dyn_cast(this)) return (BT->getKind() == (BuiltinType::Kind) K); return false; } inline bool Type::isNonOverloadPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isNonOverloadPlaceholderType(); return false; } inline bool Type::isVoidType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Void; return false; } inline bool Type::isHalfType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Half; // FIXME: Should we allow complex __fp16? Probably not. return false; } inline bool Type::isFloat16Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float16; return false; } inline bool Type::isFloat128Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float128; return false; } inline bool Type::isNullPtrType() const { if (const auto *BT = getAs()) return BT->getKind() == BuiltinType::NullPtr; return false; } bool IsEnumDeclComplete(EnumDecl *); bool IsEnumDeclScoped(EnumDecl *); inline bool Type::isIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. return IsEnumDeclComplete(ET->getDecl()) && !IsEnumDeclScoped(ET->getDecl()); } return false; } inline bool Type::isFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isSaturatedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isUnsaturatedFixedPointType() const { return isFixedPointType() && !isSaturatedFixedPointType(); } inline bool Type::isSignedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return ((BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::LongAccum) || (BT->getKind() >= BuiltinType::ShortFract && BT->getKind() <= BuiltinType::LongFract) || (BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatLongAccum) || (BT->getKind() >= BuiltinType::SatShortFract && BT->getKind() <= BuiltinType::SatLongFract)); } return false; } inline bool Type::isUnsignedFixedPointType() const { return isFixedPointType() && !isSignedFixedPointType(); } inline bool Type::isScalarType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() > BuiltinType::Void && BT->getKind() <= BuiltinType::NullPtr; if (const EnumType *ET = dyn_cast(CanonicalType)) // Enums are scalar types, but only if they are defined. Incomplete enums // are not treated as scalar types. return IsEnumDeclComplete(ET->getDecl()); return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isIntegralOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; // Check for a complete enum type; incomplete enum types are not properly an // enumeration type in the sense required here. if (const auto *ET = dyn_cast(CanonicalType)) return IsEnumDeclComplete(ET->getDecl()); return false; } inline bool Type::isBooleanType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; return false; } inline bool Type::isUndeducedType() const { auto *DT = getContainedDeducedType(); return DT && !DT->isDeduced(); } /// Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { return isDependentType() || isRecordType() || isEnumeralType(); } /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { return isFunctionType() || isArrayType(); } inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || isObjCObjectPointerType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { return isObjCObjectPointerType(); } inline const Type *Type::getBaseElementTypeUnsafe() const { const Type *type = this; while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) type = arrayType->getElementType().getTypePtr(); return type; } inline const Type *Type::getPointeeOrArrayElementType() const { const Type *type = this; if (type->isAnyPointerType()) return type->getPointeeType().getTypePtr(); else if (type->isArrayType()) return type->getBaseElementTypeUnsafe(); return type; } /// Insertion operator for diagnostics. This allows sending Qualifiers into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Qualifiers Q) { DB.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return DB; } /// Insertion operator for partial diagnostics. This allows sending Qualifiers /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, Qualifiers Q) { PD.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return PD; } /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, QualType T) { DB.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return DB; } /// Insertion operator for partial diagnostics. This allows sending QualType's /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, QualType T) { PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return PD; } // Helper class template that is used by Type::getAs to ensure that one does // not try to look through a qualified type to get to an array type. template using TypeIsArrayType = std::integral_constant::value || std::is_base_of::value>; // Member-template getAs'. template const T *Type::getAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAs!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::getAsAdjusted() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // Strip off type adjustments that do not modify the underlying nature of the // type. const Type *Ty = this; while (Ty) { if (const auto *A = dyn_cast(Ty)) Ty = A->getModifiedType().getTypePtr(); else if (const auto *E = dyn_cast(Ty)) Ty = E->desugar().getTypePtr(); else if (const auto *P = dyn_cast(Ty)) Ty = P->desugar().getTypePtr(); else if (const auto *A = dyn_cast(Ty)) Ty = A->desugar().getTypePtr(); else break; } // Just because the canonical type is correct does not mean we can use cast<>, // since we may not have stripped off all the sugar down to the base type. return dyn_cast(Ty); } inline const ArrayType *Type::getAsArrayTypeUnsafe() const { // If this is directly an array type, return it. if (const auto *arr = dyn_cast(this)) return arr; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::castAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with castAs!"); if (const auto *ty = dyn_cast(this)) return ty; assert(isa(CanonicalType)); return cast(getUnqualifiedDesugaredType()); } inline const ArrayType *Type::castAsArrayTypeUnsafe() const { assert(isa(CanonicalType)); if (const auto *arr = dyn_cast(this)) return arr; return cast(getUnqualifiedDesugaredType()); } DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { #ifndef NDEBUG QualType Adjusted = getAdjustedType(); (void)AttributedType::stripOuterNullability(Adjusted); assert(isa(Adjusted)); #endif } QualType DecayedType::getPointeeType() const { QualType Decayed = getDecayedType(); (void)AttributedType::stripOuterNullability(Decayed); return cast(Decayed)->getPointeeType(); } // Get the decimal string representation of a fixed point type, represented // as a scaled integer. void FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, unsigned Scale); } // namespace clang #endif // LLVM_CLANG_AST_TYPE_H Index: stable/11 =================================================================== --- stable/11 (revision 349966) +++ stable/11 (revision 349967) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r349876 Index: stable/12/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h =================================================================== --- stable/12/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h (revision 349966) +++ stable/12/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h (revision 349967) @@ -1,2526 +1,2526 @@ //===- DeclBase.h - Base Classes for representing declarations --*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Decl and DeclContext interfaces. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_DECLBASE_H #define LLVM_CLANG_AST_DECLBASE_H #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/VersionTuple.h" #include #include #include #include #include #include #include namespace clang { class ASTContext; class ASTMutationListener; class Attr; class DeclContext; class ExternalSourceSymbolAttr; class FunctionDecl; class FunctionType; class IdentifierInfo; enum Linkage : unsigned char; class LinkageSpecDecl; class Module; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCMethodDecl; class ObjCProtocolDecl; struct PrintingPolicy; class RecordDecl; class SourceManager; class Stmt; class StoredDeclsMap; class TemplateDecl; class TranslationUnitDecl; class UsingDirectiveDecl; /// Captures the result of checking the availability of a /// declaration. enum AvailabilityResult { AR_Available = 0, AR_NotYetIntroduced, AR_Deprecated, AR_Unavailable }; /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. /// /// Note: There are objects tacked on before the *beginning* of Decl /// (and its subclasses) in its Decl::operator new(). Proper alignment /// of all subclasses (not requiring more than the alignment of Decl) is /// asserted in DeclBase.cpp. class alignas(8) Decl { public: /// Lists the kind of concrete classes of Decl. enum Kind { #define DECL(DERIVED, BASE) DERIVED, #define ABSTRACT_DECL(DECL) #define DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END, #define LAST_DECL_RANGE(BASE, START, END) \ first##BASE = START, last##BASE = END #include "clang/AST/DeclNodes.inc" }; /// A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). struct EmptyShell {}; /// IdentifierNamespace - The different namespaces in which /// declarations may appear. According to C99 6.2.3, there are /// four namespaces, labels, tags, members and ordinary /// identifiers. C++ describes lookup completely differently: /// certain lookups merely "ignore" certain kinds of declarations, /// usually based on whether the declaration is of a type, etc. /// /// These are meant as bitmasks, so that searches in /// C++ can look into the "tag" namespace during ordinary lookup. /// /// Decl currently provides 15 bits of IDNS bits. enum IdentifierNamespace { /// Labels, declared with 'x:' and referenced with 'goto x'. IDNS_Label = 0x0001, /// Tags, declared with 'struct foo;' and referenced with /// 'struct foo'. All tags are also types. This is what /// elaborated-type-specifiers look for in C. /// This also contains names that conflict with tags in the /// same scope but that are otherwise ordinary names (non-type /// template parameters and indirect field declarations). IDNS_Tag = 0x0002, /// Types, declared with 'struct foo', typedefs, etc. /// This is what elaborated-type-specifiers look for in C++, /// but note that it's ill-formed to find a non-tag. IDNS_Type = 0x0004, /// Members, declared with object declarations within tag /// definitions. In C, these can only be found by "qualified" /// lookup in member expressions. In C++, they're found by /// normal lookup. IDNS_Member = 0x0008, /// Namespaces, declared with 'namespace foo {}'. /// Lookup for nested-name-specifiers find these. IDNS_Namespace = 0x0010, /// Ordinary names. In C, everything that's not a label, tag, /// member, or function-local extern ends up here. IDNS_Ordinary = 0x0020, /// Objective C \@protocol. IDNS_ObjCProtocol = 0x0040, /// This declaration is a friend function. A friend function /// declaration is always in this namespace but may also be in /// IDNS_Ordinary if it was previously declared. IDNS_OrdinaryFriend = 0x0080, /// This declaration is a friend class. A friend class /// declaration is always in this namespace but may also be in /// IDNS_Tag|IDNS_Type if it was previously declared. IDNS_TagFriend = 0x0100, /// This declaration is a using declaration. A using declaration /// *introduces* a number of other declarations into the current /// scope, and those declarations use the IDNS of their targets, /// but the actual using declarations go in this namespace. IDNS_Using = 0x0200, /// This declaration is a C++ operator declared in a non-class /// context. All such operators are also in IDNS_Ordinary. /// C++ lexical operator lookup looks for these. IDNS_NonMemberOperator = 0x0400, /// This declaration is a function-local extern declaration of a /// variable or function. This may also be IDNS_Ordinary if it /// has been declared outside any function. These act mostly like /// invisible friend declarations, but are also visible to unqualified /// lookup within the scope of the declaring function. IDNS_LocalExtern = 0x0800, /// This declaration is an OpenMP user defined reduction construction. IDNS_OMPReduction = 0x1000 }; /// ObjCDeclQualifier - 'Qualifiers' written next to the return and /// parameter types in method declarations. Other than remembering /// them and mangling them into the method's signature string, these /// are ignored by the compiler; they are consumed by certain /// remote-messaging frameworks. /// /// in, inout, and out are mutually exclusive and apply only to /// method parameters. bycopy and byref are mutually exclusive and /// apply only to method parameters (?). oneway applies only to /// results. All of these expect their corresponding parameter to /// have a particular type. None of this is currently enforced by /// clang. /// /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier. enum ObjCDeclQualifier { OBJC_TQ_None = 0x0, OBJC_TQ_In = 0x1, OBJC_TQ_Inout = 0x2, OBJC_TQ_Out = 0x4, OBJC_TQ_Bycopy = 0x8, OBJC_TQ_Byref = 0x10, OBJC_TQ_Oneway = 0x20, /// The nullability qualifier is set when the nullability of the /// result or parameter was expressed via a context-sensitive /// keyword. OBJC_TQ_CSNullability = 0x40 }; /// The kind of ownership a declaration has, for visibility purposes. /// This enumeration is designed such that higher values represent higher /// levels of name hiding. enum class ModuleOwnershipKind : unsigned { /// This declaration is not owned by a module. Unowned, /// This declaration has an owning module, but is globally visible /// (typically because its owning module is visible and we know that /// modules cannot later become hidden in this compilation). /// After serialization and deserialization, this will be converted /// to VisibleWhenImported. Visible, /// This declaration has an owning module, and is visible when that /// module is imported. VisibleWhenImported, /// This declaration has an owning module, but is only visible to /// lookups that occur within that module. ModulePrivate }; protected: /// The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// /// The extra two bits are used for the ModuleOwnershipKind. llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; struct MultipleDC { DeclContext *SemanticDC; DeclContext *LexicalDC; }; /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the Decl was declared. /// For declarations with C++ scope specifiers, it contains a MultipleDC* /// with the context where it semantically belongs (SemanticDC) and the /// context where it was lexically declared (LexicalDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace llvm::PointerUnion DeclCtx; bool isInSemaDC() const { return DeclCtx.is(); } bool isOutOfSemaDC() const { return DeclCtx.is(); } MultipleDC *getMultipleDC() const { return DeclCtx.get(); } DeclContext *getSemanticDC() const { return DeclCtx.get(); } /// Loc - The location of this decl. SourceLocation Loc; /// DeclKind - This indicates which class this is. unsigned DeclKind : 7; /// InvalidDecl - This indicates a semantic error occurred. unsigned InvalidDecl : 1; /// HasAttrs - This indicates whether the decl has attributes or not. unsigned HasAttrs : 1; /// Implicit - Whether this declaration was implicitly generated by /// the implementation rather than explicitly written by the user. unsigned Implicit : 1; /// Whether this declaration was "used", meaning that a definition is /// required. unsigned Used : 1; /// Whether this declaration was "referenced". /// The difference with 'Used' is whether the reference appears in a /// evaluated context or not, e.g. functions used in uninstantiated templates /// are regarded as "referenced" but not "used". unsigned Referenced : 1; /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. unsigned TopLevelDeclInObjCContainer : 1; /// Whether statistic collection is enabled. static bool StatisticsEnabled; protected: friend class ASTDeclReader; friend class ASTDeclWriter; friend class ASTNodeImporter; friend class ASTReader; friend class CXXClassMemberWrapper; friend class LinkageComputer; template friend class Redeclarable; /// Access - Used by C++ decls for the access specifier. // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum unsigned Access : 2; /// Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 13; /// If 0, we have not computed the linkage of this declaration. /// Otherwise, it is the linkage + 1. mutable unsigned CacheValidAndLinkage : 3; /// Allocate memory for a deserialized declaration. /// /// This routine must be used to allocate memory for any declaration that is /// deserialized from a module file. /// /// \param Size The size of the allocated object. /// \param Ctx The context in which we will allocate memory. /// \param ID The global ID of the deserialized declaration. /// \param Extra The amount of extra space to allocate after the object. void *operator new(std::size_t Size, const ASTContext &Ctx, unsigned ID, std::size_t Extra = 0); /// Allocate memory for a non-deserialized declaration. void *operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra = 0); private: bool AccessDeclContextSanity() const; /// Get the module ownership kind to use for a local lexical child of \p DC, /// which may be either a local or (rarely) an imported declaration. static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) { if (DC) { auto *D = cast(DC); auto MOK = D->getModuleOwnershipKind(); if (MOK != ModuleOwnershipKind::Unowned && (!D->isFromASTFile() || D->hasLocalOwningModuleStorage())) return MOK; // If D is not local and we have no local module storage, then we don't // need to track module ownership at all. } return ModuleOwnershipKind::Unowned; } protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)), DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } Decl(Kind DK, EmptyShell Empty) : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false), Used(false), Referenced(false), TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } virtual ~Decl(); /// Update a potentially out-of-date declaration. void updateOutOfDate(IdentifierInfo &II) const; Linkage getCachedLinkage() const { return Linkage(CacheValidAndLinkage - 1); } void setCachedLinkage(Linkage L) const { CacheValidAndLinkage = L + 1; } bool hasCachedLinkage() const { return CacheValidAndLinkage; } public: /// Source range that this declaration covers. virtual SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getLocation(), getLocation()); } SourceLocation getBeginLoc() const LLVM_READONLY { return getSourceRange().getBegin(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSourceRange().getEnd(); } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } Kind getKind() const { return static_cast(DeclKind); } const char *getDeclKindName() const; Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); } const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();} DeclContext *getDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->SemanticDC; } const DeclContext *getDeclContext() const { return const_cast(this)->getDeclContext(); } /// Find the innermost non-closure ancestor of this declaration, /// walking up through blocks, lambdas, etc. If that ancestor is /// not a code context (!isFunctionOrMethod()), returns null. /// /// A declaration may be its own non-closure context. Decl *getNonClosureContext(); const Decl *getNonClosureContext() const { return const_cast(this)->getNonClosureContext(); } TranslationUnitDecl *getTranslationUnitDecl(); const TranslationUnitDecl *getTranslationUnitDecl() const { return const_cast(this)->getTranslationUnitDecl(); } bool isInAnonymousNamespace() const; bool isInStdNamespace() const; ASTContext &getASTContext() const LLVM_READONLY; void setAccess(AccessSpecifier AS) { Access = AS; assert(AccessDeclContextSanity()); } AccessSpecifier getAccess() const { assert(AccessDeclContextSanity()); return AccessSpecifier(Access); } /// Retrieve the access specifier for this declaration, even though /// it may not yet have been properly set. AccessSpecifier getAccessUnsafe() const { return AccessSpecifier(Access); } bool hasAttrs() const { return HasAttrs; } void setAttrs(const AttrVec& Attrs) { return setAttrsImpl(Attrs, getASTContext()); } AttrVec &getAttrs() { return const_cast(const_cast(this)->getAttrs()); } const AttrVec &getAttrs() const; void dropAttrs(); void addAttr(Attr *A); using attr_iterator = AttrVec::const_iterator; using attr_range = llvm::iterator_range; attr_range attrs() const { return attr_range(attr_begin(), attr_end()); } attr_iterator attr_begin() const { return hasAttrs() ? getAttrs().begin() : nullptr; } attr_iterator attr_end() const { return hasAttrs() ? getAttrs().end() : nullptr; } template void dropAttr() { if (!HasAttrs) return; AttrVec &Vec = getAttrs(); Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa), Vec.end()); if (Vec.empty()) HasAttrs = false; } template llvm::iterator_range> specific_attrs() const { return llvm::make_range(specific_attr_begin(), specific_attr_end()); } template specific_attr_iterator specific_attr_begin() const { return specific_attr_iterator(attr_begin()); } template specific_attr_iterator specific_attr_end() const { return specific_attr_iterator(attr_end()); } template T *getAttr() const { return hasAttrs() ? getSpecificAttr(getAttrs()) : nullptr; } template bool hasAttr() const { return hasAttrs() && hasSpecificAttr(getAttrs()); } /// getMaxAlignment - return the maximum alignment specified by attributes /// on this decl, 0 if there are none. unsigned getMaxAlignment() const; /// setInvalidDecl - Indicates the Decl had a semantic error. This /// allows for graceful error recovery. void setInvalidDecl(bool Invalid = true); bool isInvalidDecl() const { return (bool) InvalidDecl; } /// isImplicit - Indicates whether the declaration was implicitly /// generated by the implementation. If false, this declaration /// was written explicitly in the source code. bool isImplicit() const { return Implicit; } void setImplicit(bool I = true) { Implicit = I; } /// Whether *any* (re-)declaration of the entity was used, meaning that /// a definition is required. /// /// \param CheckUsedAttr When true, also consider the "used" attribute /// (in addition to the "used" bit set by \c setUsed()) when determining /// whether the function is used. bool isUsed(bool CheckUsedAttr = true) const; /// Set whether the declaration is used, in the sense of odr-use. /// /// This should only be used immediately after creating a declaration. /// It intentionally doesn't notify any listeners. void setIsUsed() { getCanonicalDecl()->Used = true; } /// Mark the declaration used, in the sense of odr-use. /// /// This notifies any mutation listeners in addition to setting a bit /// indicating the declaration is used. void markUsed(ASTContext &C); /// Whether any declaration of this entity was referenced. bool isReferenced() const; /// Whether this declaration was referenced. This should not be relied /// upon for anything other than debugging. bool isThisDeclarationReferenced() const { return Referenced; } void setReferenced(bool R = true) { Referenced = R; } /// Whether this declaration is a top-level declaration (function, /// global variable, etc.) that is lexically inside an objc container /// definition. bool isTopLevelDeclInObjCContainer() const { return TopLevelDeclInObjCContainer; } void setTopLevelDeclInObjCContainer(bool V = true) { TopLevelDeclInObjCContainer = V; } /// Looks on this and related declarations for an applicable /// external source symbol attribute. ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const; /// Whether this declaration was marked as being private to the /// module in which it was defined. bool isModulePrivate() const { return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } /// Whether this declaration is exported (by virtue of being lexically /// within an ExportDecl or by being a NamespaceDecl). bool isExported() const; /// Return true if this declaration has an attribute which acts as /// definition of the entity, such as 'alias' or 'ifunc'. bool hasDefiningAttr() const; /// Return this declaration's defining attribute if it has one. const Attr *getDefiningAttr() const; protected: /// Specify that this declaration was marked as being private /// to the module in which it was defined. void setModulePrivate() { // The module-private specifier has no effect on unowned declarations. // FIXME: We should track this in some way for source fidelity. if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned) return; setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } /// Set the owning module ID. void setOwningModuleID(unsigned ID) { assert(isFromASTFile() && "Only works on a deserialized declaration"); *((unsigned*)this - 2) = ID; } public: /// Determine the availability of the given declaration. /// /// This routine will determine the most restrictive availability of /// the given declaration (e.g., preferring 'unavailable' to /// 'deprecated'). /// /// \param Message If non-NULL and the result is not \c /// AR_Available, will be set to a (possibly empty) message /// describing why the declaration has not been introduced, is /// deprecated, or is unavailable. /// /// \param EnclosingVersion The version to compare with. If empty, assume the /// deployment target version. /// /// \param RealizedPlatform If non-NULL and the availability result is found /// in an available attribute it will set to the platform which is written in /// the available attribute. AvailabilityResult getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple(), StringRef *RealizedPlatform = nullptr) const; /// Retrieve the version of the target platform in which this /// declaration was introduced. /// /// \returns An empty version tuple if this declaration has no 'introduced' /// availability attributes, or the version tuple that's specified in the /// attribute otherwise. VersionTuple getVersionIntroduced() const; /// Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, /// this will be set to the message describing why the declaration /// was deprecated (which may be empty). bool isDeprecated(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Deprecated; } /// Determine whether this declaration is marked 'unavailable'. /// /// \param Message If non-NULL and the declaration is unavailable, /// this will be set to the message describing why the declaration /// was made unavailable (which may be empty). bool isUnavailable(std::string *Message = nullptr) const { return getAvailability(Message) == AR_Unavailable; } /// Determine whether this is a weak-imported symbol. /// /// Weak-imported symbols are typically marked with the /// 'weak_import' attribute, but may also be marked with an /// 'availability' attribute where we're targing a platform prior to /// the introduction of this feature. bool isWeakImported() const; /// Determines whether this symbol can be weak-imported, /// e.g., whether it would be well-formed to add the weak_import /// attribute. /// /// \param IsDefinition Set to \c true to indicate that this /// declaration cannot be weak-imported because it has a definition. bool canBeWeakImported(bool &IsDefinition) const; /// Determine whether this declaration came from an AST file (such as /// a precompiled header or module) rather than having been parsed. bool isFromASTFile() const { return FromASTFile; } /// Retrieve the global declaration ID associated with this /// declaration, which specifies where this Decl was loaded from. unsigned getGlobalID() const { if (isFromASTFile()) return *((const unsigned*)this - 1); return 0; } /// Retrieve the global ID of the module that owns this particular /// declaration. unsigned getOwningModuleID() const { if (isFromASTFile()) return *((const unsigned*)this - 2); return 0; } private: Module *getOwningModuleSlow() const; protected: bool hasLocalOwningModuleStorage() const; public: /// Get the imported owning module, if this decl is from an imported /// (non-local) module. Module *getImportedOwningModule() const { if (!isFromASTFile() || !hasOwningModule()) return nullptr; return getOwningModuleSlow(); } /// Get the local owning module, if known. Returns nullptr if owner is /// not yet known or declaration is not from a module. Module *getLocalOwningModule() const { if (isFromASTFile() || !hasOwningModule()) return nullptr; assert(hasLocalOwningModuleStorage() && "owned local decl but no local module storage"); return reinterpret_cast(this)[-1]; } void setLocalOwningModule(Module *M) { assert(!isFromASTFile() && hasOwningModule() && hasLocalOwningModuleStorage() && "should not have a cached owning module"); reinterpret_cast(this)[-1] = M; } /// Is this declaration owned by some module? bool hasOwningModule() const { return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; } /// Get the module that owns this declaration (for visibility purposes). Module *getOwningModule() const { return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } /// Get the module that owns this declaration for linkage purposes. /// There only ever is such a module under the C++ Modules TS. /// /// \param IgnoreLinkage Ignore the linkage of the entity; assume that /// all declarations in a global module fragment are unowned. Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; /// Determine whether this declaration might be hidden from name /// lookup. Note that the declaration might be visible even if this returns /// \c false, if the owning module is visible within the query context. // FIXME: Rename this to make it clearer what it does. bool isHidden() const { return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible; } /// Set that this declaration is globally visible, even if it came from a /// module that is not visible. void setVisibleDespiteOwningModule() { if (isHidden()) setModuleOwnershipKind(ModuleOwnershipKind::Visible); } /// Get the kind of module ownership for this declaration. ModuleOwnershipKind getModuleOwnershipKind() const { return NextInContextAndBits.getInt(); } /// Set whether this declaration is hidden from name lookup. void setModuleOwnershipKind(ModuleOwnershipKind MOK) { assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned && MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() && !hasLocalOwningModuleStorage()) && "no storage available for owning module for this declaration"); NextInContextAndBits.setInt(MOK); } unsigned getIdentifierNamespace() const { return IdentifierNamespace; } bool isInIdentifierNamespace(unsigned NS) const { return getIdentifierNamespace() & NS; } static unsigned getIdentifierNamespaceForKind(Kind DK); bool hasTagIdentifierNamespace() const { return isTagIdentifierNamespace(getIdentifierNamespace()); } static bool isTagIdentifierNamespace(unsigned NS) { // TagDecls have Tag and Type set and may also have TagFriend. return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); } /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from /// getDeclContext() (SemanticDC). /// e.g.: /// /// namespace A { /// void f(); // SemanticDC == LexicalDC == 'namespace A' /// } /// void A::f(); // SemanticDC == namespace 'A' /// // LexicalDC == global namespace DeclContext *getLexicalDeclContext() { if (isInSemaDC()) return getSemanticDC(); return getMultipleDC()->LexicalDC; } const DeclContext *getLexicalDeclContext() const { return const_cast(this)->getLexicalDeclContext(); } /// Determine whether this declaration is declared out of line (outside its /// semantic context). virtual bool isOutOfLine() const; /// setDeclContext - Set both the semantic and lexical DeclContext /// to DC. void setDeclContext(DeclContext *DC); void setLexicalDeclContext(DeclContext *DC); /// Determine whether this declaration is a templated entity (whether it is // within the scope of a template parameter). bool isTemplated() const; /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this /// scoped decl is defined outside the current function or method. This is /// roughly global variables and functions, but also handles enums (which /// could be defined inside or outside a function etc). bool isDefinedOutsideFunctionOrMethod() const { return getParentFunctionOrMethod() == nullptr; } /// Returns true if this declaration lexically is inside a function. /// It recognizes non-defining declarations as well as members of local /// classes: /// \code /// void foo() { void bar(); } /// void foo2() { class ABC { void bar(); }; } /// \endcode bool isLexicallyWithinFunctionOrMethod() const; /// If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. const DeclContext *getParentFunctionOrMethod() const; DeclContext *getParentFunctionOrMethod() { return const_cast( const_cast(this)->getParentFunctionOrMethod()); } /// Retrieves the "canonical" declaration of the given declaration. virtual Decl *getCanonicalDecl() { return this; } const Decl *getCanonicalDecl() const { return const_cast(this)->getCanonicalDecl(); } /// Whether this particular Decl is a canonical one. bool isCanonicalDecl() const { return getCanonicalDecl() == this; } protected: /// Returns the next redeclaration or itself if this is the only decl. /// /// Decl subclasses that can be redeclared should override this method so that /// Decl::redecl_iterator can iterate over them. virtual Decl *getNextRedeclarationImpl() { return this; } /// Implementation of getPreviousDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getPreviousDeclImpl() { return nullptr; } /// Implementation of getMostRecentDecl(), to be overridden by any /// subclass that has a redeclaration chain. virtual Decl *getMostRecentDeclImpl() { return this; } public: /// Iterates through all the redeclarations of the same decl. class redecl_iterator { /// Current - The current declaration. Decl *Current = nullptr; Decl *Starter; public: using value_type = Decl *; using reference = const value_type &; using pointer = const value_type *; using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; redecl_iterator() = default; explicit redecl_iterator(Decl *C) : Current(C), Starter(C) {} reference operator*() const { return Current; } value_type operator->() const { return Current; } redecl_iterator& operator++() { assert(Current && "Advancing while iterator has reached end"); // Get either previous decl or latest decl. Decl *Next = Current->getNextRedeclarationImpl(); assert(Next && "Should return next redeclaration or itself, never null!"); Current = (Next != Starter) ? Next : nullptr; return *this; } redecl_iterator operator++(int) { redecl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(redecl_iterator x, redecl_iterator y) { return x.Current == y.Current; } friend bool operator!=(redecl_iterator x, redecl_iterator y) { return x.Current != y.Current; } }; using redecl_range = llvm::iterator_range; /// Returns an iterator range for all the redeclarations of the same /// decl. It will iterate at least once (when this decl is the only one). redecl_range redecls() const { return redecl_range(redecls_begin(), redecls_end()); } redecl_iterator redecls_begin() const { return redecl_iterator(const_cast(this)); } redecl_iterator redecls_end() const { return redecl_iterator(); } /// Retrieve the previous declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. Decl *getPreviousDecl() { return getPreviousDeclImpl(); } /// Retrieve the most recent declaration that declares the same entity /// as this declaration, or NULL if there is no previous declaration. const Decl *getPreviousDecl() const { return const_cast(this)->getPreviousDeclImpl(); } /// True if this is the first declaration in its redeclaration chain. bool isFirstDecl() const { return getPreviousDecl() == nullptr; } /// Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } /// Retrieve the most recent declaration that declares the same entity /// as this declaration (which may be this declaration). const Decl *getMostRecentDecl() const { return const_cast(this)->getMostRecentDeclImpl(); } /// getBody - If this Decl represents a declaration for a body of code, /// such as a function or method definition, this method returns the /// top-level Stmt* of that body. Otherwise this method returns null. virtual Stmt* getBody() const { return nullptr; } /// Returns true if this \c Decl represents a declaration for a body of /// code, such as a function or method definition. /// Note that \c hasBody can also return true if any redeclaration of this /// \c Decl represents a declaration for a body of code. virtual bool hasBody() const { return getBody() != nullptr; } /// getBodyRBrace - Gets the right brace of the body, if a body exists. /// This works whether the body is a CompoundStmt or a CXXTryStmt. SourceLocation getBodyRBrace() const; // global temp stats (until we have a per-module visitor) static void add(Kind k); static void EnableStatistics(); static void PrintStats(); /// isTemplateParameter - Determines whether this declaration is a /// template parameter. bool isTemplateParameter() const; /// isTemplateParameter - Determines whether this declaration is a /// template parameter pack. bool isTemplateParameterPack() const; /// Whether this declaration is a parameter pack. bool isParameterPack() const; /// returns true if this declaration is a template bool isTemplateDecl() const; /// Whether this declaration is a function or function template. bool isFunctionOrFunctionTemplate() const { return (DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction) || DeclKind == FunctionTemplate; } /// If this is a declaration that describes some template, this /// method returns that template declaration. TemplateDecl *getDescribedTemplate() const; /// Returns the function itself, or the templated function if this is a /// function template. FunctionDecl *getAsFunction() LLVM_READONLY; const FunctionDecl *getAsFunction() const { return const_cast(this)->getAsFunction(); } /// Changes the namespace of this declaration to reflect that it's /// a function-local extern declaration. /// /// These declarations appear in the lexical context of the extern /// declaration, but in the semantic context of the enclosing namespace /// scope. void setLocalExternDecl() { Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~IDNS_Ordinary; // It's OK for the declaration to still have the "invisible friend" flag or // the "conflicts with tag declarations in this scope" flag for the outer // scope. assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 && "namespace is not ordinary"); IdentifierNamespace |= IDNS_LocalExtern; if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary) IdentifierNamespace |= IDNS_Ordinary; } /// Determine whether this is a block-scope declaration with linkage. /// This will either be a local variable declaration declared 'extern', or a /// local function declaration. bool isLocalExternDecl() { return IdentifierNamespace & IDNS_LocalExtern; } /// Changes the namespace of this declaration to reflect that it's /// the object of a friend declaration. /// /// These declarations appear in the lexical context of the friending /// class, but in the semantic context of the actual entity. This property /// applies only to a specific decl object; other redeclarations of the /// same entity may not (and probably don't) share this property. void setObjectOfFriendDecl(bool PerformFriendInjection = false) { unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes neither ordinary nor tag"); assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) && "namespace includes other than ordinary or tag"); Decl *Prev = getPreviousDecl(); IdentifierNamespace &= ~(IDNS_Ordinary | IDNS_Tag | IDNS_Type); if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) IdentifierNamespace |= IDNS_Tag | IDNS_Type; } if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern | IDNS_NonMemberOperator)) { IdentifierNamespace |= IDNS_OrdinaryFriend; if (PerformFriendInjection || (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) IdentifierNamespace |= IDNS_Ordinary; } } enum FriendObjectKind { FOK_None, ///< Not a friend object. FOK_Declared, ///< A friend of a previously-declared entity. FOK_Undeclared ///< A friend of a previously-undeclared entity. }; /// Determines whether this declaration is the object of a /// friend declaration and, if so, what kind. /// /// There is currently no direct way to find the associated FriendDecl. FriendObjectKind getFriendObjectKind() const { unsigned mask = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); if (!mask) return FOK_None; return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? FOK_Declared : FOK_Undeclared); } /// Specifies that this declaration is a C++ overloaded non-member. void setNonMemberOperator() { assert(getKind() == Function || getKind() == FunctionTemplate); assert((IdentifierNamespace & IDNS_Ordinary) && "visible non-member operators should be in ordinary namespace"); IdentifierNamespace |= IDNS_NonMemberOperator; } static bool classofKind(Kind K) { return true; } static DeclContext *castToDeclContext(const Decl *); static Decl *castFromDeclContext(const DeclContext *); void print(raw_ostream &Out, unsigned Indentation = 0, bool PrintInstantiation = false) const; void print(raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0, bool PrintInstantiation = false) const; static void printGroup(Decl** Begin, unsigned NumDecls, raw_ostream &Out, const PrintingPolicy &Policy, unsigned Indentation = 0); // Debuggers don't usually respect default arguments. void dump() const; // Same as dump(), but forces color printing. void dumpColor() const; void dump(raw_ostream &Out, bool Deserialize = false) const; /// \return Unique reproducible object identifier int64_t getID() const; /// Looks through the Decl's underlying type to extract a FunctionType /// when possible. Will return null if the type underlying the Decl does not /// have a FunctionType. const FunctionType *getFunctionType(bool BlocksToo = true) const; private: void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, ASTContext &Ctx); protected: ASTMutationListener *getASTMutationListener() const; }; /// Determine whether two declarations declare the same entity. inline bool declaresSameEntity(const Decl *D1, const Decl *D2) { if (!D1 || !D2) return false; if (D1 == D2) return true; return D1->getCanonicalDecl() == D2->getCanonicalDecl(); } /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when /// doing something to a specific decl. class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { const Decl *TheDecl; SourceLocation Loc; SourceManager &SM; const char *Message; public: PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} void print(raw_ostream &OS) const override; }; /// The results of name lookup within a DeclContext. This is either a /// single result (with no stable storage) or a collection of results (with /// stable storage provided by the lookup table). class DeclContextLookupResult { using ResultTy = ArrayRef; ResultTy Result; // If there is only one lookup result, it would be invalidated by // reallocations of the name table, so store it separately. NamedDecl *Single = nullptr; static NamedDecl *const SingleElementDummyList; public: DeclContextLookupResult() = default; DeclContextLookupResult(ArrayRef Result) : Result(Result) {} DeclContextLookupResult(NamedDecl *Single) : Result(SingleElementDummyList), Single(Single) {} class iterator; using IteratorBase = llvm::iterator_adaptor_base; class iterator : public IteratorBase { value_type SingleElement; public: explicit iterator(pointer Pos, value_type Single = nullptr) : IteratorBase(Pos), SingleElement(Single) {} reference operator*() const { return SingleElement ? SingleElement : IteratorBase::operator*(); } }; using const_iterator = iterator; using pointer = iterator::pointer; using reference = iterator::reference; iterator begin() const { return iterator(Result.begin(), Single); } iterator end() const { return iterator(Result.end(), Single); } bool empty() const { return Result.empty(); } pointer data() const { return Single ? &Single : Result.data(); } size_t size() const { return Single ? 1 : Result.size(); } reference front() const { return Single ? Single : Result.front(); } reference back() const { return Single ? Single : Result.back(); } reference operator[](size_t N) const { return Single ? Single : Result[N]; } // FIXME: Remove this from the interface DeclContextLookupResult slice(size_t N) const { DeclContextLookupResult Sliced = Result.slice(N); Sliced.Single = Single; return Sliced; } }; /// DeclContext - This is used only as base class of specific decl types that /// can act as declaration contexts. These decls are (only the top classes /// that directly derive from DeclContext are mentioned, not their subclasses): /// /// TranslationUnitDecl /// ExternCContext /// NamespaceDecl /// TagDecl /// OMPDeclareReductionDecl /// FunctionDecl /// ObjCMethodDecl /// ObjCContainerDecl /// LinkageSpecDecl /// ExportDecl /// BlockDecl /// CapturedDecl class DeclContext { /// For makeDeclVisibleInContextImpl friend class ASTDeclReader; /// For reconcileExternalVisibleStorage, CreateStoredDeclsMap, /// hasNeedToReconcileExternalVisibleStorage friend class ExternalASTSource; /// For CreateStoredDeclsMap friend class DependentDiagnostic; /// For hasNeedToReconcileExternalVisibleStorage, /// hasLazyLocalLexicalLookups, hasLazyExternalLexicalLookups friend class ASTWriter; // We use uint64_t in the bit-fields below since some bit-fields // cross the unsigned boundary and this breaks the packing. /// Stores the bits used by DeclContext. /// If modified NumDeclContextBit, the ctor of DeclContext and the accessor /// methods in DeclContext should be updated appropriately. class DeclContextBitfields { friend class DeclContext; /// DeclKind - This indicates which class this is. uint64_t DeclKind : 7; /// Whether this declaration context also has some external /// storage that contains additional declarations that are lexically /// part of this context. mutable uint64_t ExternalLexicalStorage : 1; /// Whether this declaration context also has some external /// storage that contains additional declarations that are visible /// in this context. mutable uint64_t ExternalVisibleStorage : 1; /// Whether this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. mutable uint64_t NeedToReconcileExternalVisibleStorage : 1; /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. mutable uint64_t HasLazyLocalLexicalLookups : 1; /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. mutable uint64_t HasLazyExternalLexicalLookups : 1; /// If \c true, lookups should only return identifier from /// DeclContext scope (for example TranslationUnit). Used in /// LookupQualifiedName() mutable uint64_t UseQualifiedLookup : 1; }; /// Number of bits in DeclContextBitfields. enum { NumDeclContextBits = 13 }; /// Stores the bits used by TagDecl. /// If modified NumTagDeclBits and the accessor /// methods in TagDecl should be updated appropriately. class TagDeclBitfields { friend class TagDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; /// The TagKind enum. uint64_t TagDeclKind : 3; /// True if this is a definition ("struct foo {};"), false if it is a /// declaration ("struct foo;"). It is not considered a definition /// until the definition has been fully processed. uint64_t IsCompleteDefinition : 1; /// True if this is currently being defined. uint64_t IsBeingDefined : 1; /// True if this tag declaration is "embedded" (i.e., defined or declared /// for the very first time) in the syntax of a declarator. uint64_t IsEmbeddedInDeclarator : 1; /// True if this tag is free standing, e.g. "struct foo;". uint64_t IsFreeStanding : 1; /// Indicates whether it is possible for declarations of this kind /// to have an out-of-date definition. /// /// This option is only enabled when modules are enabled. uint64_t MayHaveOutOfDateDef : 1; /// Has the full definition of this type been required by a use somewhere in /// the TU. uint64_t IsCompleteDefinitionRequired : 1; }; /// Number of non-inherited bits in TagDeclBitfields. enum { NumTagDeclBits = 9 }; /// Stores the bits used by EnumDecl. /// If modified NumEnumDeclBit and the accessor /// methods in EnumDecl should be updated appropriately. class EnumDeclBitfields { friend class EnumDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in TagDeclBitfields. uint64_t : NumTagDeclBits; /// Width in bits required to store all the non-negative /// enumerators of this enum. uint64_t NumPositiveBits : 8; /// Width in bits required to store all the negative /// enumerators of this enum. uint64_t NumNegativeBits : 8; /// True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. uint64_t IsScoped : 1; /// If this tag declaration is a scoped enum, /// then this is true if the scoped enum was declared using the class /// tag, false if it was declared with the struct tag. No meaning is /// associated if this tag declaration is not a scoped enum. uint64_t IsScopedUsingClassTag : 1; /// True if this is an enumeration with fixed underlying type. Only /// possible in C++11, Microsoft extensions, or Objective C mode. uint64_t IsFixed : 1; /// True if a valid hash is stored in ODRHash. uint64_t HasODRHash : 1; }; /// Number of non-inherited bits in EnumDeclBitfields. enum { NumEnumDeclBits = 20 }; /// Stores the bits used by RecordDecl. /// If modified NumRecordDeclBits and the accessor /// methods in RecordDecl should be updated appropriately. class RecordDeclBitfields { friend class RecordDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in TagDeclBitfields. uint64_t : NumTagDeclBits; /// This is true if this struct ends with a flexible /// array member (e.g. int X[]) or if this union contains a struct that does. /// If so, this cannot be contained in arrays or other structs as a member. uint64_t HasFlexibleArrayMember : 1; /// Whether this is the type of an anonymous struct or union. uint64_t AnonymousStructOrUnion : 1; /// This is true if this struct has at least one member /// containing an Objective-C object pointer type. uint64_t HasObjectMember : 1; /// This is true if struct has at least one member of /// 'volatile' type. uint64_t HasVolatileMember : 1; /// Whether the field declarations of this record have been loaded /// from external storage. To avoid unnecessary deserialization of /// methods/nested types we allow deserialization of just the fields /// when needed. mutable uint64_t LoadedFieldsFromExternalStorage : 1; /// Basic properties of non-trivial C structs. uint64_t NonTrivialToPrimitiveDefaultInitialize : 1; uint64_t NonTrivialToPrimitiveCopy : 1; uint64_t NonTrivialToPrimitiveDestroy : 1; /// Indicates whether this struct is destroyed in the callee. uint64_t ParamDestroyedInCallee : 1; /// Represents the way this type is passed to a function. uint64_t ArgPassingRestrictions : 2; }; /// Number of non-inherited bits in RecordDeclBitfields. enum { NumRecordDeclBits = 11 }; /// Stores the bits used by OMPDeclareReductionDecl. /// If modified NumOMPDeclareReductionDeclBits and the accessor /// methods in OMPDeclareReductionDecl should be updated appropriately. class OMPDeclareReductionDeclBitfields { friend class OMPDeclareReductionDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; /// Kind of initializer, /// function call or omp_priv initializtion. uint64_t InitializerKind : 2; }; /// Number of non-inherited bits in OMPDeclareReductionDeclBitfields. enum { NumOMPDeclareReductionDeclBits = 2 }; /// Stores the bits used by FunctionDecl. /// If modified NumFunctionDeclBits and the accessor /// methods in FunctionDecl and CXXDeductionGuideDecl /// (for IsCopyDeductionCandidate) should be updated appropriately. class FunctionDeclBitfields { friend class FunctionDecl; /// For IsCopyDeductionCandidate friend class CXXDeductionGuideDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; uint64_t SClass : 3; uint64_t IsInline : 1; uint64_t IsInlineSpecified : 1; /// This is shared by CXXConstructorDecl, /// CXXConversionDecl, and CXXDeductionGuideDecl. uint64_t IsExplicitSpecified : 1; uint64_t IsVirtualAsWritten : 1; uint64_t IsPure : 1; uint64_t HasInheritedPrototype : 1; uint64_t HasWrittenPrototype : 1; uint64_t IsDeleted : 1; /// Used by CXXMethodDecl uint64_t IsTrivial : 1; /// This flag indicates whether this function is trivial for the purpose of /// calls. This is meaningful only when this function is a copy/move /// constructor or a destructor. uint64_t IsTrivialForCall : 1; /// Used by CXXMethodDecl uint64_t IsDefaulted : 1; /// Used by CXXMethodDecl uint64_t IsExplicitlyDefaulted : 1; uint64_t HasImplicitReturnZero : 1; uint64_t IsLateTemplateParsed : 1; uint64_t IsConstexpr : 1; uint64_t InstantiationIsPending : 1; /// Indicates if the function uses __try. uint64_t UsesSEHTry : 1; /// Indicates if the function was a definition /// but its body was skipped. uint64_t HasSkippedBody : 1; /// Indicates if the function declaration will /// have a body, once we're done parsing it. uint64_t WillHaveBody : 1; /// Indicates that this function is a multiversioned /// function using attribute 'target'. uint64_t IsMultiVersion : 1; /// [C++17] Only used by CXXDeductionGuideDecl. Indicates that /// the Deduction Guide is the implicitly generated 'copy /// deduction candidate' (is used during overload resolution). uint64_t IsCopyDeductionCandidate : 1; /// Store the ODRHash after first calculation. uint64_t HasODRHash : 1; }; /// Number of non-inherited bits in FunctionDeclBitfields. enum { NumFunctionDeclBits = 25 }; /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor /// methods in CXXConstructorDecl should be updated appropriately. class CXXConstructorDeclBitfields { friend class CXXConstructorDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// For the bits in FunctionDeclBitfields. uint64_t : NumFunctionDeclBits; /// 25 bits to fit in the remaining availible space. /// Note that this makes CXXConstructorDeclBitfields take /// exactly 64 bits and thus the width of NumCtorInitializers /// will need to be shrunk if some bit is added to NumDeclContextBitfields, /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. uint64_t NumCtorInitializers : 25; uint64_t IsInheritingConstructor : 1; }; /// Number of non-inherited bits in CXXConstructorDeclBitfields. enum { NumCXXConstructorDeclBits = 26 }; /// Stores the bits used by ObjCMethodDecl. /// If modified NumObjCMethodDeclBits and the accessor /// methods in ObjCMethodDecl should be updated appropriately. class ObjCMethodDeclBitfields { friend class ObjCMethodDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// The conventional meaning of this method; an ObjCMethodFamily. /// This is not serialized; instead, it is computed on demand and /// cached. mutable uint64_t Family : ObjCMethodFamilyBitWidth; /// instance (true) or class (false) method. uint64_t IsInstance : 1; uint64_t IsVariadic : 1; /// True if this method is the getter or setter for an explicit property. uint64_t IsPropertyAccessor : 1; /// Method has a definition. uint64_t IsDefined : 1; /// Method redeclaration in the same interface. uint64_t IsRedeclaration : 1; /// Is redeclared in the same interface. mutable uint64_t HasRedeclaration : 1; /// \@required/\@optional uint64_t DeclImplementation : 2; /// in, inout, etc. uint64_t objcDeclQualifier : 7; /// Indicates whether this method has a related result type. uint64_t RelatedResultType : 1; /// Whether the locations of the selector identifiers are in a /// "standard" position, a enum SelectorLocationsKind. uint64_t SelLocsKind : 2; /// Whether this method overrides any other in the class hierarchy. /// /// A method is said to override any method in the class's /// base classes, its protocols, or its categories' protocols, that has /// the same selector and is of the same kind (class or instance). /// A method in an implementation is not considered as overriding the same /// method in the interface or its categories. uint64_t IsOverriding : 1; /// Indicates if the method was a definition but its body was skipped. uint64_t HasSkippedBody : 1; }; /// Number of non-inherited bits in ObjCMethodDeclBitfields. enum { NumObjCMethodDeclBits = 24 }; /// Stores the bits used by ObjCContainerDecl. /// If modified NumObjCContainerDeclBits and the accessor /// methods in ObjCContainerDecl should be updated appropriately. class ObjCContainerDeclBitfields { friend class ObjCContainerDecl; /// For the bits in DeclContextBitfields uint32_t : NumDeclContextBits; // Not a bitfield but this saves space. // Note that ObjCContainerDeclBitfields is full. SourceLocation AtStart; }; /// Number of non-inherited bits in ObjCContainerDeclBitfields. /// Note that here we rely on the fact that SourceLocation is 32 bits /// wide. We check this with the static_assert in the ctor of DeclContext. enum { NumObjCContainerDeclBits = 64 - NumDeclContextBits }; /// Stores the bits used by LinkageSpecDecl. /// If modified NumLinkageSpecDeclBits and the accessor /// methods in LinkageSpecDecl should be updated appropriately. class LinkageSpecDeclBitfields { friend class LinkageSpecDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; /// The language for this linkage specification with values /// in the enum LinkageSpecDecl::LanguageIDs. uint64_t Language : 3; /// True if this linkage spec has braces. /// This is needed so that hasBraces() returns the correct result while the /// linkage spec body is being parsed. Once RBraceLoc has been set this is /// not used, so it doesn't need to be serialized. uint64_t HasBraces : 1; }; /// Number of non-inherited bits in LinkageSpecDeclBitfields. enum { NumLinkageSpecDeclBits = 4 }; /// Stores the bits used by BlockDecl. /// If modified NumBlockDeclBits and the accessor /// methods in BlockDecl should be updated appropriately. class BlockDeclBitfields { friend class BlockDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; uint64_t IsVariadic : 1; uint64_t CapturesCXXThis : 1; uint64_t BlockMissingReturnType : 1; uint64_t IsConversionFromLambda : 1; /// A bit that indicates this block is passed directly to a function as a /// non-escaping parameter. uint64_t DoesNotEscape : 1; }; /// Number of non-inherited bits in BlockDeclBitfields. enum { NumBlockDeclBits = 5 }; /// Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a /// dependent context). We maintain the invariant that, if the map /// contains an entry for a DeclarationName (and we haven't lazily /// omitted anything), then it contains all relevant entries for that /// name (modulo the hasExternalDecls() flag). mutable StoredDeclsMap *LookupPtr = nullptr; protected: /// This anonymous union stores the bits belonging to DeclContext and classes /// deriving from it. The goal is to use otherwise wasted /// space in DeclContext to store data belonging to derived classes. /// The space saved is especially significient when pointers are aligned /// to 8 bytes. In this case due to alignment requirements we have a /// little less than 8 bytes free in DeclContext which we can use. /// We check that none of the classes in this union is larger than /// 8 bytes with static_asserts in the ctor of DeclContext. union { DeclContextBitfields DeclContextBits; TagDeclBitfields TagDeclBits; EnumDeclBitfields EnumDeclBits; RecordDeclBitfields RecordDeclBits; OMPDeclareReductionDeclBitfields OMPDeclareReductionDeclBits; FunctionDeclBitfields FunctionDeclBits; CXXConstructorDeclBitfields CXXConstructorDeclBits; ObjCMethodDeclBitfields ObjCMethodDeclBits; ObjCContainerDeclBitfields ObjCContainerDeclBits; LinkageSpecDeclBitfields LinkageSpecDeclBits; BlockDeclBitfields BlockDeclBits; - - static_assert(sizeof(DeclContextBitfields) <= 8, - "DeclContextBitfields is larger than 8 bytes!"); - static_assert(sizeof(TagDeclBitfields) <= 8, - "TagDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(EnumDeclBitfields) <= 8, - "EnumDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(RecordDeclBitfields) <= 8, - "RecordDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(OMPDeclareReductionDeclBitfields) <= 8, - "OMPDeclareReductionDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(FunctionDeclBitfields) <= 8, - "FunctionDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(CXXConstructorDeclBitfields) <= 8, - "CXXConstructorDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCMethodDeclBitfields) <= 8, - "ObjCMethodDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCContainerDeclBitfields) <= 8, - "ObjCContainerDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(LinkageSpecDeclBitfields) <= 8, - "LinkageSpecDeclBitfields is larger than 8 bytes!"); - static_assert(sizeof(BlockDeclBitfields) <= 8, - "BlockDeclBitfields is larger than 8 bytes!"); }; + + static_assert(sizeof(DeclContextBitfields) <= 8, + "DeclContextBitfields is larger than 8 bytes!"); + static_assert(sizeof(TagDeclBitfields) <= 8, + "TagDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(EnumDeclBitfields) <= 8, + "EnumDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(RecordDeclBitfields) <= 8, + "RecordDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(OMPDeclareReductionDeclBitfields) <= 8, + "OMPDeclareReductionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionDeclBitfields) <= 8, + "FunctionDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(CXXConstructorDeclBitfields) <= 8, + "CXXConstructorDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCMethodDeclBitfields) <= 8, + "ObjCMethodDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCContainerDeclBitfields) <= 8, + "ObjCContainerDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(LinkageSpecDeclBitfields) <= 8, + "LinkageSpecDeclBitfields is larger than 8 bytes!"); + static_assert(sizeof(BlockDeclBitfields) <= 8, + "BlockDeclBitfields is larger than 8 bytes!"); /// FirstDecl - The first declaration stored within this declaration /// context. mutable Decl *FirstDecl = nullptr; /// LastDecl - The last declaration stored within this declaration /// context. FIXME: We could probably cache this value somewhere /// outside of the DeclContext, to reduce the size of DeclContext by /// another pointer. mutable Decl *LastDecl = nullptr; /// Build up a chain of declarations. /// /// \returns the first/last pair of declarations. static std::pair BuildDeclChain(ArrayRef Decls, bool FieldsAlreadyLoaded); DeclContext(Decl::Kind K); public: ~DeclContext(); Decl::Kind getDeclKind() const { return static_cast(DeclContextBits.DeclKind); } const char *getDeclKindName() const; /// getParent - Returns the containing DeclContext. DeclContext *getParent() { return cast(this)->getDeclContext(); } const DeclContext *getParent() const { return const_cast(this)->getParent(); } /// getLexicalParent - Returns the containing lexical DeclContext. May be /// different from getParent, e.g.: /// /// namespace A { /// struct S; /// } /// struct A::S {}; // getParent() == namespace 'A' /// // getLexicalParent() == translation unit /// DeclContext *getLexicalParent() { return cast(this)->getLexicalDeclContext(); } const DeclContext *getLexicalParent() const { return const_cast(this)->getLexicalParent(); } DeclContext *getLookupParent(); const DeclContext *getLookupParent() const { return const_cast(this)->getLookupParent(); } ASTContext &getParentASTContext() const { return cast(this)->getASTContext(); } bool isClosure() const { return getDeclKind() == Decl::Block; } bool isObjCContainer() const { switch (getDeclKind()) { case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: case Decl::ObjCImplementation: case Decl::ObjCInterface: case Decl::ObjCProtocol: return true; default: return false; } } bool isFunctionOrMethod() const { switch (getDeclKind()) { case Decl::Block: case Decl::Captured: case Decl::ObjCMethod: return true; default: return getDeclKind() >= Decl::firstFunction && getDeclKind() <= Decl::lastFunction; } } /// Test whether the context supports looking up names. bool isLookupContext() const { return !isFunctionOrMethod() && getDeclKind() != Decl::LinkageSpec && getDeclKind() != Decl::Export; } bool isFileContext() const { return getDeclKind() == Decl::TranslationUnit || getDeclKind() == Decl::Namespace; } bool isTranslationUnit() const { return getDeclKind() == Decl::TranslationUnit; } bool isRecord() const { return getDeclKind() >= Decl::firstRecord && getDeclKind() <= Decl::lastRecord; } bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isStdNamespace() const; bool isInlineNamespace() const; /// Determines whether this context is dependent on a /// template parameter. bool isDependentContext() const; /// isTransparentContext - Determines whether this context is a /// "transparent" context, meaning that the members declared in this /// context are semantically declared in the nearest enclosing /// non-transparent (opaque) context but are lexically declared in /// this context. For example, consider the enumerators of an /// enumeration type: /// @code /// enum E { /// Val1 /// }; /// @endcode /// Here, E is a transparent context, so its enumerator (Val1) will /// appear (semantically) that it is in the same context of E. /// Examples of transparent contexts include: enumerations (except for /// C++0x scoped enums), and C++ linkage specifications. bool isTransparentContext() const; /// Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C linkage. bool isExternCContext() const; /// Retrieve the nearest enclosing C linkage specification context. const LinkageSpecDecl *getExternCContext() const; /// Determines whether this context or some of its ancestors is a /// linkage specification context that specifies C++ linkage. bool isExternCXXContext() const; /// Determine whether this declaration context is equivalent /// to the declaration context DC. bool Equals(const DeclContext *DC) const { return DC && this->getPrimaryContext() == DC->getPrimaryContext(); } /// Determine whether this declaration context encloses the /// declaration context DC. bool Encloses(const DeclContext *DC) const; /// Find the nearest non-closure ancestor of this context, /// i.e. the innermost semantic parent of this context which is not /// a closure. A context may be its own non-closure ancestor. Decl *getNonClosureAncestor(); const Decl *getNonClosureAncestor() const { return const_cast(this)->getNonClosureAncestor(); } /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with /// a different set of declarations. This routine returns the /// "primary" DeclContext structure, which will contain the /// information needed to perform name lookup into this context. DeclContext *getPrimaryContext(); const DeclContext *getPrimaryContext() const { return const_cast(this)->getPrimaryContext(); } /// getRedeclContext - Retrieve the context in which an entity conflicts with /// other entities of the same name, or where it is a redeclaration if the /// two entities are compatible. This skips through transparent contexts. DeclContext *getRedeclContext(); const DeclContext *getRedeclContext() const { return const_cast(this)->getRedeclContext(); } /// Retrieve the nearest enclosing namespace context. DeclContext *getEnclosingNamespaceContext(); const DeclContext *getEnclosingNamespaceContext() const { return const_cast(this)->getEnclosingNamespaceContext(); } /// Retrieve the outermost lexically enclosing record context. RecordDecl *getOuterLexicalRecordContext(); const RecordDecl *getOuterLexicalRecordContext() const { return const_cast(this)->getOuterLexicalRecordContext(); } /// Test if this context is part of the enclosing namespace set of /// the context NS, as defined in C++0x [namespace.def]p9. If either context /// isn't a namespace, this is equivalent to Equals(). /// /// The enclosing namespace set of a namespace is the namespace and, if it is /// inline, its enclosing namespace, recursively. bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; /// Collects all of the declaration contexts that are semantically /// connected to this declaration context. /// /// For declaration contexts that have multiple semantically connected but /// syntactically distinct contexts, such as C++ namespaces, this routine /// retrieves the complete set of such declaration contexts in source order. /// For example, given: /// /// \code /// namespace N { /// int x; /// } /// namespace N { /// int y; /// } /// \endcode /// /// The \c Contexts parameter will contain both definitions of N. /// /// \param Contexts Will be cleared and set to the set of declaration /// contexts that are semanticaly connected to this declaration context, /// in source order, including this context (which may be the only result, /// for non-namespace contexts). void collectAllContexts(SmallVectorImpl &Contexts); /// decl_iterator - Iterates through the declarations stored /// within this context. class decl_iterator { /// Current - The current declaration. Decl *Current = nullptr; public: using value_type = Decl *; using reference = const value_type &; using pointer = const value_type *; using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; decl_iterator() = default; explicit decl_iterator(Decl *C) : Current(C) {} reference operator*() const { return Current; } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return Current; } decl_iterator& operator++() { Current = Current->getNextDeclInContext(); return *this; } decl_iterator operator++(int) { decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(decl_iterator x, decl_iterator y) { return x.Current == y.Current; } friend bool operator!=(decl_iterator x, decl_iterator y) { return x.Current != y.Current; } }; using decl_range = llvm::iterator_range; /// decls_begin/decls_end - Iterate over the declarations stored in /// this context. decl_range decls() const { return decl_range(decls_begin(), decls_end()); } decl_iterator decls_begin() const; decl_iterator decls_end() const { return decl_iterator(); } bool decls_empty() const; /// noload_decls_begin/end - Iterate over the declarations stored in this /// context that are currently loaded; don't attempt to retrieve anything /// from an external source. decl_range noload_decls() const { return decl_range(noload_decls_begin(), noload_decls_end()); } decl_iterator noload_decls_begin() const { return decl_iterator(FirstDecl); } decl_iterator noload_decls_end() const { return decl_iterator(); } /// specific_decl_iterator - Iterates over a subrange of /// declarations stored in a DeclContext, providing only those that /// are of type SpecificDecl (or a class derived from it). This /// iterator is used, for example, to provide iteration over just /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). template class specific_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && !isa(*Current)) ++Current; } public: using value_type = SpecificDecl *; // TODO: Add reference and pointer types (with some appropriate proxy type) // if we ever have a need for them. using reference = void; using pointer = void; using difference_type = std::iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; specific_decl_iterator() = default; /// specific_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } // This doesn't meet the iterator requirements, but it's convenient value_type operator->() const { return **this; } specific_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } specific_decl_iterator operator++(int) { specific_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) { return x.Current != y.Current; } }; /// Iterates over a filtered subrange of declarations stored /// in a DeclContext. /// /// This iterator visits only those declarations that are of type /// SpecificDecl (or a class derived from it) and that meet some /// additional run-time criteria. This iterator is used, for /// example, to provide access to the instance methods within an /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and /// Acceptable = ObjCMethodDecl::isInstanceMethod). template class filtered_decl_iterator { /// Current - The current, underlying declaration iterator, which /// will either be NULL or will point to a declaration of /// type SpecificDecl. DeclContext::decl_iterator Current; /// SkipToNextDecl - Advances the current position up to the next /// declaration of type SpecificDecl that also meets the criteria /// required by Acceptable. void SkipToNextDecl() { while (*Current && (!isa(*Current) || (Acceptable && !(cast(*Current)->*Acceptable)()))) ++Current; } public: using value_type = SpecificDecl *; // TODO: Add reference and pointer types (with some appropriate proxy type) // if we ever have a need for them. using reference = void; using pointer = void; using difference_type = std::iterator_traits::difference_type; using iterator_category = std::forward_iterator_tag; filtered_decl_iterator() = default; /// filtered_decl_iterator - Construct a new iterator over a /// subset of the declarations the range [C, /// end-of-declarations). If A is non-NULL, it is a pointer to a /// member function of SpecificDecl that should return true for /// all of the SpecificDecl instances that will be in the subset /// of iterators. For example, if you want Objective-C instance /// methods, SpecificDecl will be ObjCMethodDecl and A will be /// &ObjCMethodDecl::isInstanceMethod. explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { SkipToNextDecl(); } value_type operator*() const { return cast(*Current); } value_type operator->() const { return cast(*Current); } filtered_decl_iterator& operator++() { ++Current; SkipToNextDecl(); return *this; } filtered_decl_iterator operator++(int) { filtered_decl_iterator tmp(*this); ++(*this); return tmp; } friend bool operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current == y.Current; } friend bool operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) { return x.Current != y.Current; } }; /// Add the declaration D into this context. /// /// This routine should be invoked when the declaration D has first /// been declared, to place D into the context where it was /// (lexically) defined. Every declaration must be added to one /// (and only one!) context, where it can be visited via /// [decls_begin(), decls_end()). Once a declaration has been added /// to its lexical context, the corresponding DeclContext owns the /// declaration. /// /// If D is also a NamedDecl, it will be made visible within its /// semantic context via makeDeclVisibleInContext. void addDecl(Decl *D); /// Add the declaration D into this context, but suppress /// searches for external declarations with the same name. /// /// Although analogous in function to addDecl, this removes an /// important check. This is only useful if the Decl is being /// added in response to an external search; in all other cases, /// addDecl() is the right function to use. /// See the ASTImporter for use cases. void addDeclInternal(Decl *D); /// Add the declaration D to this context without modifying /// any lookup tables. /// /// This is useful for some operations in dependent contexts where /// the semantic context might not be dependent; this basically /// only happens with friends. void addHiddenDecl(Decl *D); /// Removes a declaration from this context. void removeDecl(Decl *D); /// Checks whether a declaration is in this context. bool containsDecl(Decl *D) const; /// Checks whether a declaration is in this context. /// This also loads the Decls from the external source before the check. bool containsDeclAndLoad(Decl *D) const; using lookup_result = DeclContextLookupResult; using lookup_iterator = lookup_result::iterator; /// lookup - Find the declarations (if any) with the given Name in /// this context. Returns a range of iterators that contains all of /// the declarations with this name, with object, function, member, /// and enumerator names preceding any tag name. Note that this /// routine will not look into parent contexts. lookup_result lookup(DeclarationName Name) const; /// Find the declarations with the given name that are visible /// within this context; don't attempt to retrieve anything from an /// external source. lookup_result noload_lookup(DeclarationName Name); /// A simplistic name lookup mechanism that performs name lookup /// into this declaration context without consulting the external source. /// /// This function should almost never be used, because it subverts the /// usual relationship between a DeclContext and the external source. /// See the ASTImporter for the (few, but important) use cases. /// /// FIXME: This is very inefficient; replace uses of it with uses of /// noload_lookup. void localUncachedLookup(DeclarationName Name, SmallVectorImpl &Results); /// Makes a declaration visible within this context. /// /// This routine makes the declaration D visible to name lookup /// within this context and, if this is a transparent context, /// within its parent contexts up to the first enclosing /// non-transparent context. Making a declaration visible within a /// context does not transfer ownership of a declaration, and a /// declaration can be visible in many contexts that aren't its /// lexical context. /// /// If D is a redeclaration of an existing declaration that is /// visible from this context, as determined by /// NamedDecl::declarationReplaces, the previous declaration will be /// replaced with D. void makeDeclVisibleInContext(NamedDecl *D); /// all_lookups_iterator - An iterator that provides a view over the results /// of looking up every possible name. class all_lookups_iterator; using lookups_range = llvm::iterator_range; lookups_range lookups() const; // Like lookups(), but avoids loading external declarations. // If PreserveInternalState, avoids building lookup data structures too. lookups_range noload_lookups(bool PreserveInternalState) const; /// Iterators over all possible lookups within this context. all_lookups_iterator lookups_begin() const; all_lookups_iterator lookups_end() const; /// Iterators over all possible lookups within this context that are /// currently loaded; don't attempt to retrieve anything from an external /// source. all_lookups_iterator noload_lookups_begin() const; all_lookups_iterator noload_lookups_end() const; struct udir_iterator; using udir_iterator_base = llvm::iterator_adaptor_base; struct udir_iterator : udir_iterator_base { udir_iterator(lookup_iterator I) : udir_iterator_base(I) {} UsingDirectiveDecl *operator*() const; }; using udir_range = llvm::iterator_range; udir_range using_directives() const; // These are all defined in DependentDiagnostic.h. class ddiag_iterator; using ddiag_range = llvm::iterator_range; inline ddiag_range ddiags() const; // Low-level accessors /// Mark that there are external lexical declarations that we need /// to include in our lookup table (and that are not available as external /// visible lookups). These extra lookup results will be found by walking /// the lexical declarations of this context. This should be used only if /// setHasExternalLexicalStorage() has been called on any decl context for /// which this is the primary context. void setMustBuildLookupTable() { assert(this == getPrimaryContext() && "should only be called on primary context"); DeclContextBits.HasLazyExternalLexicalLookups = true; } /// Retrieve the internal representation of the lookup structure. /// This may omit some names if we are lazily building the structure. StoredDeclsMap *getLookupPtr() const { return LookupPtr; } /// Ensure the lookup structure is fully-built and return it. StoredDeclsMap *buildLookup(); /// Whether this DeclContext has external storage containing /// additional declarations that are lexically in this context. bool hasExternalLexicalStorage() const { return DeclContextBits.ExternalLexicalStorage; } /// State whether this DeclContext has external storage for /// declarations lexically in this context. void setHasExternalLexicalStorage(bool ES = true) const { DeclContextBits.ExternalLexicalStorage = ES; } /// Whether this DeclContext has external storage containing /// additional declarations that are visible in this context. bool hasExternalVisibleStorage() const { return DeclContextBits.ExternalVisibleStorage; } /// State whether this DeclContext has external storage for /// declarations visible in this context. void setHasExternalVisibleStorage(bool ES = true) const { DeclContextBits.ExternalVisibleStorage = ES; if (ES && LookupPtr) DeclContextBits.NeedToReconcileExternalVisibleStorage = true; } /// Determine whether the given declaration is stored in the list of /// declarations lexically within this context. bool isDeclInLexicalTraversal(const Decl *D) const { return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl || D == LastDecl); } bool setUseQualifiedLookup(bool use = true) const { bool old_value = DeclContextBits.UseQualifiedLookup; DeclContextBits.UseQualifiedLookup = use; return old_value; } bool shouldUseQualifiedLookup() const { return DeclContextBits.UseQualifiedLookup; } static bool classof(const Decl *D); static bool classof(const DeclContext *D) { return true; } void dumpDeclContext() const; void dumpLookups() const; void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false, bool Deserialize = false) const; private: /// Whether this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. bool hasNeedToReconcileExternalVisibleStorage() const { return DeclContextBits.NeedToReconcileExternalVisibleStorage; } /// State that this declaration context has had externally visible /// storage added since the last lookup. In this case, \c LookupPtr's /// invariant may not hold and needs to be fixed before we perform /// another lookup. void setNeedToReconcileExternalVisibleStorage(bool Need = true) const { DeclContextBits.NeedToReconcileExternalVisibleStorage = Need; } /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. bool hasLazyLocalLexicalLookups() const { return DeclContextBits.HasLazyLocalLexicalLookups; } /// If \c true, this context may have local lexical declarations /// that are missing from the lookup table. void setHasLazyLocalLexicalLookups(bool HasLLLL = true) const { DeclContextBits.HasLazyLocalLexicalLookups = HasLLLL; } /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. bool hasLazyExternalLexicalLookups() const { return DeclContextBits.HasLazyExternalLexicalLookups; } /// If \c true, the external source may have lexical declarations /// that are missing from the lookup table. void setHasLazyExternalLexicalLookups(bool HasLELL = true) const { DeclContextBits.HasLazyExternalLexicalLookups = HasLELL; } void reconcileExternalVisibleStorage() const; bool LoadLexicalDeclsFromExternalStorage() const; /// Makes a declaration visible within this context, but /// suppresses searches for external declarations with the same /// name. /// /// Analogous to makeDeclVisibleInContext, but for the exclusive /// use of addDeclInternal(). void makeDeclVisibleInContextInternal(NamedDecl *D); StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; void loadLazyLocalLexicalLookups(); void buildLookupImpl(DeclContext *DCtx, bool Internal); void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Rediscoverable); void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); }; inline bool Decl::isTemplateParameter() const { return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || getKind() == TemplateTemplateParm; } // Specialization selected when ToTy is not a known subclass of DeclContext. template ::value> struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } static ToTy *doit(DeclContext *Val) { return static_cast(Decl::castFromDeclContext(Val)); } }; // Specialization selected when ToTy is a known subclass of DeclContext. template struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { return static_cast(Val); } static ToTy *doit(DeclContext *Val) { return static_cast(Val); } }; } // namespace clang namespace llvm { /// isa(DeclContext*) template struct isa_impl { static bool doit(const ::clang::DeclContext &Val) { return To::classofKind(Val.getDeclKind()); } }; /// cast(DeclContext*) template struct cast_convert_val { static const ToTy &doit(const ::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static ToTy &doit(::clang::DeclContext &Val) { return *::clang::cast_convert_decl_context::doit(&Val); } }; template struct cast_convert_val { static const ToTy *doit(const ::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; template struct cast_convert_val { static ToTy *doit(::clang::DeclContext *Val) { return ::clang::cast_convert_decl_context::doit(Val); } }; /// Implement cast_convert_val for Decl -> DeclContext conversions. template struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { static ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { static ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { static const ::clang::DeclContext &doit(const FromTy &Val) { return *FromTy::castToDeclContext(&Val); } }; template struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { static const ::clang::DeclContext *doit(const FromTy *Val) { return FromTy::castToDeclContext(Val); } }; } // namespace llvm #endif // LLVM_CLANG_AST_DECLBASE_H Index: stable/12/contrib/llvm/tools/clang/include/clang/AST/Type.h =================================================================== --- stable/12/contrib/llvm/tools/clang/include/clang/AST/Type.h (revision 349966) +++ stable/12/contrib/llvm/tools/clang/include/clang/AST/Type.h (revision 349967) @@ -1,6849 +1,6849 @@ //===- Type.h - C Language Family Type Representation -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// C Language Family Type Representation /// /// This file defines the clang::Type interface and subclasses, used to /// represent types for languages in the C family. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPE_H #define LLVM_CLANG_AST_TYPE_H #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" #include "llvm/Support/TrailingObjects.h" #include #include #include #include #include #include #include namespace clang { class ExtQuals; class QualType; class TagDecl; class Type; enum { TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits }; } // namespace clang namespace llvm { template struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits< ::clang::Type*> { static inline void *getAsVoidPointer(::clang::Type *P) { return P; } static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template<> struct PointerLikeTypeTraits< ::clang::ExtQuals*> { static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { return static_cast< ::clang::ExtQuals*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template <> struct isPodLike { static const bool value = true; }; } // namespace llvm namespace clang { class ASTContext; template class CanQual; class CXXRecordDecl; class DeclContext; class EnumDecl; class Expr; class ExtQualsTypeCommonBase; class FunctionDecl; class IdentifierInfo; class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; struct PrintingPolicy; class RecordDecl; class Stmt; class TagDecl; class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; class TemplateTypeParmDecl; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; using CanQualType = CanQual; // Provide forward declarations for all of the *Type classes. #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" /// The collection of all-type qualifiers we support. /// Clang supports five independent qualifiers: /// * C99: const, volatile, and restrict /// * MS: __unaligned /// * Embedded C (TR18037): address spaces /// * Objective C: the GC attributes (none, weak, or strong) class Qualifiers { public: enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, Restrict = 0x2, Volatile = 0x4, CVRMask = Const | Volatile | Restrict }; enum GC { GCNone = 0, Weak, Strong }; enum ObjCLifetime { /// There is no lifetime qualification on this type. OCL_None, /// This object can be modified without requiring retains or /// releases. OCL_ExplicitNone, /// Assigning into this object requires the old value to be /// released and the new value to be retained. The timing of the /// release of the old value is inexact: it may be moved to /// immediately after the last known point where the value is /// live. OCL_Strong, /// Reading or writing from this object requires a barrier call. OCL_Weak, /// Assigning into this object requires a lifetime extension. OCL_Autoreleasing }; enum { /// The maximum supported address space number. /// 23 bits should be enough for anyone. MaxAddressSpace = 0x7fffffu, /// The width of the "fast" qualifier mask. FastWidth = 3, /// The fast qualifier mask. FastMask = (1 << FastWidth) - 1 }; /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { // If both are only CVR-qualified, bit operations are sufficient. if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { Qualifiers Q; Q.Mask = L.Mask & R.Mask; L.Mask &= ~Q.Mask; R.Mask &= ~Q.Mask; return Q; } Qualifiers Q; unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); Q.addCVRQualifiers(CommonCRV); L.removeCVRQualifiers(CommonCRV); R.removeCVRQualifiers(CommonCRV); if (L.getObjCGCAttr() == R.getObjCGCAttr()) { Q.setObjCGCAttr(L.getObjCGCAttr()); L.removeObjCGCAttr(); R.removeObjCGCAttr(); } if (L.getObjCLifetime() == R.getObjCLifetime()) { Q.setObjCLifetime(L.getObjCLifetime()); L.removeObjCLifetime(); R.removeObjCLifetime(); } if (L.getAddressSpace() == R.getAddressSpace()) { Q.setAddressSpace(L.getAddressSpace()); L.removeAddressSpace(); R.removeAddressSpace(); } return Q; } static Qualifiers fromFastMask(unsigned Mask) { Qualifiers Qs; Qs.addFastQualifiers(Mask); return Qs; } static Qualifiers fromCVRMask(unsigned CVR) { Qualifiers Qs; Qs.addCVRQualifiers(CVR); return Qs; } static Qualifiers fromCVRUMask(unsigned CVRU) { Qualifiers Qs; Qs.addCVRUQualifiers(CVRU); return Qs; } // Deserialize qualifiers from an opaque representation. static Qualifiers fromOpaqueValue(unsigned opaque) { Qualifiers Qs; Qs.Mask = opaque; return Qs; } // Serialize these qualifiers into an opaque representation. unsigned getAsOpaqueValue() const { return Mask; } bool hasConst() const { return Mask & Const; } bool hasOnlyConst() const { return Mask == Const; } void removeConst() { Mask &= ~Const; } void addConst() { Mask |= Const; } bool hasVolatile() const { return Mask & Volatile; } bool hasOnlyVolatile() const { return Mask == Volatile; } void removeVolatile() { Mask &= ~Volatile; } void addVolatile() { Mask |= Volatile; } bool hasRestrict() const { return Mask & Restrict; } bool hasOnlyRestrict() const { return Mask == Restrict; } void removeRestrict() { Mask &= ~Restrict; } void addRestrict() { Mask |= Restrict; } bool hasCVRQualifiers() const { return getCVRQualifiers(); } unsigned getCVRQualifiers() const { return Mask & CVRMask; } unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } void setCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask = (Mask & ~CVRMask) | mask; } void removeCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask &= ~mask; } void removeCVRQualifiers() { removeCVRQualifiers(CVRMask); } void addCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask |= mask; } void addCVRUQualifiers(unsigned mask) { assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits"); Mask |= mask; } bool hasUnaligned() const { return Mask & UMask; } void setUnaligned(bool flag) { Mask = (Mask & ~UMask) | (flag ? UMask : 0); } void removeUnaligned() { Mask &= ~UMask; } void addUnaligned() { Mask |= UMask; } bool hasObjCGCAttr() const { return Mask & GCAttrMask; } GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } void setObjCGCAttr(GC type) { Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); } void removeObjCGCAttr() { setObjCGCAttr(GCNone); } void addObjCGCAttr(GC type) { assert(type); setObjCGCAttr(type); } Qualifiers withoutObjCGCAttr() const { Qualifiers qs = *this; qs.removeObjCGCAttr(); return qs; } Qualifiers withoutObjCLifetime() const { Qualifiers qs = *this; qs.removeObjCLifetime(); return qs; } bool hasObjCLifetime() const { return Mask & LifetimeMask; } ObjCLifetime getObjCLifetime() const { return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); } void setObjCLifetime(ObjCLifetime type) { Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); } void removeObjCLifetime() { setObjCLifetime(OCL_None); } void addObjCLifetime(ObjCLifetime type) { assert(type); assert(!hasObjCLifetime()); Mask |= (type << LifetimeShift); } /// True if the lifetime is neither None or ExplicitNone. bool hasNonTrivialObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime > OCL_ExplicitNone); } /// True if the lifetime is either strong or weak. bool hasStrongOrWeakObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime == OCL_Strong || lifetime == OCL_Weak); } bool hasAddressSpace() const { return Mask & AddressSpaceMask; } LangAS getAddressSpace() const { return static_cast(Mask >> AddressSpaceShift); } bool hasTargetSpecificAddressSpace() const { return isTargetAddressSpace(getAddressSpace()); } /// Get the address space attribute value to be printed by diagnostics. unsigned getAddressSpaceAttributePrintValue() const { auto Addr = getAddressSpace(); // This function is not supposed to be used with language specific // address spaces. If that happens, the diagnostic message should consider // printing the QualType instead of the address space value. assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); if (Addr != LangAS::Default) return toTargetAddressSpace(Addr); // TODO: The diagnostic messages where Addr may be 0 should be fixed // since it cannot differentiate the situation where 0 denotes the default // address space or user specified __attribute__((address_space(0))). return 0; } void setAddressSpace(LangAS space) { assert((unsigned)space <= MaxAddressSpace); Mask = (Mask & ~AddressSpaceMask) | (((uint32_t) space) << AddressSpaceShift); } void removeAddressSpace() { setAddressSpace(LangAS::Default); } void addAddressSpace(LangAS space) { assert(space != LangAS::Default); setAddressSpace(space); } // Fast qualifiers are those that can be allocated directly // on a QualType object. bool hasFastQualifiers() const { return getFastQualifiers(); } unsigned getFastQualifiers() const { return Mask & FastMask; } void setFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask = (Mask & ~FastMask) | mask; } void removeFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask &= ~mask; } void removeFastQualifiers() { removeFastQualifiers(FastMask); } void addFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask |= mask; } /// Return true if the set contains any qualifiers which require an ExtQuals /// node to be allocated. bool hasNonFastQualifiers() const { return Mask & ~FastMask; } Qualifiers getNonFastQualifiers() const { Qualifiers Quals = *this; Quals.setFastQualifiers(0); return Quals; } /// Return true if the set contains any qualifiers. bool hasQualifiers() const { return Mask; } bool empty() const { return !Mask; } /// Add the qualifiers from the given set to this set. void addQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-or it in. if (!(Q.Mask & ~CVRMask)) Mask |= Q.Mask; else { Mask |= (Q.Mask & CVRMask); if (Q.hasAddressSpace()) addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) addObjCGCAttr(Q.getObjCGCAttr()); if (Q.hasObjCLifetime()) addObjCLifetime(Q.getObjCLifetime()); } } /// Remove the qualifiers from the given set from this set. void removeQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-and the inverse in. if (!(Q.Mask & ~CVRMask)) Mask &= ~Q.Mask; else { Mask &= ~(Q.Mask & CVRMask); if (getObjCGCAttr() == Q.getObjCGCAttr()) removeObjCGCAttr(); if (getObjCLifetime() == Q.getObjCLifetime()) removeObjCLifetime(); if (getAddressSpace() == Q.getAddressSpace()) removeAddressSpace(); } } /// Add the qualifiers from the given set to this set, given that /// they don't conflict. void addConsistentQualifiers(Qualifiers qs) { assert(getAddressSpace() == qs.getAddressSpace() || !hasAddressSpace() || !qs.hasAddressSpace()); assert(getObjCGCAttr() == qs.getObjCGCAttr() || !hasObjCGCAttr() || !qs.hasObjCGCAttr()); assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() || !qs.hasObjCLifetime()); Mask |= qs.Mask; } /// Returns true if this address space is a superset of the other one. /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of /// overlapping address spaces. /// CL1.1 or CL1.2: /// every address space is a superset of itself. /// CL2.0 adds: /// __generic is a superset of any address space except for __constant. bool isAddressSpaceSupersetOf(Qualifiers other) const { return // Address spaces must match exactly. getAddressSpace() == other.getAddressSpace() || // Otherwise in OpenCLC v2.0 s6.5.5: every address space except // for __constant can be used as __generic. (getAddressSpace() == LangAS::opencl_generic && other.getAddressSpace() != LangAS::opencl_constant); } /// Determines if these qualifiers compatibly include another set. /// Generally this answers the question of whether an object with the other /// qualifiers can be safely used as an object with these qualifiers. bool compatiblyIncludes(Qualifiers other) const { return isAddressSpaceSupersetOf(other) && // ObjC GC qualifiers can match, be added, or be removed, but can't // be changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || !other.hasObjCGCAttr()) && // ObjC lifetime qualifiers must match exactly. getObjCLifetime() == other.getObjCLifetime() && // CVR qualifiers may subset. (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && // U qualifier may superset. (!other.hasUnaligned() || hasUnaligned()); } /// Determines if these qualifiers compatibly include another set of /// qualifiers from the narrow perspective of Objective-C ARC lifetime. /// /// One set of Objective-C lifetime qualifiers compatibly includes the other /// if the lifetime qualifiers match, or if both are non-__weak and the /// including set also contains the 'const' qualifier, or both are non-__weak /// and one is None (which can only happen in non-ARC modes). bool compatiblyIncludesObjCLifetime(Qualifiers other) const { if (getObjCLifetime() == other.getObjCLifetime()) return true; if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) return false; if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) return true; return hasConst(); } /// Determine whether this set of qualifiers is a strict superset of /// another set of qualifiers, not considering qualifier compatibility. bool isStrictSupersetOf(Qualifiers Other) const; bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } explicit operator bool() const { return hasQualifiers(); } Qualifiers &operator+=(Qualifiers R) { addQualifiers(R); return *this; } // Union two qualifier sets. If an enumerated qualifier appears // in both sets, use the one from the right. friend Qualifiers operator+(Qualifiers L, Qualifiers R) { L += R; return L; } Qualifiers &operator-=(Qualifiers R) { removeQualifiers(R); return *this; } /// Compute the difference between two qualifier sets. friend Qualifiers operator-(Qualifiers L, Qualifiers R) { L -= R; return L; } std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, bool appendSpaceIfNonEmpty = false) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } private: // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| // |C R V|U|GCAttr|Lifetime|AddressSpace| uint32_t Mask = 0; static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; static const uint32_t GCAttrMask = 0x30; static const uint32_t GCAttrShift = 4; static const uint32_t LifetimeMask = 0x1C0; static const uint32_t LifetimeShift = 6; static const uint32_t AddressSpaceMask = ~(CVRMask | UMask | GCAttrMask | LifetimeMask); static const uint32_t AddressSpaceShift = 9; }; /// A std::pair-like structure for storing a qualified type split /// into its local qualifiers and its locally-unqualified type. struct SplitQualType { /// The locally-unqualified type. const Type *Ty = nullptr; /// The local qualifiers. Qualifiers Quals; SplitQualType() = default; SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} SplitQualType getSingleStepDesugaredType() const; // end of this file // Make std::tie work. std::pair asPair() const { return std::pair(Ty, Quals); } friend bool operator==(SplitQualType a, SplitQualType b) { return a.Ty == b.Ty && a.Quals == b.Quals; } friend bool operator!=(SplitQualType a, SplitQualType b) { return a.Ty != b.Ty || a.Quals != b.Quals; } }; /// The kind of type we are substituting Objective-C type arguments into. /// /// The kind of substitution affects the replacement of type parameters when /// no concrete type information is provided, e.g., when dealing with an /// unspecialized type. enum class ObjCSubstitutionContext { /// An ordinary type. Ordinary, /// The result type of a method or function. Result, /// The parameter type of a method or function. Parameter, /// The type of a property. Property, /// The superclass of a type. Superclass, }; /// A (possibly-)qualified type. /// /// For efficiency, we don't store CV-qualified types as nodes on their /// own: instead each reference to a type stores the qualifiers. This /// greatly reduces the number of nodes we need to allocate for types (for /// example we only need one for 'int', 'const int', 'volatile int', /// 'const volatile int', etc). /// /// As an added efficiency bonus, instead of making this a pair, we /// just store the two bits we care about in the low bits of the /// pointer. To handle the packing/unpacking, we make QualType be a /// simple wrapper class that acts like a smart pointer. A third bit /// indicates whether there are extended qualifiers present, in which /// case the pointer points to a special structure. class QualType { friend class QualifierCollector; // Thankfully, these are efficiently composable. llvm::PointerIntPair, Qualifiers::FastWidth> Value; const ExtQuals *getExtQualsUnsafe() const { return Value.getPointer().get(); } const Type *getTypePtrUnsafe() const { return Value.getPointer().get(); } const ExtQualsTypeCommonBase *getCommonPtr() const { assert(!isNull() && "Cannot retrieve a NULL type pointer"); auto CommonPtrVal = reinterpret_cast(Value.getOpaqueValue()); CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); return reinterpret_cast(CommonPtrVal); } public: QualType() = default; QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} unsigned getLocalFastQualifiers() const { return Value.getInt(); } void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } /// Retrieves a pointer to the underlying (unqualified) type. /// /// This function requires that the type not be NULL. If the type might be /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). const Type *getTypePtr() const; const Type *getTypePtrOrNull() const; /// Retrieves a pointer to the name of the base type. const IdentifierInfo *getBaseTypeIdentifier() const; /// Divides a QualType into its unqualified type and a set of local /// qualifiers. SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(const void *Ptr) { QualType T; T.Value.setFromOpaqueValue(const_cast(Ptr)); return T; } const Type &operator*() const { return *getTypePtr(); } const Type *operator->() const { return getTypePtr(); } bool isCanonical() const; bool isCanonicalAsParam() const; /// Return true if this QualType doesn't point to a type yet. bool isNull() const { return Value.getPointer().isNull(); } /// Determine whether this particular QualType instance has the /// "const" qualifier set, without looking through typedefs that may have /// added "const" at a different level. bool isLocalConstQualified() const { return (getLocalFastQualifiers() & Qualifiers::Const); } /// Determine whether this type is const-qualified. bool isConstQualified() const; /// Determine whether this particular QualType instance has the /// "restrict" qualifier set, without looking through typedefs that may have /// added "restrict" at a different level. bool isLocalRestrictQualified() const { return (getLocalFastQualifiers() & Qualifiers::Restrict); } /// Determine whether this type is restrict-qualified. bool isRestrictQualified() const; /// Determine whether this particular QualType instance has the /// "volatile" qualifier set, without looking through typedefs that may have /// added "volatile" at a different level. bool isLocalVolatileQualified() const { return (getLocalFastQualifiers() & Qualifiers::Volatile); } /// Determine whether this type is volatile-qualified. bool isVolatileQualified() const; /// Determine whether this particular QualType instance has any /// qualifiers, without looking through any typedefs that might add /// qualifiers at a different level. bool hasLocalQualifiers() const { return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); } /// Determine whether this type has any qualifiers. bool hasQualifiers() const; /// Determine whether this particular QualType instance has any /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType /// instance. bool hasLocalNonFastQualifiers() const { return Value.getPointer().is(); } /// Retrieve the set of qualifiers local to this particular QualType /// instance, not including any qualifiers acquired through typedefs or /// other sugar. Qualifiers getLocalQualifiers() const; /// Retrieve the set of qualifiers applied to this type. Qualifiers getQualifiers() const; /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// local to this particular QualType instance, not including any qualifiers /// acquired through typedefs or other sugar. unsigned getLocalCVRQualifiers() const { return getLocalFastQualifiers(); } /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// applied to this type. unsigned getCVRQualifiers() const; bool isConstant(const ASTContext& Ctx) const { return QualType::isConstant(*this, Ctx); } /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). bool isPODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the rules of the C++98 /// standard, regardless of the current compilation's language. bool isCXX98PODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the more relaxed rules /// of the C++11 standard, regardless of the current compilation's language. /// (C++0x [basic.types]p9). Note that, unlike /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account. bool isCXX11PODType(const ASTContext &Context) const; /// Return true if this is a trivial type per (C++0x [basic.types]p9) bool isTrivialType(const ASTContext &Context) const; /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; /// Returns true if it is a class and it might be dynamic. bool mayBeDynamicClass() const; /// Returns true if it is not a class or if the class might not be dynamic. bool mayBeNotDynamicClass() const; // Don't promise in the API that anything besides 'const' can be // easily added. /// Add the `const` type qualifier to this QualType. void addConst() { addFastQualifiers(Qualifiers::Const); } QualType withConst() const { return withFastQualifiers(Qualifiers::Const); } /// Add the `volatile` type qualifier to this QualType. void addVolatile() { addFastQualifiers(Qualifiers::Volatile); } QualType withVolatile() const { return withFastQualifiers(Qualifiers::Volatile); } /// Add the `restrict` qualifier to this QualType. void addRestrict() { addFastQualifiers(Qualifiers::Restrict); } QualType withRestrict() const { return withFastQualifiers(Qualifiers::Restrict); } QualType withCVRQualifiers(unsigned CVR) const { return withFastQualifiers(CVR); } void addFastQualifiers(unsigned TQs) { assert(!(TQs & ~Qualifiers::FastMask) && "non-fast qualifier bits set in mask!"); Value.setInt(Value.getInt() | TQs); } void removeLocalConst(); void removeLocalVolatile(); void removeLocalRestrict(); void removeLocalCVRQualifiers(unsigned Mask); void removeLocalFastQualifiers() { Value.setInt(0); } void removeLocalFastQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); Value.setInt(Value.getInt() & ~Mask); } // Creates a type with the given qualifiers in addition to any // qualifiers already on this type. QualType withFastQualifiers(unsigned TQs) const { QualType T = *this; T.addFastQualifiers(TQs); return T; } // Creates a type with exactly the given fast qualifiers, removing // any existing fast qualifiers. QualType withExactLocalFastQualifiers(unsigned TQs) const { return withoutLocalFastQualifiers().withFastQualifiers(TQs); } // Removes fast qualifiers, but leaves any extended qualifiers in place. QualType withoutLocalFastQualifiers() const { QualType T = *this; T.removeLocalFastQualifiers(); return T; } QualType getCanonicalType() const; /// Return this type with all of the instance-specific qualifiers /// removed, but without removing any qualifiers that may have been applied /// through typedefs. QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } /// Retrieve the unqualified variant of the given type, /// removing as little sugar as possible. /// /// This routine looks through various kinds of sugar to find the /// least-desugared type that is unqualified. For example, given: /// /// \code /// typedef int Integer; /// typedef const Integer CInteger; /// typedef CInteger DifferenceType; /// \endcode /// /// Executing \c getUnqualifiedType() on the type \c DifferenceType will /// desugar until we hit the type \c Integer, which has no qualifiers on it. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline QualType getUnqualifiedType() const; /// Retrieve the unqualified variant of the given type, removing as little /// sugar as possible. /// /// Like getUnqualifiedType(), but also returns the set of /// qualifiers that were built up. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline SplitQualType getSplitUnqualifiedType() const; /// Determine whether this type is more qualified than the other /// given type, requiring exact equality for non-CVR qualifiers. bool isMoreQualifiedThan(QualType Other) const; /// Determine whether this type is at least as qualified as the other /// given type, requiring exact equality for non-CVR qualifiers. bool isAtLeastAsQualifiedAs(QualType Other) const; QualType getNonReferenceType() const; /// Determine the type of a (typically non-lvalue) expression with the /// specified result type. /// /// This routine should be used for expressions for which the return type is /// explicitly specified (e.g., in a cast or call) and isn't necessarily /// an lvalue. It removes a top-level reference (since there are no /// expressions of reference type) and deletes top-level cvr-qualifiers /// from non-class types (in C++) or all types (in C). QualType getNonLValueExprType(const ASTContext &Context) const; /// Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. /// /// Qualifiers are left in place. QualType getDesugaredType(const ASTContext &Context) const { return getDesugaredType(*this, Context); } SplitQualType getSplitDesugaredType() const { return getSplitDesugaredType(*this); } /// Return the specified type with one level of "sugar" removed from /// the type. /// /// This routine takes off the first typedef, typeof, etc. If the outer level /// of the type is already concrete, it returns it unmodified. QualType getSingleStepDesugaredType(const ASTContext &Context) const { return getSingleStepDesugaredTypeImpl(*this, Context); } /// Returns the specified type after dropping any /// outer-level parentheses. QualType IgnoreParens() const { if (isa(*this)) return QualType::IgnoreParens(*this); return *this; } /// Indicate whether the specified types and qualifiers are identical. friend bool operator==(const QualType &LHS, const QualType &RHS) { return LHS.Value == RHS.Value; } friend bool operator!=(const QualType &LHS, const QualType &RHS) { return LHS.Value != RHS.Value; } static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy) { return getAsString(split.Ty, split.Quals, Policy); } static std::string getAsString(const Type *ty, Qualifiers qs, const PrintingPolicy &Policy); std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const; static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0) { return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); } static void print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0); void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { return getAsStringInternal(split.Ty, split.Quals, out, policy); } static void getAsStringInternal(const Type *ty, Qualifiers qs, std::string &out, const PrintingPolicy &policy); class StreamedQualTypeHelper { const QualType &T; const PrintingPolicy &Policy; const Twine &PlaceHolder; unsigned Indentation; public: StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, const Twine &PlaceHolder, unsigned Indentation) : T(T), Policy(Policy), PlaceHolder(PlaceHolder), Indentation(Indentation) {} friend raw_ostream &operator<<(raw_ostream &OS, const StreamedQualTypeHelper &SQT) { SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); return OS; } }; StreamedQualTypeHelper stream(const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const { return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); } void dump(const char *s) const; void dump() const; void dump(llvm::raw_ostream &OS) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(getAsOpaquePtr()); } /// Return the address space of this type. inline LangAS getAddressSpace() const; /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; /// true when Type is objc's weak. bool isObjCGCWeak() const { return getObjCGCAttr() == Qualifiers::Weak; } /// true when Type is objc's strong. bool isObjCGCStrong() const { return getObjCGCAttr() == Qualifiers::Strong; } /// Returns lifetime attribute of this type. Qualifiers::ObjCLifetime getObjCLifetime() const { return getQualifiers().getObjCLifetime(); } bool hasNonTrivialObjCLifetime() const { return getQualifiers().hasNonTrivialObjCLifetime(); } bool hasStrongOrWeakObjCLifetime() const { return getQualifiers().hasStrongOrWeakObjCLifetime(); } // true when Type is objc's weak and weak is enabled but ARC isn't. bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PDIK_Trivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PDIK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PDIK_ARCWeak, /// The type is a struct containing a field whose type is not PCK_Trivial. PDIK_Struct }; /// Functions to query basic properties of non-trivial C struct types. /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to default initialize /// and return the kind. PrimitiveDefaultInitializeKind isNonTrivialToPrimitiveDefaultInitialize() const; enum PrimitiveCopyKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PCK_Trivial, /// The type would be trivial except that it is volatile-qualified. Types /// that fall into one of the other non-trivial cases may additionally be /// volatile-qualified. PCK_VolatileTrivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PCK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PCK_ARCWeak, /// The type is a struct containing a field whose type is neither /// PCK_Trivial nor PCK_VolatileTrivial. /// Note that a C++ struct type does not necessarily match this; C++ copying /// semantics are too complex to express here, in part because they depend /// on the exact constructor or assignment operator that is chosen by /// overload resolution to do the copy. PCK_Struct }; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to copy and return the /// kind. PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to destructively /// move and return the kind. Destructive move in this context is a C++-style /// move in which the source object is placed in a valid but unspecified state /// after it is moved, as opposed to a truly destructive move in which the /// source object is placed in an uninitialized state. PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const; enum DestructionKind { DK_none, DK_cxx_destructor, DK_objc_strong_lifetime, DK_objc_weak_lifetime, DK_nontrivial_c_struct }; /// Returns a nonzero value if objects of this type require /// non-trivial work to clean up after. Non-zero because it's /// conceivable that qualifiers (objc_gc(weak)?) could make /// something require destruction. DestructionKind isDestructedType() const { return isDestructedTypeImpl(*this); } /// Determine whether expressions of the given type are forbidden /// from being lvalues in C. /// /// The expression types that are forbidden to be lvalues are: /// - 'void', but not qualified void /// - function types /// /// The exact rule here is C99 6.3.2.1: /// An lvalue is an expression with an object type or an incomplete /// type other than void. bool isCForbiddenLValueType() const; /// Substitute type arguments for the Objective-C type parameters used in the /// subject type. /// /// \param ctx ASTContext in which the type exists. /// /// \param typeArgs The type arguments that will be substituted for the /// Objective-C type parameters in the subject type, which are generally /// computed via \c Type::getObjCSubstitutions. If empty, the type /// parameters will be replaced with their bounds or id/Class, as appropriate /// for the context. /// /// \param context The context in which the subject type was written. /// /// \returns the resulting type. QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef typeArgs, ObjCSubstitutionContext context) const; /// Substitute type arguments from an object type for the Objective-C type /// parameters used in the subject type. /// /// This operation combines the computation of type arguments for /// substitution (\c Type::getObjCSubstitutions) with the actual process of /// substitution (\c QualType::substObjCTypeArgs) for the convenience of /// callers that need to perform a single substitution in isolation. /// /// \param objectType The type of the object whose member type we're /// substituting into. For example, this might be the receiver of a message /// or the base of a property access. /// /// \param dc The declaration context from which the subject type was /// retrieved, which indicates (for example) which type parameters should /// be substituted. /// /// \param context The context in which the subject type was written. /// /// \returns the subject type after replacing all of the Objective-C type /// parameters with their corresponding arguments. QualType substObjCMemberType(QualType objectType, const DeclContext *dc, ObjCSubstitutionContext context) const; /// Strip Objective-C "__kindof" types from the given type. QualType stripObjCKindOfType(const ASTContext &ctx) const; /// Remove all qualifiers including _Atomic. QualType getAtomicUnqualifiedType() const; private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the // caller. static bool isConstant(QualType T, const ASTContext& Ctx); static QualType getDesugaredType(QualType T, const ASTContext &Context); static SplitQualType getSplitDesugaredType(QualType T); static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); static QualType getSingleStepDesugaredTypeImpl(QualType type, const ASTContext &C); static QualType IgnoreParens(QualType T); static DestructionKind isDestructedTypeImpl(QualType type); }; } // namespace clang namespace llvm { /// Implement simplify_type for QualType, so that we can dyn_cast from QualType /// to a specific Type class. template<> struct simplify_type< ::clang::QualType> { using SimpleType = const ::clang::Type *; static SimpleType getSimplifiedValue(::clang::QualType Val) { return Val.getTypePtr(); } }; // Teach SmallPtrSet that QualType is "basically a pointer". template<> struct PointerLikeTypeTraits { static inline void *getAsVoidPointer(clang::QualType P) { return P.getAsOpaquePtr(); } static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; } // namespace llvm namespace clang { /// Base class that is common to both the \c ExtQuals and \c Type /// classes, which allows \c QualType to access the common fields between the /// two. class ExtQualsTypeCommonBase { friend class ExtQuals; friend class QualType; friend class Type; /// The "base" type of an extended qualifiers type (\c ExtQuals) or /// a self-referential pointer (for \c Type). /// /// This pointer allows an efficient mapping from a QualType to its /// underlying type pointer. const Type *const BaseType; /// The canonical type of this type. A QualType. QualType CanonicalType; ExtQualsTypeCommonBase(const Type *baseType, QualType canon) : BaseType(baseType), CanonicalType(canon) {} }; /// We can encode up to four bits in the low bits of a /// type pointer, but there are many more type qualifiers that we want /// to be able to apply to an arbitrary type. Therefore we have this /// struct, intended to be heap-allocated and used by QualType to /// store qualifiers. /// /// The current design tags the 'const', 'restrict', and 'volatile' qualifiers /// in three low bits on the QualType pointer; a fourth bit records whether /// the pointer is an ExtQuals node. The extended qualifiers (address spaces, /// Objective-C GC attributes) are much more rare. class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { // NOTE: changing the fast qualifiers should be straightforward as // long as you don't make 'const' non-fast. // 1. Qualifiers: // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). // Fast qualifiers must occupy the low-order bits. // b) Update Qualifiers::FastWidth and FastMask. // 2. QualType: // a) Update is{Volatile,Restrict}Qualified(), defined inline. // b) Update remove{Volatile,Restrict}, defined near the end of // this header. // 3. ASTContext: // a) Update get{Volatile,Restrict}Type. /// The immutable set of qualifiers applied by this node. Always contains /// extended qualifiers. Qualifiers Quals; ExtQuals *this_() { return this; } public: ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) : ExtQualsTypeCommonBase(baseType, canon.isNull() ? QualType(this_(), 0) : canon), Quals(quals) { assert(Quals.hasNonFastQualifiers() && "ExtQuals created with no fast qualifiers"); assert(!Quals.hasFastQualifiers() && "ExtQuals created with fast qualifiers"); } Qualifiers getQualifiers() const { return Quals; } bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } Qualifiers::ObjCLifetime getObjCLifetime() const { return Quals.getObjCLifetime(); } bool hasAddressSpace() const { return Quals.hasAddressSpace(); } LangAS getAddressSpace() const { return Quals.getAddressSpace(); } const Type *getBaseType() const { return BaseType; } public: void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, getBaseType(), Quals); } static void Profile(llvm::FoldingSetNodeID &ID, const Type *BaseType, Qualifiers Quals) { assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); ID.AddPointer(BaseType); Quals.Profile(ID); } }; /// The kind of C++11 ref-qualifier associated with a function type. /// This determines whether a member function's "this" object can be an /// lvalue, rvalue, or neither. enum RefQualifierKind { /// No ref-qualifier was provided. RQ_None = 0, /// An lvalue ref-qualifier was provided (\c &). RQ_LValue, /// An rvalue ref-qualifier was provided (\c &&). RQ_RValue }; /// Which keyword(s) were used to create an AutoType. enum class AutoTypeKeyword { /// auto Auto, /// decltype(auto) DecltypeAuto, /// __auto_type (GNU extension) GNUAutoType }; /// The base class of the type hierarchy. /// /// A central concept with types is that each type always has a canonical /// type. A canonical type is the type with any typedef names stripped out /// of it or the types it references. For example, consider: /// /// typedef int foo; /// typedef foo* bar; /// 'int *' 'foo *' 'bar' /// /// There will be a Type object created for 'int'. Since int is canonical, its /// CanonicalType pointer points to itself. There is also a Type for 'foo' (a /// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next /// there is a PointerType that represents 'int*', which, like 'int', is /// canonical. Finally, there is a PointerType type for 'foo*' whose canonical /// type is 'int*', and there is a TypedefType for 'bar', whose canonical type /// is also 'int*'. /// /// Non-canonical types are useful for emitting diagnostics, without losing /// information about typedefs being used. Canonical types are useful for type /// comparisons (they allow by-pointer equality tests) and useful for reasoning /// about whether something has a particular form (e.g. is a function type), /// because they implicitly, recursively, strip all typedefs out of a type. /// /// Types, once created, are immutable. /// class Type : public ExtQualsTypeCommonBase { public: enum TypeClass { #define TYPE(Class, Base) Class, #define LAST_TYPE(Class) TypeLast = Class, #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" TagFirst = Record, TagLast = Enum }; private: /// Bitfields required by the Type class. class TypeBitfields { friend class Type; template friend class TypePropertyCache; /// TypeClass bitfield - Enum that specifies what subclass this belongs to. unsigned TC : 8; /// Whether this type is a dependent type (C++ [temp.dep.type]). unsigned Dependent : 1; /// Whether this type somehow involves a template parameter, even /// if the resolution of the type does not depend on a template parameter. unsigned InstantiationDependent : 1; /// Whether this type is a variably-modified type (C99 6.7.5). unsigned VariablyModified : 1; /// Whether this type contains an unexpanded parameter pack /// (for C++11 variadic templates). unsigned ContainsUnexpandedParameterPack : 1; /// True if the cache (i.e. the bitfields here starting with /// 'Cache') is valid. mutable unsigned CacheValid : 1; /// Linkage of this type. mutable unsigned CachedLinkage : 3; /// Whether this type involves and local or unnamed types. mutable unsigned CachedLocalOrUnnamed : 1; /// Whether this type comes from an AST file. mutable unsigned FromAST : 1; bool isCacheValid() const { return CacheValid; } Linkage getLinkage() const { assert(isCacheValid() && "getting linkage from invalid cache"); return static_cast(CachedLinkage); } bool hasLocalOrUnnamedType() const { assert(isCacheValid() && "getting linkage from invalid cache"); return CachedLocalOrUnnamed; } }; enum { NumTypeBits = 18 }; protected: // These classes allow subclasses to somewhat cleanly pack bitfields // into Type. class ArrayTypeBitfields { friend class ArrayType; unsigned : NumTypeBits; /// CVR qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. unsigned IndexTypeQuals : 3; /// Storage class qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. /// Actually an ArrayType::ArraySizeModifier. unsigned SizeModifier : 3; }; class BuiltinTypeBitfields { friend class BuiltinType; unsigned : NumTypeBits; /// The kind (BuiltinType::Kind) of builtin type this is. unsigned Kind : 8; }; /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. /// Only common bits are stored here. Additional uncommon bits are stored /// in a trailing object after FunctionProtoType. class FunctionTypeBitfields { friend class FunctionProtoType; friend class FunctionType; unsigned : NumTypeBits; /// Extra information which affects how the function is called, like /// regparm and the calling convention. unsigned ExtInfo : 12; /// The ref-qualifier associated with a \c FunctionProtoType. /// /// This is a value of type \c RefQualifierKind. unsigned RefQualifier : 2; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. /// The qualifiers are part of FunctionProtoType because... /// /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. unsigned FastTypeQuals : Qualifiers::FastWidth; /// Whether this function has extended Qualifiers. unsigned HasExtQuals : 1; /// The number of parameters this function has, not counting '...'. /// According to [implimits] 8 bits should be enough here but this is /// somewhat easy to exceed with metaprogramming and so we would like to /// keep NumParams as wide as reasonably possible. unsigned NumParams : 16; /// The type of exception specification this function has. unsigned ExceptionSpecType : 4; /// Whether this function has extended parameter information. unsigned HasExtParameterInfos : 1; /// Whether the function is variadic. unsigned Variadic : 1; /// Whether this function has a trailing return type. unsigned HasTrailingReturn : 1; }; class ObjCObjectTypeBitfields { friend class ObjCObjectType; unsigned : NumTypeBits; /// The number of type arguments stored directly on this object type. unsigned NumTypeArgs : 7; /// The number of protocols stored directly on this object type. unsigned NumProtocols : 6; /// Whether this is a "kindof" type. unsigned IsKindOf : 1; }; class ReferenceTypeBitfields { friend class ReferenceType; unsigned : NumTypeBits; /// True if the type was originally spelled with an lvalue sigil. /// This is never true of rvalue references but can also be false /// on lvalue references because of C++0x [dcl.typedef]p9, /// as follows: /// /// typedef int &ref; // lvalue, spelled lvalue /// typedef int &&rvref; // rvalue /// ref &a; // lvalue, inner ref, spelled lvalue /// ref &&a; // lvalue, inner ref /// rvref &a; // lvalue, inner ref, spelled lvalue /// rvref &&a; // rvalue, inner ref unsigned SpelledAsLValue : 1; /// True if the inner type is a reference type. This only happens /// in non-canonical forms. unsigned InnerRef : 1; }; class TypeWithKeywordBitfields { friend class TypeWithKeyword; unsigned : NumTypeBits; /// An ElaboratedTypeKeyword. 8 bits for efficient access. unsigned Keyword : 8; }; enum { NumTypeWithKeywordBits = 8 }; class ElaboratedTypeBitfields { friend class ElaboratedType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// Whether the ElaboratedType has a trailing OwnedTagDecl. unsigned HasOwnedTagDecl : 1; }; class VectorTypeBitfields { friend class VectorType; friend class DependentVectorType; unsigned : NumTypeBits; /// The kind of vector, either a generic vector type or some /// target-specific vector type such as for AltiVec or Neon. unsigned VecKind : 3; /// The number of elements in the vector. unsigned NumElements : 29 - NumTypeBits; enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; }; class AttributedTypeBitfields { friend class AttributedType; unsigned : NumTypeBits; /// An AttributedType::Kind unsigned AttrKind : 32 - NumTypeBits; }; class AutoTypeBitfields { friend class AutoType; unsigned : NumTypeBits; /// Was this placeholder type spelled as 'auto', 'decltype(auto)', /// or '__auto_type'? AutoTypeKeyword value. unsigned Keyword : 2; }; class SubstTemplateTypeParmPackTypeBitfields { friend class SubstTemplateTypeParmPackType; unsigned : NumTypeBits; /// The number of template arguments in \c Arguments, which is /// expected to be able to hold at least 1024 according to [implimits]. /// However as this limit is somewhat easy to hit with template /// metaprogramming we'd prefer to keep it as large as possible. /// At the moment it has been left as a non-bitfield since this type /// safely fits in 64 bits as an unsigned, so there is no reason to /// introduce the performance impact of a bitfield. unsigned NumArgs; }; class TemplateSpecializationTypeBitfields { friend class TemplateSpecializationType; unsigned : NumTypeBits; /// Whether this template specialization type is a substituted type alias. unsigned TypeAlias : 1; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class DependentTemplateSpecializationTypeBitfields { friend class DependentTemplateSpecializationType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class PackExpansionTypeBitfields { friend class PackExpansionType; unsigned : NumTypeBits; /// The number of expansions that this pack expansion will /// generate when substituted (+1), which is expected to be able to /// hold at least 1024 according to [implimits]. However, as this limit /// is somewhat easy to hit with template metaprogramming we'd prefer to /// keep it as large as possible. At the moment it has been left as a /// non-bitfield since this type safely fits in 64 bits as an unsigned, so /// there is no reason to introduce the performance impact of a bitfield. /// /// This field will only have a non-zero value when some of the parameter /// packs that occur within the pattern have been substituted but others /// have not. unsigned NumExpansions; }; union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; ElaboratedTypeBitfields ElaboratedTypeBits; VectorTypeBitfields VectorTypeBits; SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; DependentTemplateSpecializationTypeBitfields DependentTemplateSpecializationTypeBits; PackExpansionTypeBitfields PackExpansionTypeBits; - - static_assert(sizeof(TypeBitfields) <= 8, - "TypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ArrayTypeBitfields) <= 8, - "ArrayTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AttributedTypeBitfields) <= 8, - "AttributedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AutoTypeBitfields) <= 8, - "AutoTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(BuiltinTypeBitfields) <= 8, - "BuiltinTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(FunctionTypeBitfields) <= 8, - "FunctionTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, - "ObjCObjectTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ReferenceTypeBitfields) <= 8, - "ReferenceTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(TypeWithKeywordBitfields) <= 8, - "TypeWithKeywordBitfields is larger than 8 bytes!"); - static_assert(sizeof(ElaboratedTypeBitfields) <= 8, - "ElaboratedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(VectorTypeBitfields) <= 8, - "VectorTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, - "SubstTemplateTypeParmPackTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, - "TemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, - "DependentTemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(PackExpansionTypeBitfields) <= 8, - "PackExpansionTypeBitfields is larger than 8 bytes"); }; + + static_assert(sizeof(TypeBitfields) <= 8, + "TypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ArrayTypeBitfields) <= 8, + "ArrayTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AttributedTypeBitfields) <= 8, + "AttributedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(AutoTypeBitfields) <= 8, + "AutoTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(BuiltinTypeBitfields) <= 8, + "BuiltinTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(FunctionTypeBitfields) <= 8, + "FunctionTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, + "ObjCObjectTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(ReferenceTypeBitfields) <= 8, + "ReferenceTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(TypeWithKeywordBitfields) <= 8, + "TypeWithKeywordBitfields is larger than 8 bytes!"); + static_assert(sizeof(ElaboratedTypeBitfields) <= 8, + "ElaboratedTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(VectorTypeBitfields) <= 8, + "VectorTypeBitfields is larger than 8 bytes!"); + static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, + "SubstTemplateTypeParmPackTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, + "TemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, + "DependentTemplateSpecializationTypeBitfields is larger" + " than 8 bytes!"); + static_assert(sizeof(PackExpansionTypeBitfields) <= 8, + "PackExpansionTypeBitfields is larger than 8 bytes"); private: template friend class TypePropertyCache; /// Set whether this type comes from an AST file. void setFromAST(bool V = true) const { TypeBits.FromAST = V; } protected: friend class ASTContext; Type(TypeClass tc, QualType canon, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; TypeBits.InstantiationDependent = Dependent || InstantiationDependent; TypeBits.VariablyModified = VariablyModified; TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; TypeBits.CacheValid = false; TypeBits.CachedLocalOrUnnamed = false; TypeBits.CachedLinkage = NoLinkage; TypeBits.FromAST = false; } // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } void setDependent(bool D = true) { TypeBits.Dependent = D; if (D) TypeBits.InstantiationDependent = true; } void setInstantiationDependent(bool D = true) { TypeBits.InstantiationDependent = D; } void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } void setContainsUnexpandedParameterPack(bool PP = true) { TypeBits.ContainsUnexpandedParameterPack = PP; } public: friend class ASTReader; friend class ASTWriter; Type(const Type &) = delete; Type &operator=(const Type &) = delete; TypeClass getTypeClass() const { return static_cast(TypeBits.TC); } /// Whether this type comes from an AST file. bool isFromAST() const { return TypeBits.FromAST; } /// Whether this type is or contains an unexpanded parameter /// pack, used to support C++0x variadic templates. /// /// A type that contains a parameter pack shall be expanded by the /// ellipsis operator at some point. For example, the typedef in the /// following example contains an unexpanded parameter pack 'T': /// /// \code /// template /// struct X { /// typedef T* pointer_types; // ill-formed; T is a parameter pack. /// }; /// \endcode /// /// Note that this routine does not specify which bool containsUnexpandedParameterPack() const { return TypeBits.ContainsUnexpandedParameterPack; } /// Determines if this type would be canonical if it had no further /// qualification. bool isCanonicalUnqualified() const { return CanonicalType == QualType(this, 0); } /// Pull a single level of sugar off of this locally-unqualified type. /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() /// or QualType::getSingleStepDesugaredType(const ASTContext&). QualType getLocallyUnqualifiedSingleStepDesugaredType() const; /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. /// Return true if this is an incomplete type. /// A type that can describe objects, but which lacks information needed to /// determine its size (e.g. void, or a fwd declared struct). Clients of this /// routine will need to determine if the size is actually required. /// /// Def If non-null, and the type refers to some kind of declaration /// that can be completed (such as a C struct, C++ class, or Objective-C /// class), will be set to the declaration. bool isIncompleteType(NamedDecl **Def = nullptr) const; /// Return true if this is an incomplete or object /// type, in other words, not a function type. bool isIncompleteOrObjectType() const { return !isFunctionType(); } /// Determine whether this type is an object type. bool isObjectType() const { // C++ [basic.types]p8: // An object type is a (possibly cv-qualified) type that is not a // function type, not a reference type, and not a void type. return !isReferenceType() && !isFunctionType() && !isVoidType(); } /// Return true if this is a literal type /// (C++11 [basic.types]p10) bool isLiteralType(const ASTContext &Ctx) const; /// Test if this type is a standard-layout type. /// (C++0x [basic.type]p9) bool isStandardLayoutType() const; /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. /// Returns true if the type is a builtin type. bool isBuiltinType() const; /// Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; /// Test for a type which does not represent an actual type-system type but /// is instead used as a placeholder for various convenient purposes within /// Clang. All such types are BuiltinTypes. bool isPlaceholderType() const; const BuiltinType *getAsPlaceholderType() const; /// Test for a specific placeholder type. bool isSpecificPlaceholderType(unsigned K) const; /// Test for a placeholder type other than Overload; see /// BuiltinType::isNonOverloadPlaceholderType. bool isNonOverloadPlaceholderType() const; /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) bool isEnumeralType() const; /// Determine whether this type is a scoped enumeration type. bool isScopedEnumeralType() const; bool isBooleanType() const; bool isCharType() const; bool isWideCharType() const; bool isChar8Type() const; bool isChar16Type() const; bool isChar32Type() const; bool isAnyCharacterType() const; bool isIntegralType(const ASTContext &Ctx) const; /// Determine whether this type is an integral or enumeration type. bool isIntegralOrEnumerationType() const; /// Determine whether this type is an integral or unscoped enumeration type. bool isIntegralOrUnscopedEnumerationType() const; /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isComplexType() const; // C99 6.2.5p11 (complex) bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isFloat128Type() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) bool isAggregateType() const; bool isFundamentalType() const; bool isCompoundType() const; // Type Predicates: Check to see if this type is structurally the specified // type, ignoring typedefs and qualifiers. bool isFunctionType() const; bool isFunctionNoProtoType() const { return getAs(); } bool isFunctionProtoType() const { return getAs(); } bool isPointerType() const; bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isBlockPointerType() const; bool isVoidPointerType() const; bool isReferenceType() const; bool isLValueReferenceType() const; bool isRValueReferenceType() const; bool isFunctionPointerType() const; bool isMemberPointerType() const; bool isMemberFunctionPointerType() const; bool isMemberDataPointerType() const; bool isArrayType() const; bool isConstantArrayType() const; bool isIncompleteArrayType() const; bool isVariableArrayType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; bool isClassType() const; bool isStructureType() const; bool isObjCBoxableRecordType() const; bool isInterfaceType() const; bool isStructureOrClassType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type bool isObjCNSObjectType() const; // __attribute__((NSObject)) bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) // FIXME: change this to 'raw' interface type, so we can used 'interface' type // for the common case. bool isObjCObjectType() const; // NSString or typeof(*(id)0) bool isObjCQualifiedInterfaceType() const; // NSString bool isObjCQualifiedIdType() const; // id bool isObjCQualifiedClassType() const; // Class bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id /// Was this type written with the special inert-in-ARC __unsafe_unretained /// qualifier? /// /// This approximates the answer to the following question: if this /// translation unit were compiled in ARC, would this type be qualified /// with __unsafe_unretained? bool isObjCInertUnsafeUnretainedType() const { return hasAttr(attr::ObjCInertUnsafeUnretained); } /// Whether the type is Objective-C 'id' or a __kindof type of an /// object type, e.g., __kindof NSView * or __kindof id /// . /// /// \param bound Will be set to the bound on non-id subtype types, /// which will be (possibly specialized) Objective-C class type, or /// null for 'id. bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, const ObjCObjectType *&bound) const; bool isObjCClassType() const; // Class /// Whether the type is Objective-C 'Class' or a __kindof type of an /// Class type, e.g., __kindof Class . /// /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound /// here because Objective-C's type system cannot express "a class /// object for a subclass of NSFoo". bool isObjCClassOrClassKindOfType() const; bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isObjCARCBridgableType() const; bool isCARCBridgableType() const; bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++11 std::nullptr_t bool isAlignValT() const; // C++17 std::align_val_t bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLImageTypes.def" bool isImageType() const; // Any OpenCL image type bool isSamplerT() const; // OpenCL sampler_t bool isEventT() const; // OpenCL event_t bool isClkEventT() const; // OpenCL clk_event_t bool isQueueT() const; // OpenCL queue_t bool isReserveIDT() const; // OpenCL reserve_id_t #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLExtensionTypes.def" // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension bool isOCLIntelSubgroupAVCType() const; bool isOCLExtOpaqueType() const; // Any OpenCL extension type bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type /// Determines if this type, which must satisfy /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather /// than implicitly __strong. bool isObjCARCImplicitlyUnretainedType() const; /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; enum ScalarTypeKind { STK_CPointer, STK_BlockPointer, STK_ObjCObjectPointer, STK_MemberPointer, STK_Bool, STK_Integral, STK_Floating, STK_IntegralComplex, STK_FloatingComplex, STK_FixedPoint }; /// Given that this is a scalar type, classify it. ScalarTypeKind getScalarTypeKind() const; /// Whether this type is a dependent type, meaning that its definition /// somehow depends on a template parameter (C++ [temp.dep.type]). bool isDependentType() const { return TypeBits.Dependent; } /// Determine whether this type is an instantiation-dependent type, /// meaning that the type involves a template parameter (even if the /// definition does not actually depend on the type substituted for that /// template parameter). bool isInstantiationDependentType() const { return TypeBits.InstantiationDependent; } /// Determine whether this type is an undeduced type, meaning that /// it somehow involves a C++11 'auto' type or similar which has not yet been /// deduced. bool isUndeducedType() const; /// Whether this type is a variably-modified type (C99 6.7.5). bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } /// Whether this type involves a variable-length array type /// with a definite size. bool hasSizedVLAType() const; /// Whether this type is or contains a local or unnamed type. bool hasUnnamedOrLocalType() const; bool isOverloadableType() const; /// Determine wither this type is a C++ elaborated-type-specifier. bool isElaboratedTypeSpecifier() const; bool canDecayToPointerType() const; /// Whether this type is represented natively as a pointer. This includes /// pointers, references, block pointers, and Objective-C interface, /// qualified id, and qualified interface types, as well as nullptr_t. bool hasPointerRepresentation() const; /// Whether this type can represent an objective pointer type for the /// purpose of GC'ability bool hasObjCPointerRepresentation() const; /// Determine whether this type has an integer representation /// of some sort, e.g., it is an integer type or a vector. bool hasIntegerRepresentation() const; /// Determine whether this type has an signed integer representation /// of some sort, e.g., it is an signed integer type or a vector. bool hasSignedIntegerRepresentation() const; /// Determine whether this type has an unsigned integer representation /// of some sort, e.g., it is an unsigned integer type or a vector. bool hasUnsignedIntegerRepresentation() const; /// Determine whether this type has a floating-point representation /// of some sort, e.g., it is a floating-point type or a vector thereof. bool hasFloatingRepresentation() const; // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. const RecordType *getAsStructureType() const; /// NOTE: getAs*ArrayType are methods on ASTContext. const RecordType *getAsUnionType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. const ObjCObjectType *getAsObjCInterfaceType() const; // The following is a convenience method that returns an ObjCObjectPointerType // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; /// Retrieves the CXXRecordDecl that this type refers to, either /// because the type is a RecordType or because it is the injected-class-name /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; /// Retrieves the RecordDecl this type refers to. RecordDecl *getAsRecordDecl() const; /// Retrieves the TagDecl that this type refers to, either /// because the type is a TagType or because it is the injected-class-name /// type of a class template or class template partial specialization. TagDecl *getAsTagDecl() const; /// If this is a pointer or reference to a RecordType, return the /// CXXRecordDecl that the type refers to. /// /// If this is not a pointer or reference, or the type being pointed to does /// not refer to a CXXRecordDecl, returns NULL. const CXXRecordDecl *getPointeeCXXRecordDecl() const; /// Get the DeducedType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. DeducedType *getContainedDeducedType() const; /// Get the AutoType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. AutoType *getContainedAutoType() const { return dyn_cast_or_null(getContainedDeducedType()); } /// Determine whether this type was written with a leading 'auto' /// corresponding to a trailing return type (possibly for a nested /// function type within a pointer to function type or similar). bool hasAutoForTrailingReturnType() const; /// Member-template getAs'. Look through sugar for /// an instance of \. This scheme will eventually /// replace the specific getAsXXXX methods above. /// /// There are some specializations of this member template listed /// immediately following this class. template const T *getAs() const; /// Member-template getAsAdjusted. Look through specific kinds /// of sugar (parens, attributes, etc) for an instance of \. /// This is used when you need to walk over sugar nodes that represent some /// kind of type adjustment from a type that was written as a \ /// to another type that is still canonically a \. template const T *getAsAdjusted() const; /// A variant of getAs<> for array types which silently discards /// qualifiers from the outermost type. const ArrayType *getAsArrayTypeUnsafe() const; /// Member-template castAs. Look through sugar for /// the underlying instance of \. /// /// This method has the same relationship to getAs as cast has /// to dyn_cast; which is to say, the underlying type *must* /// have the intended type, and this method will never return null. template const T *castAs() const; /// A variant of castAs<> for array type which silently discards /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; /// Determine whether this type had the specified attribute applied to it /// (looking through top-level type sugar). bool hasAttr(attr::Kind AK) const; /// Get the base element type of this type, potentially discarding type /// qualifiers. This should never be used when type qualifiers /// are meaningful. const Type *getBaseElementTypeUnsafe() const; /// If this is an array type, return the element type of the array, /// potentially with type qualifiers missing. /// This should never be used when type qualifiers are meaningful. const Type *getArrayElementTypeNoTypeQual() const; /// If this is a pointer type, return the pointee type. /// If this is an array type, return the array element type. /// This should never be used when type qualifiers are meaningful. const Type *getPointeeOrArrayElementType() const; /// If this is a pointer, ObjC object pointer, or block /// pointer, this returns the respective pointee. QualType getPointeeType() const; /// Return the specified type with any "sugar" removed from the type, /// removing any typedefs, typeofs, etc., as well as any qualifiers. const Type *getUnqualifiedDesugaredType() const; /// More type predicates useful for type checking/promotion bool isPromotableIntegerType() const; // C99 6.3.1.1p2 /// Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// or an enum decl which has a signed representation. bool isSignedIntegerType() const; /// Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], /// or an enum decl which has an unsigned representation. bool isUnsignedIntegerType() const; /// Determines whether this is an integer type that is signed or an /// enumeration types whose underlying type is a signed integer type. bool isSignedIntegerOrEnumerationType() const; /// Determines whether this is an integer type that is unsigned or an /// enumeration types whose underlying type is a unsigned integer type. bool isUnsignedIntegerOrEnumerationType() const; /// Return true if this is a fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. bool isFixedPointType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isSaturatedFixedPointType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isUnsaturatedFixedPointType() const; /// Return true if this is a fixed point type that is signed according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isSignedFixedPointType() const; /// Return true if this is a fixed point type that is unsigned according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isUnsignedFixedPointType() const; /// Return true if this is not a variable sized type, /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. bool isConstantSizeType() const; /// Returns true if this type can be represented by some /// set of type specifiers. bool isSpecifierType() const; /// Determine the linkage of this type. Linkage getLinkage() const; /// Determine the visibility of this type. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); } /// Return true if the visibility was explicitly set is the code. bool isVisibilityExplicit() const { return getLinkageAndVisibility().isVisibilityExplicit(); } /// Determine the linkage and visibility of this type. LinkageInfo getLinkageAndVisibility() const; /// True if the computed linkage is valid. Used for consistency /// checking. Should always return true. bool isLinkageValid() const; /// Determine the nullability of the given type. /// /// Note that nullability is only captured as sugar within the type /// system, not as part of the canonical type, so nullability will /// be lost by canonicalization and desugaring. Optional getNullability(const ASTContext &context) const; /// Determine whether the given type can have a nullability /// specifier applied to it, i.e., if it is any kind of pointer type. /// /// \param ResultIfUnknown The value to return if we don't yet know whether /// this type can have nullability because it is dependent. bool canHaveNullability(bool ResultIfUnknown = true) const; /// Retrieve the set of substitutions required when accessing a member /// of the Objective-C receiver type that is declared in the given context. /// /// \c *this is the type of the object we're operating on, e.g., the /// receiver for a message send or the base of a property access, and is /// expected to be of some object or object pointer type. /// /// \param dc The declaration context for which we are building up a /// substitution mapping, which should be an Objective-C class, extension, /// category, or method within. /// /// \returns an array of type arguments that can be substituted for /// the type parameters of the given declaration context in any type described /// within that context, or an empty optional to indicate that no /// substitution is required. Optional> getObjCSubstitutions(const DeclContext *dc) const; /// Determines if this is an ObjC interface type that may accept type /// parameters. bool acceptsObjCTypeParams() const; const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { return CanonicalType; } CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; void dump(llvm::raw_ostream &OS) const; }; /// This will check for a TypedefType by removing any existing sugar /// until it reaches a TypedefType or a non-sugared type. template <> const TypedefType *Type::getAs() const; /// This will check for a TemplateSpecializationType by removing any /// existing sugar until it reaches a TemplateSpecializationType or a /// non-sugared type. template <> const TemplateSpecializationType *Type::getAs() const; /// This will check for an AttributedType by removing any existing sugar /// until it reaches an AttributedType or a non-sugared type. template <> const AttributedType *Type::getAs() const; // We can do canonical leaf types faster, because we don't have to // worry about preserving child type decoration. #define TYPE(Class, Base) #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ return dyn_cast(CanonicalType); \ } \ template <> inline const Class##Type *Type::castAs() const { \ return cast(CanonicalType); \ } #include "clang/AST/TypeNodes.def" /// This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { public: enum Kind { // OpenCL image types #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, #include "clang/Basic/OpenCLImageTypes.def" // OpenCL extension types #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, #include "clang/Basic/OpenCLExtensionTypes.def" // All other builtin types #define BUILTIN_TYPE(Id, SingletonId) Id, #define LAST_BUILTIN_TYPE(Id) LastKind = Id #include "clang/AST/BuiltinTypes.def" }; private: friend class ASTContext; // ASTContext creates these. BuiltinType(Kind K) : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), /*InstantiationDependent=*/(K == Dependent), /*VariablyModified=*/false, /*Unexpanded parameter pack=*/false) { BuiltinTypeBits.Kind = K; } public: Kind getKind() const { return static_cast(BuiltinTypeBits.Kind); } StringRef getName(const PrintingPolicy &Policy) const; const char *getNameAsCString(const PrintingPolicy &Policy) const { // The StringRef is null-terminated. StringRef str = getName(Policy); assert(!str.empty() && str.data()[str.size()] == '\0'); return str.data(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } bool isInteger() const { return getKind() >= Bool && getKind() <= Int128; } bool isSignedInteger() const { return getKind() >= Char_S && getKind() <= Int128; } bool isUnsignedInteger() const { return getKind() >= Bool && getKind() <= UInt128; } bool isFloatingPoint() const { return getKind() >= Half && getKind() <= Float128; } /// Determines whether the given kind corresponds to a placeholder type. static bool isPlaceholderTypeKind(Kind K) { return K >= Overload; } /// Determines whether this type is a placeholder type, i.e. a type /// which cannot appear in arbitrary positions in a fully-formed /// expression. bool isPlaceholderType() const { return isPlaceholderTypeKind(getKind()); } /// Determines whether this type is a placeholder type other than /// Overload. Most placeholder types require only syntactic /// information about their context in order to be resolved (e.g. /// whether it is a call expression), which means they can (and /// should) be resolved in an earlier "phase" of analysis. /// Overload expressions sometimes pick up further information /// from their context, like whether the context expects a /// specific function-pointer type, and so frequently need /// special treatment. bool isNonOverloadPlaceholderType() const { return getKind() > Overload; } static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } }; /// Complex values, per C99 6.2.5p11. This supports the C99 complex /// types (_Complex float etc) as well as the GCC integer complex extensions. class ComplexType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) : Type(Complex, CanonicalPtr, Element->isDependentType(), Element->isInstantiationDependentType(), Element->isVariablyModifiedType(), Element->containsUnexpandedParameterPack()), ElementType(Element) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { ID.AddPointer(Element.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Complex; } }; /// Sugar for parentheses used when specifying types. class ParenType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType Inner; ParenType(QualType InnerType, QualType CanonType) : Type(Paren, CanonType, InnerType->isDependentType(), InnerType->isInstantiationDependentType(), InnerType->isVariablyModifiedType(), InnerType->containsUnexpandedParameterPack()), Inner(InnerType) {} public: QualType getInnerType() const { return Inner; } bool isSugared() const { return true; } QualType desugar() const { return getInnerType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInnerType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { Inner.Profile(ID); } static bool classof(const Type *T) { return T->getTypeClass() == Paren; } }; /// PointerType - C99 6.7.5.1 - Pointer Declarators. class PointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr) : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if address spaces of pointers overlap. /// OpenCL v2.0 defines conversion rules for pointers to different /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping /// address spaces. /// CL1.1 or CL1.2: /// address spaces overlap iff they are they same. /// CL2.0 adds: /// __generic overlaps with any address space except for __constant. bool isAddressSpaceOverlapping(const PointerType &other) const { Qualifiers thisQuals = PointeeType.getQualifiers(); Qualifiers otherQuals = other.getPointeeType().getQualifiers(); // Address spaces overlap if at least one of them is a superset of another return thisQuals.isAddressSpaceSupersetOf(otherQuals) || otherQuals.isAddressSpaceSupersetOf(thisQuals); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } }; /// Represents a type which was implicitly adjusted by the semantic /// engine for arbitrary reasons. For example, array and function types can /// decay, and function types can have their calling conventions adjusted. class AdjustedType : public Type, public llvm::FoldingSetNode { QualType OriginalTy; QualType AdjustedTy; protected: friend class ASTContext; // ASTContext creates these. AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, QualType CanonicalPtr) : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), OriginalTy->isInstantiationDependentType(), OriginalTy->isVariablyModifiedType(), OriginalTy->containsUnexpandedParameterPack()), OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} public: QualType getOriginalType() const { return OriginalTy; } QualType getAdjustedType() const { return AdjustedTy; } bool isSugared() const { return true; } QualType desugar() const { return AdjustedTy; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, OriginalTy, AdjustedTy); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { ID.AddPointer(Orig.getAsOpaquePtr()); ID.AddPointer(New.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; } }; /// Represents a pointer type decayed from an array or function type. class DecayedType : public AdjustedType { friend class ASTContext; // ASTContext creates these. inline DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); public: QualType getDecayedType() const { return getAdjustedType(); } inline QualType getPointeeType() const; static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } }; /// Pointer to a block type. /// This type is to represent types syntactically represented as /// "void (^)(int)", etc. Pointee is required to always be a function type. class BlockPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. // Block is some kind of pointer type QualType PointeeType; BlockPointerType(QualType Pointee, QualType CanonicalCls) : Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: // Get the pointee type. Pointee is required to always be a function type. QualType getPointeeType() const { return PointeeType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == BlockPointer; } }; /// Base for LValueReferenceType and RValueReferenceType class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : Type(tc, CanonicalRef, Referencee->isDependentType(), Referencee->isInstantiationDependentType(), Referencee->isVariablyModifiedType(), Referencee->containsUnexpandedParameterPack()), PointeeType(Referencee) { ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } public: bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } QualType getPointeeTypeAsWritten() const { return PointeeType; } QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; while (T->isInnerRef()) T = T->PointeeType->castAs(); return T->PointeeType; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, PointeeType, isSpelledAsLValue()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, bool SpelledAsLValue) { ID.AddPointer(Referencee.getAsOpaquePtr()); ID.AddBoolean(SpelledAsLValue); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference || T->getTypeClass() == RValueReference; } }; /// An lvalue reference type, per C++11 [dcl.ref]. class LValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these LValueReferenceType(QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference; } }; /// An rvalue reference type, per C++11 [dcl.ref]. class RValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these RValueReferenceType(QualType Referencee, QualType CanonicalRef) : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == RValueReference; } }; /// A pointer to member type per C++ 8.3.3 - Pointers to members. /// /// This includes both pointers to data members and pointer to member functions. class MemberPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; /// The class of which the pointee is a member. Must ultimately be a /// RecordType, but could be a typedef or a template parameter too. const Type *Class; MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, Cls->isDependentType() || Pointee->isDependentType(), (Cls->isInstantiationDependentType() || Pointee->isInstantiationDependentType()), Pointee->isVariablyModifiedType(), (Cls->containsUnexpandedParameterPack() || Pointee->containsUnexpandedParameterPack())), PointeeType(Pointee), Class(Cls) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if the member type (i.e. the pointee type) is a /// function type rather than a data-member type. bool isMemberFunctionPointer() const { return PointeeType->isFunctionProtoType(); } /// Returns true if the member type (i.e. the pointee type) is a /// data type rather than a function type. bool isMemberDataPointer() const { return !PointeeType->isFunctionProtoType(); } const Type *getClass() const { return Class; } CXXRecordDecl *getMostRecentCXXRecordDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), getClass()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, const Type *Class) { ID.AddPointer(Pointee.getAsOpaquePtr()); ID.AddPointer(Class); } static bool classof(const Type *T) { return T->getTypeClass() == MemberPointer; } }; /// Represents an array type, per C99 6.7.5.2 - Array Declarators. class ArrayType : public Type, public llvm::FoldingSetNode { public: /// Capture whether this is a normal array (e.g. int X[4]) /// an array with a static size (e.g. int X[static 4]), or an array /// with a star size (e.g. int X[*]). /// 'static' is only allowed on function parameters. enum ArraySizeModifier { Normal, Static, Star }; private: /// The element type of the array. QualType ElementType; protected: friend class ASTContext; // ASTContext creates these. // C++ [temp.dep.type]p1: // A type is dependent if it is... // - an array type constructed from any dependent type or whose // size is specified by a constant expression that is // value-dependent, ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, bool ContainsUnexpandedParameterPack) : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, et->isInstantiationDependentType() || tc == DependentSizedArray, (tc == VariableArray || et->isVariablyModifiedType()), ContainsUnexpandedParameterPack), ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; } public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(ArrayTypeBits.SizeModifier); } Qualifiers getIndexTypeQualifiers() const { return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); } unsigned getIndexTypeCVRQualifiers() const { return ArrayTypeBits.IndexTypeQuals; } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || T->getTypeClass() == DependentSizedArray; } }; /// Represents the canonical version of C arrays with a specified constant size. /// For example, the canonical type for 'int A[4 + 4*100]' is a /// ConstantArrayType where the element type is 'int' and the size is 404. class ConstantArrayType : public ArrayType { llvm::APInt Size; // Allows us to unique the type. ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) : ArrayType(ConstantArray, et, can, sm, tq, et->containsUnexpandedParameterPack()), Size(size) {} protected: friend class ASTContext; // ASTContext creates these. ConstantArrayType(TypeClass tc, QualType et, QualType can, const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), Size(size) {} public: const llvm::APInt &getSize() const { return Size; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Determine the number of bits required to address a member of // an array with the given element type and number of elements. static unsigned getNumAddressingBits(const ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements); /// Determine the maximum number of active bits that an array's size /// can require, which limits the maximum size of the array. static unsigned getMaxSizeBits(const ASTContext &Context); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSize(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(ArraySize.getZExtValue()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray; } }; /// Represents a C array with an unspecified size. For example 'int A[]' has /// an IncompleteArrayType where the element type is 'int' and the size is /// unspecified. class IncompleteArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, unsigned tq) : ArrayType(IncompleteArray, et, can, sm, tq, et->containsUnexpandedParameterPack()) {} public: friend class StmtIteratorBase; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == IncompleteArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } }; /// Represents a C array with a specified size that is not an /// integer-constant-expression. For example, 'int s[x+foo()]'. /// Since the size expression is an arbitrary expression, we store it as such. /// /// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and /// should not be: two lexically equivalent variable array types could mean /// different things, for example, these variables do not have the same type /// dynamically: /// /// void foo(int x) { /// int Y[x]; /// ++x; /// int Z[x]; /// } class VariableArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. /// An assignment-expression. VLA's are only permitted within /// a function block. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) : ArrayType(VariableArray, et, can, sm, tq, et->containsUnexpandedParameterPack()), SizeExpr((Stmt*) e), Brackets(brackets) {} public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == VariableArray; } void Profile(llvm::FoldingSetNodeID &ID) { llvm_unreachable("Cannot unique VariableArrayTypes."); } }; /// Represents an array type in C++ whose size is a value-dependent expression. /// /// For example: /// \code /// template /// class array { /// T data[Size]; /// }; /// \endcode /// /// For these types, we won't actually know what the array bound is /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. const ASTContext &Context; /// An assignment expression that will instantiate to the /// size of the array. /// /// The expression itself might be null, in which case the array /// type will have its size deduced from an initializer. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets); public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E); }; /// Represents an extended address space qualifier where the input address space /// value is dependent. Non-dependent address spaces are not represented with a /// special Type subclass; they are stored on an ExtQuals node as part of a QualType. /// /// For example: /// \code /// template /// class AddressSpace { /// typedef T __attribute__((address_space(AddrSpace))) type; /// } /// \endcode class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *AddrSpaceExpr; QualType PointeeType; SourceLocation loc; DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, QualType can, Expr *AddrSpaceExpr, SourceLocation loc); public: Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } QualType getPointeeType() const { return PointeeType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentAddressSpace; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType PointeeType, Expr *AddrSpaceExpr); }; /// Represents an extended vector type where either the type or size is /// dependent. /// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((ext_vector_type(Size))) type; /// } /// \endcode class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *SizeExpr; /// The element type of the array. QualType ElementType; SourceLocation loc; DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, QualType can, Expr *SizeExpr, SourceLocation loc); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedExtVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, Expr *SizeExpr); }; /// Represents a GCC generic vector type. This type is created using /// __attribute__((vector_size(n)), where "n" specifies the vector size in /// bytes; or from an Altivec __vector or vector declaration. /// Since the constructor takes the number of vector elements, the /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { public: enum VectorKind { /// not a target-specific vector type GenericVector, /// is AltiVec vector AltiVecVector, /// is AltiVec 'vector Pixel' AltiVecPixel, /// is AltiVec 'vector bool ...' AltiVecBool, /// is ARM Neon vector NeonVector, /// is ARM Neon polynomial vector NeonPolyVector }; protected: friend class ASTContext; // ASTContext creates these. /// The element type of the vector. QualType ElementType; VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); public: QualType getElementType() const { return ElementType; } unsigned getNumElements() const { return VectorTypeBits.NumElements; } static bool isVectorSizeTooLarge(unsigned NumElements) { return NumElements > VectorTypeBitfields::MaxNumElements; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } VectorKind getVectorKind() const { return VectorKind(VectorTypeBits.VecKind); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass, VectorKind VecKind) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); ID.AddInteger(VecKind); } static bool classof(const Type *T) { return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } }; /// Represents a vector type where either the type or size is dependent. //// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((vector_size(Size))) type; /// } /// \endcode class DependentVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; QualType ElementType; Expr *SizeExpr; SourceLocation Loc; DependentVectorType(const ASTContext &Context, QualType ElementType, QualType CanonType, Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind vecKind); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return Loc; } VectorType::VectorKind getVectorKind() const { return VectorType::VectorKind(VectorTypeBits.VecKind); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, const Expr *SizeExpr, VectorType::VectorKind VecKind); }; /// ExtVectorType - Extended vector type. This type is created using /// __attribute__((ext_vector_type(n)), where "n" is the number of elements. /// Unlike vector_size, ext_vector_type is only allowed on typedef's. This /// class enables syntactic extensions, like Vector Components for accessing /// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL /// Shading Language). class ExtVectorType : public VectorType { friend class ASTContext; // ASTContext creates these. ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} public: static int getPointAccessorIdx(char c) { switch (c) { default: return -1; case 'x': case 'r': return 0; case 'y': case 'g': return 1; case 'z': case 'b': return 2; case 'w': case 'a': return 3; } } static int getNumericAccessorIdx(char c) { switch (c) { default: return -1; case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } } static int getAccessorIdx(char c, bool isNumericAccessor) { if (isNumericAccessor) return getNumericAccessorIdx(c); else return getPointAccessorIdx(c); } bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const { if (int idx = getAccessorIdx(c, isNumericAccessor)+1) return unsigned(idx-1) < getNumElements(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ExtVector; } }; /// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base /// class of FunctionNoProtoType and FunctionProtoType. class FunctionType : public Type { // The type returned by the function. QualType ResultType; public: /// Interesting information about a specific parameter that can't simply /// be reflected in parameter's type. This is only used by FunctionProtoType /// but is in FunctionType to make this class available during the /// specification of the bases of FunctionProtoType. /// /// It makes sense to model language features this way when there's some /// sort of parameter-specific override (such as an attribute) that /// affects how the function is called. For example, the ARC ns_consumed /// attribute changes whether a parameter is passed at +0 (the default) /// or +1 (ns_consumed). This must be reflected in the function type, /// but isn't really a change to the parameter type. /// /// One serious disadvantage of modelling language features this way is /// that they generally do not work with language features that attempt /// to destructure types. For example, template argument deduction will /// not be able to match a parameter declared as /// T (*)(U) /// against an argument of type /// void (*)(__attribute__((ns_consumed)) id) /// because the substitution of T=void, U=id into the former will /// not produce the latter. class ExtParameterInfo { enum { ABIMask = 0x0F, IsConsumed = 0x10, HasPassObjSize = 0x20, IsNoEscape = 0x40, }; unsigned char Data = 0; public: ExtParameterInfo() = default; /// Return the ABI treatment of this parameter. ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } ExtParameterInfo withABI(ParameterABI kind) const { ExtParameterInfo copy = *this; copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); return copy; } /// Is this parameter considered "consumed" by Objective-C ARC? /// Consumed parameters must have retainable object type. bool isConsumed() const { return (Data & IsConsumed); } ExtParameterInfo withIsConsumed(bool consumed) const { ExtParameterInfo copy = *this; if (consumed) copy.Data |= IsConsumed; else copy.Data &= ~IsConsumed; return copy; } bool hasPassObjectSize() const { return Data & HasPassObjSize; } ExtParameterInfo withHasPassObjectSize() const { ExtParameterInfo Copy = *this; Copy.Data |= HasPassObjSize; return Copy; } bool isNoEscape() const { return Data & IsNoEscape; } ExtParameterInfo withIsNoEscape(bool NoEscape) const { ExtParameterInfo Copy = *this; if (NoEscape) Copy.Data |= IsNoEscape; else Copy.Data &= ~IsNoEscape; return Copy; } unsigned char getOpaqueValue() const { return Data; } static ExtParameterInfo getFromOpaqueValue(unsigned char data) { ExtParameterInfo result; result.Data = data; return result; } friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data == rhs.Data; } friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data != rhs.Data; } }; /// A class which abstracts out some details necessary for /// making a call. /// /// It is not actually used directly for storing this information in /// a FunctionType, although FunctionType does currently use the /// same bit-pattern. /// // If you add a field (say Foo), other than the obvious places (both, // constructors, compile failures), what you need to update is // * Operator== // * getFoo // * withFoo // * functionType. Add Foo, getFoo. // * ASTContext::getFooType // * ASTContext::mergeFunctionTypes // * FunctionNoProtoType::Profile // * FunctionProtoType::Profile // * TypePrinter::PrintFunctionProto // * AST read and write // * Codegen class ExtInfo { friend class FunctionType; // Feel free to rearrange or add bits, but if you go over 12, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck| // |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 | // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; enum { NoCallerSavedRegsMask = 0x80 }; enum { NoCfCheckMask = 0x800 }; enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | NoCallerSavedRegsMask | NoCfCheckMask), RegParmOffset = 8 }; // Assumed to be the last field uint16_t Bits = CC_C; ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs, bool NoCfCheck) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | (producesResult ? ProducesResultMask : 0) | (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | (NoCfCheck ? NoCfCheckMask : 0); } // Constructor with all defaults. Use when for example creating a // function known to use defaults. ExtInfo() = default; // Constructor with just the calling convention, which is an important part // of the canonical type. ExtInfo(CallingConv CC) : Bits(CC) {} bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getNoCfCheck() const { return Bits & NoCfCheckMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset; if (RegParm > 0) --RegParm; return RegParm; } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } bool operator==(ExtInfo Other) const { return Bits == Other.Bits; } bool operator!=(ExtInfo Other) const { return Bits != Other.Bits; } // Note that we don't have setters. That is by design, use // the following with methods instead of mutating these objects. ExtInfo withNoReturn(bool noReturn) const { if (noReturn) return ExtInfo(Bits | NoReturnMask); else return ExtInfo(Bits & ~NoReturnMask); } ExtInfo withProducesResult(bool producesResult) const { if (producesResult) return ExtInfo(Bits | ProducesResultMask); else return ExtInfo(Bits & ~ProducesResultMask); } ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { if (noCallerSavedRegs) return ExtInfo(Bits | NoCallerSavedRegsMask); else return ExtInfo(Bits & ~NoCallerSavedRegsMask); } ExtInfo withNoCfCheck(bool noCfCheck) const { if (noCfCheck) return ExtInfo(Bits | NoCfCheckMask); else return ExtInfo(Bits & ~NoCfCheckMask); } ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | ((RegParm + 1) << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } }; /// A simple holder for a QualType representing a type in an /// exception specification. Unfortunately needed by FunctionProtoType /// because TrailingObjects cannot handle repeated types. struct ExceptionType { QualType Type; }; /// A simple holder for various uncommon bits which do not fit in /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the /// alignment of subsequent objects in TrailingObjects. You must update /// hasExtraBitfields in FunctionProtoType after adding extra data here. struct alignas(void *) FunctionTypeExtraBitfields { /// The number of types in the exception specification. /// A whole unsigned is not needed here and according to /// [implimits] 8 bits would be enough here. unsigned NumExceptionType; }; protected: FunctionType(TypeClass tc, QualType res, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; } Qualifiers getFastTypeQuals() const { return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); } public: QualType getReturnType() const { return ResultType; } bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } /// Determine whether this function type includes the GNU noreturn /// attribute. The C++11 [[noreturn]] attribute does not affect the function /// type. bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, "Const, volatile and restrict are assumed to be a subset of " "the fast qualifiers."); bool isConst() const { return getFastTypeQuals().hasConst(); } bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } /// Determine the type of an expression that calls a function of /// this type. QualType getCallResultType(const ASTContext &Context) const { return getReturnType().getNonLValueExprType(Context); } static StringRef getNameForCallConv(CallingConv CC); static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; } }; /// Represents a K&R-style 'int foo()' function, which has /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) : FunctionType(FunctionNoProto, Result, Canonical, /*Dependent=*/false, /*InstantiationDependent=*/false, Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} public: // No additional state past what FunctionType provides. bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReturnType(), getExtInfo()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, ExtInfo Info) { Info.Profile(ID); ID.AddPointer(ResultType.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } }; /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no /// parameters, not as having a single void parameter. Such a type can have /// an exception specification, but this specification is not part of the /// canonical type. FunctionProtoType has several trailing objects, some of /// which optional. For more information about the trailing objects see /// the first comment inside FunctionProtoType. class FunctionProtoType final : public FunctionType, public llvm::FoldingSetNode, private llvm::TrailingObjects< FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; // FunctionProtoType is followed by several trailing objects, some of // which optional. They are in order: // // * An array of getNumParams() QualType holding the parameter types. // Always present. Note that for the vast majority of FunctionProtoType, // these will be the only trailing objects. // // * Optionally if some extra data is stored in FunctionTypeExtraBitfields // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): // a single FunctionTypeExtraBitfields. Present if and only if // hasExtraBitfields() is true. // // * Optionally exactly one of: // * an array of getNumExceptions() ExceptionType, // * a single Expr *, // * a pair of FunctionDecl *, // * a single FunctionDecl * // used to store information about the various types of exception // specification. See getExceptionSpecSize for the details. // // * Optionally an array of getNumParams() ExtParameterInfo holding // an ExtParameterInfo for each of the parameters. Present if and // only if hasExtParameterInfos() is true. // // * Optionally a Qualifiers object to represent extra qualifiers that can't // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only // if hasExtQualifiers() is true. // // The optional FunctionTypeExtraBitfields has to be before the data // related to the exception specification since it contains the number // of exception types. // // We put the ExtParameterInfos last. If all were equal, it would make // more sense to put these before the exception specification, because // it's much easier to skip past them compared to the elaborate switch // required to skip the exception specification. However, all is not // equal; ExtParameterInfos are used to model very uncommon features, // and it's better not to burden the more common paths. public: /// Holds information about the various types of exception specification. /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is /// used to group together the various bits of information about the /// exception specification. struct ExceptionSpecInfo { /// The kind of exception specification this is. ExceptionSpecificationType Type = EST_None; /// Explicitly-specified list of exception types. ArrayRef Exceptions; /// Noexcept expression, if this is a computed noexcept specification. Expr *NoexceptExpr = nullptr; /// The function whose exception specification this is, for /// EST_Unevaluated and EST_Uninstantiated. FunctionDecl *SourceDecl = nullptr; /// The function template whose exception specification this is instantiated /// from, for EST_Uninstantiated. FunctionDecl *SourceTemplate = nullptr; ExceptionSpecInfo() = default; ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; /// Extra information about a function prototype. ExtProtoInfo is not /// stored as such in FunctionProtoType but is used to group together /// the various bits of extra information about a function prototype. struct ExtProtoInfo { FunctionType::ExtInfo ExtInfo; bool Variadic : 1; bool HasTrailingReturn : 1; Qualifiers TypeQuals; RefQualifierKind RefQualifier = RQ_None; ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { ExtProtoInfo Result(*this); Result.ExceptionSpec = ESI; return Result; } }; private: unsigned numTrailingObjects(OverloadToken) const { return getNumParams(); } unsigned numTrailingObjects(OverloadToken) const { return hasExtraBitfields(); } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExceptionType; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExprPtr; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumFunctionDeclPtr; } unsigned numTrailingObjects(OverloadToken) const { return hasExtParameterInfos() ? getNumParams() : 0; } /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, unsigned numArgs) { for (unsigned Idx = 0; Idx < numArgs; ++Idx) if (ArgArray[Idx]->containsUnexpandedParameterPack()) return true; return false; } FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi); /// This struct is returned by getExceptionSpecSize and is used to /// translate an ExceptionSpecificationType to the number and kind /// of trailing objects related to the exception specification. struct ExceptionSpecSizeHolder { unsigned NumExceptionType; unsigned NumExprPtr; unsigned NumFunctionDeclPtr; }; /// Return the number and kind of trailing objects /// related to the exception specification. static ExceptionSpecSizeHolder getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { switch (EST) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_Unparsed: return {0, 0, 0}; case EST_Dynamic: return {NumExceptions, 0, 0}; case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: return {0, 1, 0}; case EST_Uninstantiated: return {0, 0, 2}; case EST_Unevaluated: return {0, 0, 1}; } llvm_unreachable("bad exception specification kind"); } /// Return the number and kind of trailing objects /// related to the exception specification. ExceptionSpecSizeHolder getExceptionSpecSize() const { return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); } /// Whether the trailing FunctionTypeExtraBitfields is present. static bool hasExtraBitfields(ExceptionSpecificationType EST) { // If the exception spec type is EST_Dynamic then we have > 0 exception // types and the exact number is stored in FunctionTypeExtraBitfields. return EST == EST_Dynamic; } /// Whether the trailing FunctionTypeExtraBitfields is present. bool hasExtraBitfields() const { return hasExtraBitfields(getExceptionSpecType()); } bool hasExtQualifiers() const { return FunctionTypeBits.HasExtQuals; } public: unsigned getNumParams() const { return FunctionTypeBits.NumParams; } QualType getParamType(unsigned i) const { assert(i < getNumParams() && "invalid parameter index"); return param_type_begin()[i]; } ArrayRef getParamTypes() const { return llvm::makeArrayRef(param_type_begin(), param_type_end()); } ExtProtoInfo getExtProtoInfo() const { ExtProtoInfo EPI; EPI.ExtInfo = getExtInfo(); EPI.Variadic = isVariadic(); EPI.HasTrailingReturn = hasTrailingReturn(); EPI.ExceptionSpec.Type = getExceptionSpecType(); EPI.TypeQuals = getTypeQuals(); EPI.RefQualifier = getRefQualifier(); if (EPI.ExceptionSpec.Type == EST_Dynamic) { EPI.ExceptionSpec.Exceptions = exceptions(); } else if (isComputedNoexcept(EPI.ExceptionSpec.Type)) { EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr(); } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate(); } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } EPI.ExtParameterInfos = getExtParameterInfosOrNull(); return EPI; } /// Get the kind of exception specification on this function. ExceptionSpecificationType getExceptionSpecType() const { return static_cast( FunctionTypeBits.ExceptionSpecType); } /// Return whether this function has any kind of exception spec. bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { return isDynamicExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a noexcept exception spec. bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a dependent exception spec. bool hasDependentExceptionSpec() const; /// Return whether this function has an instantiation-dependent exception /// spec. bool hasInstantiationDependentExceptionSpec() const; /// Return the number of types in the exception specification. unsigned getNumExceptions() const { return getExceptionSpecType() == EST_Dynamic ? getTrailingObjects() ->NumExceptionType : 0; } /// Return the ith exception type, where 0 <= i < getNumExceptions(). QualType getExceptionType(unsigned i) const { assert(i < getNumExceptions() && "Invalid exception number!"); return exception_begin()[i]; } /// Return the expression inside noexcept(expression), or a null pointer /// if there is none (because the exception spec is not of this form). Expr *getNoexceptExpr() const { if (!isComputedNoexcept(getExceptionSpecType())) return nullptr; return *getTrailingObjects(); } /// If this function type has an exception specification which hasn't /// been determined yet (either because it has not been evaluated or because /// it has not been instantiated), this is the function whose exception /// specification is represented by this type. FunctionDecl *getExceptionSpecDecl() const { if (getExceptionSpecType() != EST_Uninstantiated && getExceptionSpecType() != EST_Unevaluated) return nullptr; return getTrailingObjects()[0]; } /// If this function type has an uninstantiated exception /// specification, this is the function whose exception specification /// should be instantiated to find the exception specification for /// this type. FunctionDecl *getExceptionSpecTemplate() const { if (getExceptionSpecType() != EST_Uninstantiated) return nullptr; return getTrailingObjects()[1]; } /// Determine whether this function type has a non-throwing exception /// specification. CanThrowResult canThrow() const; /// Determine whether this function type has a non-throwing exception /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. bool isNothrow(bool ResultIfDependent = false) const { return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; } /// Whether this function prototype is variadic. bool isVariadic() const { return FunctionTypeBits.Variadic; } /// Determines whether this function prototype contains a /// parameter pack at the end. /// /// A function template whose last parameter is a parameter pack can be /// called with an arbitrary number of arguments, much like a variadic /// function. bool isTemplateVariadic() const; /// Whether this function prototype has a trailing return type. bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } Qualifiers getTypeQuals() const { if (hasExtQualifiers()) return *getTrailingObjects(); else return getFastTypeQuals(); } /// Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { return static_cast(FunctionTypeBits.RefQualifier); } using param_type_iterator = const QualType *; using param_type_range = llvm::iterator_range; param_type_range param_types() const { return param_type_range(param_type_begin(), param_type_end()); } param_type_iterator param_type_begin() const { return getTrailingObjects(); } param_type_iterator param_type_end() const { return param_type_begin() + getNumParams(); } using exception_iterator = const QualType *; ArrayRef exceptions() const { return llvm::makeArrayRef(exception_begin(), exception_end()); } exception_iterator exception_begin() const { return reinterpret_cast( getTrailingObjects()); } exception_iterator exception_end() const { return exception_begin() + getNumExceptions(); } /// Is there any interesting extra information for any of the parameters /// of this function type? bool hasExtParameterInfos() const { return FunctionTypeBits.HasExtParameterInfos; } ArrayRef getExtParameterInfos() const { assert(hasExtParameterInfos()); return ArrayRef(getTrailingObjects(), getNumParams()); } /// Return a pointer to the beginning of the array of extra parameter /// information, if present, or else null if none of the parameters /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. const ExtParameterInfo *getExtParameterInfosOrNull() const { if (!hasExtParameterInfos()) return nullptr; return getTrailingObjects(); } ExtParameterInfo getExtParameterInfo(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I]; return ExtParameterInfo(); } ParameterABI getParameterABI(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].getABI(); return ParameterABI::Ordinary; } bool isParamConsumed(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].isConsumed(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void printExceptionSpecification(raw_ostream &OS, const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, param_type_iterator ArgTys, unsigned NumArgs, const ExtProtoInfo &EPI, const ASTContext &Context, bool Canonical); }; /// Represents the dependent type named by a dependently-scoped /// typename using declaration, e.g. /// using typename Base::foo; /// /// Template instantiation turns these into the underlying type. class UnresolvedUsingType : public Type { friend class ASTContext; // ASTContext creates these. UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) : Type(UnresolvedUsing, QualType(), true, true, false, /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) {} public: UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == UnresolvedUsing; } void Profile(llvm::FoldingSetNodeID &ID) { return Profile(ID, Decl); } static void Profile(llvm::FoldingSetNodeID &ID, UnresolvedUsingTypenameDecl *D) { ID.AddPointer(D); } }; class TypedefType : public Type { TypedefNameDecl *Decl; protected: friend class ASTContext; // ASTContext creates these. TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) : Type(tc, can, can->isDependentType(), can->isInstantiationDependentType(), can->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } public: TypedefNameDecl *getDecl() const { return Decl; } bool isSugared() const { return true; } QualType desugar() const; static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } }; /// Represents a `typeof` (or __typeof__) expression (a GCC extension). class TypeOfExprType : public Type { Expr *TOExpr; protected: friend class ASTContext; // ASTContext creates these. TypeOfExprType(Expr *E, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return TOExpr; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } }; /// Internal representation of canonical, dependent /// `typeof(expr)` types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via TypeOfExprType nodes. class DependentTypeOfExprType : public TypeOfExprType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentTypeOfExprType(const ASTContext &Context, Expr *E) : TypeOfExprType(E), Context(Context) {} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// Represents `typeof(type)`, a GCC extension. class TypeOfType : public Type { friend class ASTContext; // ASTContext creates these. QualType TOType; TypeOfType(QualType T, QualType can) : Type(TypeOf, can, T->isDependentType(), T->isInstantiationDependentType(), T->isVariablyModifiedType(), T->containsUnexpandedParameterPack()), TOType(T) { assert(!isa(can) && "Invalid canonical type"); } public: QualType getUnderlyingType() const { return TOType; } /// Remove a single level of sugar. QualType desugar() const { return getUnderlyingType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } }; /// Represents the type `decltype(expr)` (C++11). class DecltypeType : public Type { Expr *E; QualType UnderlyingType; protected: friend class ASTContext; // ASTContext creates these. DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return E; } QualType getUnderlyingType() const { return UnderlyingType; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } }; /// Internal representation of canonical, dependent /// decltype(expr) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentDecltypeType(const ASTContext &Context, Expr *E); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// A unary type transform, which is a type constructed from another. class UnaryTransformType : public Type { public: enum UTTKind { EnumUnderlyingType }; private: /// The untransformed type. QualType BaseType; /// The transformed type if not dependent, otherwise the same as BaseType. QualType UnderlyingType; UTTKind UKind; protected: friend class ASTContext; UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, QualType CanonicalTy); public: bool isSugared() const { return !isDependentType(); } QualType desugar() const { return UnderlyingType; } QualType getUnderlyingType() const { return UnderlyingType; } QualType getBaseType() const { return BaseType; } UTTKind getUTTKind() const { return UKind; } static bool classof(const Type *T) { return T->getTypeClass() == UnaryTransform; } }; /// Internal representation of canonical, dependent /// __underlying_type(type) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via UnaryTransformType nodes. class DependentUnaryTransformType : public UnaryTransformType, public llvm::FoldingSetNode { public: DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), getUTTKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, UTTKind UKind) { ID.AddPointer(BaseType.getAsOpaquePtr()); ID.AddInteger((unsigned)UKind); } }; class TagType : public Type { friend class ASTReader; /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. TagDecl *decl; protected: TagType(TypeClass TC, const TagDecl *D, QualType can); public: TagDecl *getDecl() const; /// Determines whether this type is in the process of being defined. bool isBeingDefined() const; static bool classof(const Type *T) { return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of structs/unions/classes. class RecordType : public TagType { protected: friend class ASTContext; // ASTContext creates these. explicit RecordType(const RecordDecl *D) : TagType(Record, reinterpret_cast(D), QualType()) {} explicit RecordType(TypeClass TC, RecordDecl *D) : TagType(TC, reinterpret_cast(D), QualType()) {} public: RecordDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } /// Recursively check all fields in the record for const-ness. If any field /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Record; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. class EnumType : public TagType { friend class ASTContext; // ASTContext creates these. explicit EnumType(const EnumDecl *D) : TagType(Enum, reinterpret_cast(D), QualType()) {} public: EnumDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Enum; } }; /// An attributed type is a type to which a type attribute has been applied. /// /// The "modified type" is the fully-sugared type to which the attributed /// type was applied; generally it is not canonically equivalent to the /// attributed type. The "equivalent type" is the minimally-desugared type /// which the type is canonically equivalent to. /// /// For example, in the following attributed type: /// int32_t __attribute__((vector_size(16))) /// - the modified type is the TypedefType for int32_t /// - the equivalent type is VectorType(16, int32_t) /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: using Kind = attr::Kind; private: friend class ASTContext; // ASTContext creates these QualType ModifiedType; QualType EquivalentType; AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), equivalent->isVariablyModifiedType(), equivalent->containsUnexpandedParameterPack()), ModifiedType(modified), EquivalentType(equivalent) { AttributedTypeBits.AttrKind = attrKind; } public: Kind getAttrKind() const { return static_cast(AttributedTypeBits.AttrKind); } QualType getModifiedType() const { return ModifiedType; } QualType getEquivalentType() const { return EquivalentType; } bool isSugared() const { return true; } QualType desugar() const { return getEquivalentType(); } /// Does this attribute behave like a type qualifier? /// /// A type qualifier adjusts a type to provide specialized rules for /// a specific object, like the standard const and volatile qualifiers. /// This includes attributes controlling things like nullability, /// address spaces, and ARC ownership. The value of the object is still /// largely described by the modified type. /// /// In contrast, many type attributes "rewrite" their modified type to /// produce a fundamentally different type, not necessarily related in any /// formalizable way to the original type. For example, calling convention /// and vector attributes are not simple type qualifiers. /// /// Type qualifiers are often, but not always, reflected in the canonical /// type. bool isQualifier() const; bool isMSTypeSpec() const; bool isCallingConv() const; llvm::Optional getImmediateNullability() const; /// Retrieve the attribute kind corresponding to the given /// nullability kind. static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: return attr::TypeNonNull; case NullabilityKind::Nullable: return attr::TypeNullable; case NullabilityKind::Unspecified: return attr::TypeNullUnspecified; } llvm_unreachable("Unknown nullability kind."); } /// Strip off the top-level nullability annotation on the given /// type, if it's there. /// /// \param T The type to strip. If the type is exactly an /// AttributedType specifying nullability (without looking through /// type sugar), the nullability is returned and this type changed /// to the underlying modified type. /// /// \returns the top-level nullability, if present. static Optional stripOuterNullability(QualType &T); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAttrKind(), ModifiedType, EquivalentType); } static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, QualType modified, QualType equivalent) { ID.AddInteger(attrKind); ID.AddPointer(modified.getAsOpaquePtr()); ID.AddPointer(equivalent.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Attributed; } }; class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these // Helper data collector for canonical types. struct CanonicalTTPTInfo { unsigned Depth : 15; unsigned ParameterPack : 1; unsigned Index : 16; }; union { // Info for the canonical type. CanonicalTTPTInfo CanTTPTInfo; // Info for the non-canonical type. TemplateTypeParmDecl *TTPDecl; }; /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) : Type(TemplateTypeParm, Canon, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, Canon->containsUnexpandedParameterPack()), TTPDecl(TTPDecl) {} /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, PP) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; CanTTPTInfo.ParameterPack = PP; } const CanonicalTTPTInfo& getCanTTPTInfo() const { QualType Can = getCanonicalTypeInternal(); return Can->castAs()->CanTTPTInfo; } public: unsigned getDepth() const { return getCanTTPTInfo().Depth; } unsigned getIndex() const { return getCanTTPTInfo().Index; } bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; } TemplateTypeParmDecl *getDecl() const { return isCanonicalUnqualified() ? nullptr : TTPDecl; } IdentifierInfo *getIdentifier() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, unsigned Index, bool ParameterPack, TemplateTypeParmDecl *TTPDecl) { ID.AddInteger(Depth); ID.AddInteger(Index); ID.AddBoolean(ParameterPack); ID.AddPointer(TTPDecl); } static bool classof(const Type *T) { return T->getTypeClass() == TemplateTypeParm; } }; /// Represents the result of substituting a type for a template /// type parameter. /// /// Within an instantiated template, all template type parameters have /// been replaced with these. They are used solely to record that a /// type was originally written as a template type parameter; /// therefore they are never canonical. class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // The original type parameter. const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), Canon->isInstantiationDependentType(), Canon->isVariablyModifiedType(), Canon->containsUnexpandedParameterPack()), Replaced(Param) {} public: /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } /// Gets the type that was substituted for the template /// parameter. QualType getReplacementType() const { return getCanonicalTypeInternal(); } bool isSugared() const { return true; } QualType desugar() const { return getReplacementType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacedParameter(), getReplacementType()); } static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, QualType Replacement) { ID.AddPointer(Replaced); ID.AddPointer(Replacement.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParm; } }; /// Represents the result of substituting a set of types for a template /// type parameter pack. /// /// When a pack expansion in the source code contains multiple parameter packs /// and those parameter packs correspond to different levels of template /// parameter lists, this type node is used to represent a template type /// parameter pack from an outer level, which has already had its argument pack /// substituted but that still lives within a pack expansion that itself /// could not be instantiated. When actually performing a substitution into /// that pack expansion (e.g., when all template parameters have corresponding /// arguments), this type will be replaced with the \c SubstTemplateTypeParmType /// at the current pack substitution index. class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { friend class ASTContext; /// The original type parameter. const TemplateTypeParmType *Replaced; /// A pointer to the set of template arguments that this /// parameter pack is instantiated with. const TemplateArgument *Arguments; SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack); public: IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } TemplateArgument getArgumentPack() const; void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, const TemplateArgument &ArgPack); static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParmPack; } }; /// Common base class for placeholders for types that get replaced by /// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced /// class template types, and (eventually) constrained type names from the C++ /// Concepts TS. /// /// These types are usually a placeholder for a deduced type. However, before /// the initializer is attached, or (usually) if the initializer is /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { protected: DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent, bool IsInstantiationDependent, bool ContainsParameterPack) : Type(TC, // FIXME: Retain the sugared deduced type? DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType.getCanonicalType(), IsDependent, IsInstantiationDependent, /*VariablyModified=*/false, ContainsParameterPack) { if (!DeducedAsType.isNull()) { if (DeducedAsType->isDependentType()) setDependent(); if (DeducedAsType->isInstantiationDependentType()) setInstantiationDependent(); if (DeducedAsType->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); } } public: bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } /// Get the type deduced for this placeholder type, or null if it's /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); } bool isDeduced() const { return !isCanonicalUnqualified() || isDependentType(); } static bool classof(const Type *T) { return T->getTypeClass() == Auto || T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a C++11 auto or C++14 decltype(auto) type. class AutoType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, bool IsDeducedAsDependent) : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, IsDeducedAsDependent, /*ContainsPack=*/false) { AutoTypeBits.Keyword = (unsigned)Keyword; } public: bool isDecltypeAuto() const { return getKeyword() == AutoTypeKeyword::DecltypeAuto; } AutoTypeKeyword getKeyword() const { return (AutoTypeKeyword)AutoTypeBits.Keyword; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDeducedType(), getKeyword(), isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, AutoTypeKeyword Keyword, bool IsDependent) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); } static bool classof(const Type *T) { return T->getTypeClass() == Auto; } }; /// Represents a C++17 deduced template specialization type. class DeducedTemplateSpecializationType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template whose arguments will be deduced. TemplateName Template; DeducedTemplateSpecializationType(TemplateName Template, QualType DeducedAsType, bool IsDeducedAsDependent) : DeducedType(DeducedTemplateSpecialization, DeducedAsType, IsDeducedAsDependent || Template.isDependent(), IsDeducedAsDependent || Template.isInstantiationDependent(), Template.containsUnexpandedParameterPack()), Template(Template) {} public: /// Retrieve the name of the template that we are deducing. TemplateName getTemplateName() const { return Template;} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getTemplateName(), getDeducedType(), isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, QualType Deduced, bool IsDependent) { Template.Profile(ID); ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddBoolean(IsDependent); } static bool classof(const Type *T) { return T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a type template specialization; the template /// must be a class template, a type alias template, or a template /// template parameter. A template which cannot be resolved to one of /// these, e.g. because it is written with a dependent scope /// specifier, is instead represented as a /// @c DependentTemplateSpecializationType. /// /// A non-dependent template specialization type is always "sugar", /// typically for a \c RecordType. For example, a class template /// specialization type of \c vector will refer to a tag type for /// the instantiation \c std::vector> /// /// Template specializations are dependent if either the template or /// any of the template arguments are dependent, in which case the /// type may also be canonical. /// /// Instances of this type are allocated with a trailing array of /// TemplateArguments, followed by a QualType representing the /// non-canonical aliased type when the template is a type alias /// template. class alignas(8) TemplateSpecializationType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a /// TypeAliasTemplateDecl*), a /// TemplateName::SubstTemplateTemplateParmPack, or a /// TemplateName::SubstTemplateTemplateParm (in which case the /// replacement must, recursively, be one of these). TemplateName Template; TemplateSpecializationType(TemplateName T, ArrayRef Args, QualType Canon, QualType Aliased); public: /// Determine whether any of the given template arguments are dependent. static bool anyDependentTemplateArguments(ArrayRef Args, bool &InstantiationDependent); static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, bool &InstantiationDependent); /// True if this template specialization type matches a current /// instantiation in the context in which it is found. bool isCurrentInstantiation() const { return isa(getCanonicalTypeInternal()); } /// Determine if this template specialization type is for a type alias /// template that has been substituted. /// /// Nearly every template specialization type whose template is an alias /// template will be substituted. However, this is not the case when /// the specialization contains a pack expansion but the template alias /// does not have a corresponding parameter pack, e.g., /// /// \code /// template struct S; /// template using A = S; /// template struct X { /// typedef A type; // not a type alias /// }; /// \endcode bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } /// Get the aliased type, if this is a specialization of a type alias /// template. QualType getAliasedType() const { assert(isTypeAlias() && "not a type alias template specialization"); return *reinterpret_cast(end()); } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // defined inline in TemplateBase.h /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return reinterpret_cast(this + 1); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return TemplateSpecializationTypeBits.NumArgs; } /// Retrieve a specific template argument as a type. /// \pre \c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } QualType desugar() const { return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, template_arguments(), Ctx); if (isTypeAlias()) getAliasedType().Profile(ID); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, ArrayRef Args, const ASTContext &Context); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; } }; /// Print a template argument list, including the '<' and '>' /// enclosing the template arguments. void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, const TemplateArgumentListInfo &Args, const PrintingPolicy &Policy); /// The injected class name of a C++ class template or class /// template partial specialization. Used to record that a type was /// spelled with a bare identifier rather than as a template-id; the /// equivalent for non-templated classes is just RecordType. /// /// Injected class name types are always dependent. Template /// instantiation turns these into RecordTypes. /// /// Injected class name types are always canonical. This works /// because it is impossible to compare an injected class name type /// with the corresponding non-injected template type, for the same /// reason that it is impossible to directly compare template /// parameters from different dependent contexts: injected class name /// types can only occur within the scope of a particular templated /// declaration, and within that scope every template specialization /// will canonicalize to the injected class name (when appropriate /// according to the rules of the language). class InjectedClassNameType : public Type { friend class ASTContext; // ASTContext creates these. friend class ASTNodeImporter; friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not // currently suitable for AST reading, too much // interdependencies. CXXRecordDecl *Decl; /// The template specialization which this type represents. /// For example, in /// template class A { ... }; /// this is A, whereas in /// template class A > { ... }; /// this is A >. /// /// It is always unqualified, always a template specialization type, /// and always dependent. QualType InjectedType; InjectedClassNameType(CXXRecordDecl *D, QualType TST) : Type(InjectedClassName, QualType(), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, /*ContainsUnexpandedParameterPack=*/false), Decl(D), InjectedType(TST) { assert(isa(TST)); assert(!TST.hasQualifiers()); assert(TST->isDependentType()); } public: QualType getInjectedSpecializationType() const { return InjectedType; } const TemplateSpecializationType *getInjectedTST() const { return cast(InjectedType.getTypePtr()); } TemplateName getTemplateName() const { return getInjectedTST()->getTemplateName(); } CXXRecordDecl *getDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == InjectedClassName; } }; /// The kind of a tag type. enum TagTypeKind { /// The "struct" keyword. TTK_Struct, /// The "__interface" keyword. TTK_Interface, /// The "union" keyword. TTK_Union, /// The "class" keyword. TTK_Class, /// The "enum" keyword. TTK_Enum }; /// The elaboration keyword that precedes a qualified type name or /// introduces an elaborated-type-specifier. enum ElaboratedTypeKeyword { /// The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, /// The "__interface" keyword introduces the elaborated-type-specifier. ETK_Interface, /// The "union" keyword introduces the elaborated-type-specifier. ETK_Union, /// The "class" keyword introduces the elaborated-type-specifier. ETK_Class, /// The "enum" keyword introduces the elaborated-type-specifier. ETK_Enum, /// The "typename" keyword precedes the qualified type name, e.g., /// \c typename T::type. ETK_Typename, /// No keyword precedes the qualified type name. ETK_None }; /// A helper class for Type nodes having an ElaboratedTypeKeyword. /// The keyword in stored in the free bits of the base class. /// Also provides a few static helpers for converting and printing /// elaborated type keyword and tag type kind enumerations. class TypeWithKeyword : public Type { protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack) { TypeWithKeywordBits.Keyword = Keyword; } public: ElaboratedTypeKeyword getKeyword() const { return static_cast(TypeWithKeywordBits.Keyword); } /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); /// Converts a type specifier (DeclSpec::TST) into a tag type kind. /// It is an error to provide a type specifier which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); /// Converts a TagTypeKind into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); /// Converts an elaborated type keyword into a TagTypeKind. /// It is an error to provide an elaborated type keyword /// which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); static StringRef getTagTypeKindName(TagTypeKind Kind) { return getKeywordName(getKeywordForTagTypeKind(Kind)); } class CannotCastToThisType {}; static CannotCastToThisType classof(const Type *); }; /// Represents a type that was referred to using an elaborated type /// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, /// or both. /// /// This type is used to keep track of a type name as written in the /// source code, including tag keywords and any nested-name-specifiers. /// The type itself is always "sugar", used to express what was written /// in the source code but containing no additional semantic information. class ElaboratedType final : public TypeWithKeyword, public llvm::FoldingSetNode, private llvm::TrailingObjects { friend class ASTContext; // ASTContext creates these friend TrailingObjects; /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this qualified name refers to. QualType NamedType; /// The (re)declaration of this tag type owned by this occurrence is stored /// as a trailing object if there is one. Use getOwnedTagDecl to obtain /// it, or obtain a null pointer if there is none. ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, NamedType->isDependentType(), NamedType->isInstantiationDependentType(), NamedType->isVariablyModifiedType(), NamedType->containsUnexpandedParameterPack()), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { ElaboratedTypeBits.HasOwnedTagDecl = true; *getTrailingObjects() = OwnedTagDecl; } assert(!(Keyword == ETK_None && NNS == nullptr) && "ElaboratedType cannot have elaborated type keyword " "and name qualifier both null."); } public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the qualified-id. QualType getNamedType() const { return NamedType; } /// Remove a single level of sugar. QualType desugar() const { return getNamedType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } /// Return the (re)declaration of this type owned by this occurrence of this /// type, or nullptr if there is none. TagDecl *getOwnedTagDecl() const { return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, TagDecl *OwnedTagDecl) { ID.AddInteger(Keyword); ID.AddPointer(NNS); NamedType.Profile(ID); ID.AddPointer(OwnedTagDecl); } static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } }; /// Represents a qualified type name for which the type name is /// dependent. /// /// DependentNameType represents a class of dependent types that involve a /// possibly dependent nested-name-specifier (e.g., "T::") followed by a /// name of a type. The DependentNameType may start with a "typename" (for a /// typename-specifier), "class", "struct", "union", or "enum" (for a /// dependent elaborated-type-specifier), or nothing (in contexts where we /// know that we must be referring to a type, e.g., in a base class specifier). /// Typically the nested-name-specifier is dependent, but in MSVC compatibility /// mode, this type is used with non-dependent names to delay name lookup until /// instantiation. class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this typename specifier refers to. const IdentifierInfo *Name; DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name) {} public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the typename specifier as an identifier. /// /// This routine will return a non-NULL identifier pointer when the /// form of the original typename was terminated by an identifier, /// e.g., "typename T::type". const IdentifierInfo *getIdentifier() const { return Name; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, Name); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name) { ID.AddInteger(Keyword); ID.AddPointer(NNS); ID.AddPointer(Name); } static bool classof(const Type *T) { return T->getTypeClass() == DependentName; } }; /// Represents a template specialization type whose template cannot be /// resolved, e.g. /// A::template B class alignas(8) DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The identifier of the template. const IdentifierInfo *Name; DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args, QualType Canon); const TemplateArgument *getArgBuffer() const { return reinterpret_cast(this+1); } TemplateArgument *getArgBuffer() { return reinterpret_cast(this+1); } public: NestedNameSpecifier *getQualifier() const { return NNS; } const IdentifierInfo *getIdentifier() const { return Name; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return getArgBuffer(); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return DependentTemplateSpecializationTypeBits.NumArgs; } const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // inline in TemplateBase.h bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getKeyword(), NNS, Name, {getArgs(), getNumArgs()}); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, ArrayRef Args); static bool classof(const Type *T) { return T->getTypeClass() == DependentTemplateSpecialization; } }; /// Represents a pack expansion of types. /// /// Pack expansions are part of C++11 variadic templates. A pack /// expansion contains a pattern, which itself contains one or more /// "unexpanded" parameter packs. When instantiated, a pack expansion /// produces a series of types, each instantiated from the pattern of /// the expansion, where the Ith instantiation of the pattern uses the /// Ith arguments bound to each of the unexpanded parameter packs. The /// pack expansion is considered to "expand" these unexpanded /// parameter packs. /// /// \code /// template struct tuple; /// /// template /// struct tuple_of_references { /// typedef tuple type; /// }; /// \endcode /// /// Here, the pack expansion \c Types&... is represented via a /// PackExpansionType whose pattern is Types&. class PackExpansionType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The pattern of the pack expansion. QualType Pattern; PackExpansionType(QualType Pattern, QualType Canon, Optional NumExpansions) : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), /*InstantiationDependent=*/true, /*VariablyModified=*/Pattern->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Pattern(Pattern) { PackExpansionTypeBits.NumExpansions = NumExpansions ? *NumExpansions + 1 : 0; } public: /// Retrieve the pattern of this pack expansion, which is the /// type that will be repeatedly instantiated when instantiating the /// pack expansion itself. QualType getPattern() const { return Pattern; } /// Retrieve the number of expansions that this pack expansion will /// generate, if known. Optional getNumExpansions() const { if (PackExpansionTypeBits.NumExpansions) return PackExpansionTypeBits.NumExpansions - 1; return None; } bool isSugared() const { return !Pattern->isDependentType(); } QualType desugar() const { return isSugared() ? Pattern : QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPattern(), getNumExpansions()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, Optional NumExpansions) { ID.AddPointer(Pattern.getAsOpaquePtr()); ID.AddBoolean(NumExpansions.hasValue()); if (NumExpansions) ID.AddInteger(*NumExpansions); } static bool classof(const Type *T) { return T->getTypeClass() == PackExpansion; } }; /// This class wraps the list of protocol qualifiers. For types that can /// take ObjC protocol qualifers, they can subclass this class. template class ObjCProtocolQualifiers { protected: ObjCProtocolQualifiers() = default; ObjCProtocolDecl * const *getProtocolStorage() const { return const_cast(this)->getProtocolStorage(); } ObjCProtocolDecl **getProtocolStorage() { return static_cast(this)->getProtocolStorageImpl(); } void setNumProtocols(unsigned N) { static_cast(this)->setNumProtocolsImpl(N); } void initialize(ArrayRef protocols) { setNumProtocols(protocols.size()); assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); if (!protocols.empty()) memcpy(getProtocolStorage(), protocols.data(), protocols.size() * sizeof(ObjCProtocolDecl*)); } public: using qual_iterator = ObjCProtocolDecl * const *; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getProtocolStorage(); } qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } bool qual_empty() const { return getNumProtocols() == 0; } /// Return the number of qualifying protocols in this type, or 0 if /// there are none. unsigned getNumProtocols() const { return static_cast(this)->getNumProtocolsImpl(); } /// Fetch a protocol by index. ObjCProtocolDecl *getProtocol(unsigned I) const { assert(I < getNumProtocols() && "Out-of-range protocol access"); return qual_begin()[I]; } /// Retrieve all of the protocol qualifiers. ArrayRef getProtocols() const { return ArrayRef(qual_begin(), getNumProtocols()); } }; /// Represents a type parameter type in Objective C. It can take /// a list of protocols. class ObjCTypeParamType : public Type, public ObjCProtocolQualifiers, public llvm::FoldingSetNode { friend class ASTContext; friend class ObjCProtocolQualifiers; /// The number of protocols stored on this type. unsigned NumProtocols : 6; ObjCTypeParamDecl *OTPDecl; /// The protocols are stored after the ObjCTypeParamType node. In the /// canonical type, the list of protocols are sorted alphabetically /// and uniqued. ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return NumProtocols; } void setNumProtocolsImpl(unsigned N) { NumProtocols = N; } ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols); public: bool isSugared() const { return true; } QualType desugar() const { return getCanonicalTypeInternal(); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCTypeParam; } void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const ObjCTypeParamDecl *OTPDecl, ArrayRef protocols); ObjCTypeParamDecl *getDecl() const { return OTPDecl; } }; /// Represents a class type in Objective C. /// /// Every Objective C type is a combination of a base type, a set of /// type arguments (optional, for parameterized classes) and a list of /// protocols. /// /// Given the following declarations: /// \code /// \@class C; /// \@protocol P; /// \endcode /// /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType /// with base C and no protocols. /// /// 'C

' is an unspecialized ObjCObjectType with base C and protocol list [P]. /// 'C' is a specialized ObjCObjectType with type arguments 'C*' and no /// protocol list. /// 'C

' is a specialized ObjCObjectType with base C, type arguments 'C*', /// and protocol list [P]. /// /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType /// and no protocols. /// /// 'id

' is an ObjCObjectPointerType whose pointee is an ObjCObjectType /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type, public ObjCProtocolQualifiers { friend class ObjCProtocolQualifiers; // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. // ObjCObjectType.NumProtocols - the number of protocols stored // after the type arguments of ObjCObjectPointerType node. // // These protocols are those written directly on the type. If // protocol qualifiers ever become additive, the iterators will need // to get kindof complicated. // // In the canonical object type, these are sorted alphabetically // and uniqued. /// Either a BuiltinType or an InterfaceType or sugar for either. QualType BaseType; /// Cached superclass type. mutable llvm::PointerIntPair CachedSuperClassType; QualType *getTypeArgStorage(); const QualType *getTypeArgStorage() const { return const_cast(this)->getTypeArgStorage(); } ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return ObjCObjectTypeBits.NumProtocols; } void setNumProtocolsImpl(unsigned N) { ObjCObjectTypeBits.NumProtocols = N; } protected: enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; ObjCObjectTypeBits.NumTypeArgs = 0; ObjCObjectTypeBits.IsKindOf = 0; } void computeSuperClassTypeSlow() const; public: /// Gets the base type of this object type. This is always (possibly /// sugar for) one of: /// - the 'id' builtin type (as opposed to the 'id' type visible to the /// user, which is a typedef for an ObjCObjectPointerType) /// - the 'Class' builtin type (same caveat) /// - an ObjCObjectType (currently always an ObjCInterfaceType) QualType getBaseType() const { return BaseType; } bool isObjCId() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); } bool isObjCClass() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); } bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } bool isObjCUnqualifiedIdOrClass() const { if (!qual_empty()) return false; if (const BuiltinType *T = getBaseType()->getAs()) return T->getKind() == BuiltinType::ObjCId || T->getKind() == BuiltinType::ObjCClass; return false; } bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } /// Gets the interface declaration for this object type, if the base type /// really is an interface. ObjCInterfaceDecl *getInterface() const; /// Determine whether this object type is "specialized", meaning /// that it has type arguments. bool isSpecialized() const; /// Determine whether this object type was written with type arguments. bool isSpecializedAsWritten() const { return ObjCObjectTypeBits.NumTypeArgs > 0; } /// Determine whether this object type is "unspecialized", meaning /// that it has no type arguments. bool isUnspecialized() const { return !isSpecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments of this object type (semantically). ArrayRef getTypeArgs() const; /// Retrieve the type arguments of this object type as they were /// written. ArrayRef getTypeArgsAsWritten() const { return llvm::makeArrayRef(getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs); } /// Whether this is a "__kindof" type as written. bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } /// Whether this ia a "__kindof" type (semantically). bool isKindOfType() const; /// Retrieve the type of the superclass of this object type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// specialization of the superclass type. Produces a null type if /// there is no superclass. QualType getSuperClassType() const { if (!CachedSuperClassType.getInt()) computeSuperClassTypeSlow(); assert(CachedSuperClassType.getInt() && "Superclass not set?"); return QualType(CachedSuperClassType.getPointer(), 0); } /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObject || T->getTypeClass() == ObjCInterface; } }; /// A class providing a concrete implementation /// of ObjCObjectType, so as to not increase the footprint of /// ObjCInterfaceType. Code outside of ASTContext and the core type /// system should not reference this type. class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { friend class ASTContext; // If anyone adds fields here, ObjCObjectType::getProtocolStorage() // will need to be modified. ObjCObjectTypeImpl(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); }; inline QualType *ObjCObjectType::getTypeArgStorage() { return reinterpret_cast(static_cast(this)+1); } inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { return reinterpret_cast( getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); } inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { return reinterpret_cast( static_cast(this)+1); } /// Interfaces are the core concept in Objective-C for object oriented design. /// They basically correspond to C++ classes. There are two kinds of interface /// types: normal interfaces like `NSString`, and qualified interfaces, which /// are qualified with a protocol list like `NSString`. /// /// ObjCInterfaceType guarantees the following properties when considered /// as a subtype of its superclass, ObjCObjectType: /// - There are no protocol qualifiers. To reinforce this, code which /// tries to invoke the protocol methods via an ObjCInterfaceType will /// fail to compile. /// - It is its own base type. That is, if T is an ObjCInterfaceType*, /// T->getBaseType() == QualType(T, 0). class ObjCInterfaceType : public ObjCObjectType { friend class ASTContext; // ASTContext creates these. friend class ASTReader; friend class ObjCInterfaceDecl; mutable ObjCInterfaceDecl *Decl; ObjCInterfaceType(const ObjCInterfaceDecl *D) : ObjCObjectType(Nonce_ObjCInterface), Decl(const_cast(D)) {} public: /// Get the declaration of this interface. ObjCInterfaceDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCInterface; } // Nonsense to "hide" certain members of ObjCObjectType within this // class. People asking for protocols on an ObjCInterfaceType are // not going to get what they want: ObjCInterfaceTypes are // guaranteed to have no protocols. enum { qual_iterator, qual_begin, qual_end, getNumProtocols, getProtocol }; }; inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { QualType baseType = getBaseType(); while (const auto *ObjT = baseType->getAs()) { if (const auto *T = dyn_cast(ObjT)) return T->getDecl(); baseType = ObjT->getBaseType(); } return nullptr; } /// Represents a pointer to an Objective C object. /// /// These are constructed from pointer declarators when the pointee type is /// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' /// types are typedefs for these, and the protocol-qualified types 'id

' /// and 'Class

' are translated into these. /// /// Pointers to pointers to Objective C objects are still PointerTypes; /// only the first level of pointer gets it own type implementation. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) : Type(ObjCObjectPointer, Canonical, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: /// Gets the type pointed to by this ObjC pointer. /// The result will always be an ObjCObjectType or sugar thereof. QualType getPointeeType() const { return PointeeType; } /// Gets the type pointed to by this ObjC pointer. Always returns non-null. /// /// This method is equivalent to getPointeeType() except that /// it discards any typedefs (or other sugar) between this /// type and the "outermost" object type. So for: /// \code /// \@class A; \@protocol P; \@protocol Q; /// typedef A

AP; /// typedef A A1; /// typedef A1

A1P; /// typedef A1P A1PQ; /// \endcode /// For 'A*', getObjectType() will return 'A'. /// For 'A

*', getObjectType() will return 'A

'. /// For 'AP*', getObjectType() will return 'A

'. /// For 'A1*', getObjectType() will return 'A'. /// For 'A1

*', getObjectType() will return 'A1

'. /// For 'A1P*', getObjectType() will return 'A1

'. /// For 'A1PQ*', getObjectType() will return 'A1', because /// adding protocols to a protocol-qualified base discards the /// old qualifiers (for now). But if it didn't, getObjectType() /// would return 'A1P' (and we'd have to make iterating over /// qualifiers more complicated). const ObjCObjectType *getObjectType() const { return PointeeType->castAs(); } /// If this pointer points to an Objective C /// \@interface type, gets the type for that interface. Any protocol /// qualifiers on the interface are ignored. /// /// \return null if the base type for this pointer is 'id' or 'Class' const ObjCInterfaceType *getInterfaceType() const; /// If this pointer points to an Objective \@interface /// type, gets the declaration for that interface. /// /// \return null if the base type for this pointer is 'id' or 'Class' ObjCInterfaceDecl *getInterfaceDecl() const { return getObjectType()->getInterface(); } /// True if this is equivalent to the 'id' type, i.e. if /// its object type is the primitive 'id' type with no protocols. bool isObjCIdType() const { return getObjectType()->isObjCUnqualifiedId(); } /// True if this is equivalent to the 'Class' type, /// i.e. if its object tive is the primitive 'Class' type with no protocols. bool isObjCClassType() const { return getObjectType()->isObjCUnqualifiedClass(); } /// True if this is equivalent to the 'id' or 'Class' type, bool isObjCIdOrClassType() const { return getObjectType()->isObjCUnqualifiedIdOrClass(); } /// True if this is equivalent to 'id

' for some non-empty set of /// protocols. bool isObjCQualifiedIdType() const { return getObjectType()->isObjCQualifiedId(); } /// True if this is equivalent to 'Class

' for some non-empty set of /// protocols. bool isObjCQualifiedClassType() const { return getObjectType()->isObjCQualifiedClass(); } /// Whether this is a "__kindof" type. bool isKindOfType() const { return getObjectType()->isKindOfType(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecialized() const { return getObjectType()->isSpecialized(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecializedAsWritten() const { return getObjectType()->isSpecializedAsWritten(); } /// Whether this type is unspecialized, meaning that is has no type arguments. bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgs() const { return getObjectType()->getTypeArgs(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgsAsWritten() const { return getObjectType()->getTypeArgsAsWritten(); } /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. using qual_iterator = ObjCObjectType::qual_iterator; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getObjectType()->qual_begin(); } qual_iterator qual_end() const { return getObjectType()->qual_end(); } bool qual_empty() const { return getObjectType()->qual_empty(); } /// Return the number of qualifying protocols on the object type. unsigned getNumProtocols() const { return getObjectType()->getNumProtocols(); } /// Retrieve a qualifying protocol by index on the object type. ObjCProtocolDecl *getProtocol(unsigned I) const { return getObjectType()->getProtocol(I); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Retrieve the type of the superclass of this object pointer type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// pointer to a specialization of the superclass type. Produces a /// null type if there is no superclass. QualType getSuperClassType() const; /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const; void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } }; class AtomicType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ValueType; AtomicType(QualType ValTy, QualType Canonical) : Type(Atomic, Canonical, ValTy->isDependentType(), ValTy->isInstantiationDependentType(), ValTy->isVariablyModifiedType(), ValTy->containsUnexpandedParameterPack()), ValueType(ValTy) {} public: /// Gets the type contained by this atomic type, i.e. /// the type returned by performing an atomic load of this atomic type. QualType getValueType() const { return ValueType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getValueType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Atomic; } }; /// PipeType - OpenCL20. class PipeType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; bool isRead; PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) : Type(Pipe, CanonicalPtr, elemType->isDependentType(), elemType->isInstantiationDependentType(), elemType->isVariablyModifiedType(), elemType->containsUnexpandedParameterPack()), ElementType(elemType), isRead(isRead) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), isReadOnly()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { ID.AddPointer(T.getAsOpaquePtr()); ID.AddBoolean(isRead); } static bool classof(const Type *T) { return T->getTypeClass() == Pipe; } bool isReadOnly() const { return isRead; } }; /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} /// Collect any qualifiers on the given type and return an /// unqualified type. The qualifiers are assumed to be consistent /// with those already in the type. const Type *strip(QualType type) { addFastQualifiers(type.getLocalFastQualifiers()); if (!type.hasLocalNonFastQualifiers()) return type.getTypePtrUnsafe(); const ExtQuals *extQuals = type.getExtQualsUnsafe(); addConsistentQualifiers(extQuals->getQualifiers()); return extQuals->getBaseType(); } /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, QualType QT) const; /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, const Type* T) const; }; // Inline function definitions. inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { SplitQualType desugar = Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); desugar.Quals.addConsistentQualifiers(Quals); return desugar; } inline const Type *QualType::getTypePtr() const { return getCommonPtr()->BaseType; } inline const Type *QualType::getTypePtrOrNull() const { return (isNull() ? nullptr : getCommonPtr()->BaseType); } inline SplitQualType QualType::split() const { if (!hasLocalNonFastQualifiers()) return SplitQualType(getTypePtrUnsafe(), Qualifiers::fromFastMask(getLocalFastQualifiers())); const ExtQuals *eq = getExtQualsUnsafe(); Qualifiers qs = eq->getQualifiers(); qs.addFastQualifiers(getLocalFastQualifiers()); return SplitQualType(eq->getBaseType(), qs); } inline Qualifiers QualType::getLocalQualifiers() const { Qualifiers Quals; if (hasLocalNonFastQualifiers()) Quals = getExtQualsUnsafe()->getQualifiers(); Quals.addFastQualifiers(getLocalFastQualifiers()); return Quals; } inline Qualifiers QualType::getQualifiers() const { Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); quals.addFastQualifiers(getLocalFastQualifiers()); return quals; } inline unsigned QualType::getCVRQualifiers() const { unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); cvr |= getLocalCVRQualifiers(); return cvr; } inline QualType QualType::getCanonicalType() const { QualType canon = getCommonPtr()->CanonicalType; return canon.withFastQualifiers(getLocalFastQualifiers()); } inline bool QualType::isCanonical() const { return getTypePtr()->isCanonicalUnqualified(); } inline bool QualType::isCanonicalAsParam() const { if (!isCanonical()) return false; if (hasLocalQualifiers()) return false; const Type *T = getTypePtr(); if (T->isVariablyModifiedType() && T->hasSizedVLAType()) return false; return !isa(T) && !isa(T); } inline bool QualType::isConstQualified() const { return isLocalConstQualified() || getCommonPtr()->CanonicalType.isLocalConstQualified(); } inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || getCommonPtr()->CanonicalType.isLocalRestrictQualified(); } inline bool QualType::isVolatileQualified() const { return isLocalVolatileQualified() || getCommonPtr()->CanonicalType.isLocalVolatileQualified(); } inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || getCommonPtr()->CanonicalType.hasLocalQualifiers(); } inline QualType QualType::getUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return QualType(getTypePtr(), 0); return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); } inline SplitQualType QualType::getSplitUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return split(); return getSplitUnqualifiedTypeImpl(*this); } inline void QualType::removeLocalConst() { removeLocalFastQualifiers(Qualifiers::Const); } inline void QualType::removeLocalRestrict() { removeLocalFastQualifiers(Qualifiers::Restrict); } inline void QualType::removeLocalVolatile() { removeLocalFastQualifiers(Qualifiers::Volatile); } inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); static_assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask, "Fast bits differ from CVR bits!"); // Fast path: we don't need to touch the slow qualifiers. removeLocalFastQualifiers(Mask); } /// Return the address space of this type. inline LangAS QualType::getAddressSpace() const { return getQualifiers().getAddressSpace(); } /// Return the gc attribute of this type. inline Qualifiers::GC QualType::getObjCGCAttr() const { return getQualifiers().getObjCGCAttr(); } inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { if (const auto *PT = t.getAs()) { if (const auto *FT = PT->getPointeeType()->getAs()) return FT->getExtInfo(); } else if (const auto *FT = t.getAs()) return FT->getExtInfo(); return FunctionType::ExtInfo(); } inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { return getFunctionExtInfo(*t); } /// Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and /// "int". However, it is not more qualified than "const volatile /// int". inline bool QualType::isMoreQualifiedThan(QualType other) const { Qualifiers MyQuals = getQualifiers(); Qualifiers OtherQuals = other.getQualifiers(); return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals)); } /// Determine whether this type is at last /// as qualified as the Other type. For example, "const volatile /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { Qualifiers OtherQuals = other.getQualifiers(); // Ignore __unaligned qualifier if this type is a void. if (getUnqualifiedType()->isVoidType()) OtherQuals.removeUnaligned(); return getQualifiers().compatiblyIncludes(OtherQuals); } /// If Type is a reference type (e.g., const /// int&), returns the type that the reference refers to ("const /// int"). Otherwise, returns the type itself. This routine is used /// throughout Sema to implement C++ 5p6: /// /// If an expression initially has the type "reference to T" (8.3.2, /// 8.5.3), the type is adjusted to "T" prior to any further /// analysis, the expression designates the object or function /// denoted by the reference, and the expression is an lvalue. inline QualType QualType::getNonReferenceType() const { if (const auto *RefType = (*this)->getAs()) return RefType->getPointeeType(); else return *this; } inline bool QualType::isCForbiddenLValueType() const { return ((getTypePtr()->isVoidType() && !hasQualifiers()) || getTypePtr()->isFunctionType()); } /// Tests whether the type is categorized as a fundamental type. /// /// \returns True for types specified in C++0x [basic.fundamental]. inline bool Type::isFundamentalType() const { return isVoidType() || // FIXME: It's really annoying that we don't have an // 'isArithmeticType()' which agrees with the standard definition. (isArithmeticType() && !isEnumeralType()); } /// Tests whether the type is categorized as a compound type. /// /// \returns True for types specified in C++0x [basic.compound]. inline bool Type::isCompoundType() const { // C++0x [basic.compound]p1: // Compound types can be constructed in the following ways: // -- arrays of objects of a given type [...]; return isArrayType() || // -- functions, which have parameters of given types [...]; isFunctionType() || // -- pointers to void or objects or functions [...]; isPointerType() || // -- references to objects or functions of a given type. [...] isReferenceType() || // -- classes containing a sequence of objects of various types, [...]; isRecordType() || // -- unions, which are classes capable of containing objects of different // types at different times; isUnionType() || // -- enumerations, which comprise a set of named constant values. [...]; isEnumeralType() || // -- pointers to non-static class members, [...]. isMemberPointerType(); } inline bool Type::isFunctionType() const { return isa(CanonicalType); } inline bool Type::isPointerType() const { return isa(CanonicalType); } inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } inline bool Type::isBlockPointerType() const { return isa(CanonicalType); } inline bool Type::isReferenceType() const { return isa(CanonicalType); } inline bool Type::isLValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isRValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isFunctionPointerType() const { if (const auto *T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; } inline bool Type::isMemberPointerType() const { return isa(CanonicalType); } inline bool Type::isMemberFunctionPointerType() const { if (const auto *T = getAs()) return T->isMemberFunctionPointer(); else return false; } inline bool Type::isMemberDataPointerType() const { if (const auto *T = getAs()) return T->isMemberDataPointer(); else return false; } inline bool Type::isArrayType() const { return isa(CanonicalType); } inline bool Type::isConstantArrayType() const { return isa(CanonicalType); } inline bool Type::isIncompleteArrayType() const { return isa(CanonicalType); } inline bool Type::isVariableArrayType() const { return isa(CanonicalType); } inline bool Type::isDependentSizedArrayType() const { return isa(CanonicalType); } inline bool Type::isBuiltinType() const { return isa(CanonicalType); } inline bool Type::isRecordType() const { return isa(CanonicalType); } inline bool Type::isEnumeralType() const { return isa(CanonicalType); } inline bool Type::isAnyComplexType() const { return isa(CanonicalType); } inline bool Type::isVectorType() const { return isa(CanonicalType); } inline bool Type::isExtVectorType() const { return isa(CanonicalType); } inline bool Type::isDependentAddressSpaceType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectPointerType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectOrInterfaceType() const { return isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isAtomicType() const { return isa(CanonicalType); } inline bool Type::isObjCQualifiedIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedIdType(); return false; } inline bool Type::isObjCQualifiedClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedClassType(); return false; } inline bool Type::isObjCIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCIdType(); return false; } inline bool Type::isObjCClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCClassType(); return false; } inline bool Type::isObjCSelType() const { if (const auto *OPT = getAs()) return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); return false; } inline bool Type::isObjCBuiltinType() const { return isObjCIdType() || isObjCClassType() || isObjCSelType(); } #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLImageTypes.def" inline bool Type::isSamplerT() const { return isSpecificBuiltinType(BuiltinType::OCLSampler); } inline bool Type::isEventT() const { return isSpecificBuiltinType(BuiltinType::OCLEvent); } inline bool Type::isClkEventT() const { return isSpecificBuiltinType(BuiltinType::OCLClkEvent); } inline bool Type::isQueueT() const { return isSpecificBuiltinType(BuiltinType::OCLQueue); } inline bool Type::isReserveIDT() const { return isSpecificBuiltinType(BuiltinType::OCLReserveID); } inline bool Type::isImageType() const { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || return #include "clang/Basic/OpenCLImageTypes.def" false; // end boolean or operation } inline bool Type::isPipeType() const { return isa(CanonicalType); } #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLExtensionTypes.def" inline bool Type::isOCLIntelSubgroupAVCType() const { #define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ isOCLIntelSubgroupAVC##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOCLExtOpaqueType() const { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); } inline bool Type::isTemplateTypeParmType() const { return isa(CanonicalType); } inline bool Type::isSpecificBuiltinType(unsigned K) const { if (const BuiltinType *BT = getAs()) if (BT->getKind() == (BuiltinType::Kind) K) return true; return false; } inline bool Type::isPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isPlaceholderType(); return false; } inline const BuiltinType *Type::getAsPlaceholderType() const { if (const auto *BT = dyn_cast(this)) if (BT->isPlaceholderType()) return BT; return nullptr; } inline bool Type::isSpecificPlaceholderType(unsigned K) const { assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); if (const auto *BT = dyn_cast(this)) return (BT->getKind() == (BuiltinType::Kind) K); return false; } inline bool Type::isNonOverloadPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isNonOverloadPlaceholderType(); return false; } inline bool Type::isVoidType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Void; return false; } inline bool Type::isHalfType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Half; // FIXME: Should we allow complex __fp16? Probably not. return false; } inline bool Type::isFloat16Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float16; return false; } inline bool Type::isFloat128Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float128; return false; } inline bool Type::isNullPtrType() const { if (const auto *BT = getAs()) return BT->getKind() == BuiltinType::NullPtr; return false; } bool IsEnumDeclComplete(EnumDecl *); bool IsEnumDeclScoped(EnumDecl *); inline bool Type::isIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. return IsEnumDeclComplete(ET->getDecl()) && !IsEnumDeclScoped(ET->getDecl()); } return false; } inline bool Type::isFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isSaturatedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isUnsaturatedFixedPointType() const { return isFixedPointType() && !isSaturatedFixedPointType(); } inline bool Type::isSignedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return ((BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::LongAccum) || (BT->getKind() >= BuiltinType::ShortFract && BT->getKind() <= BuiltinType::LongFract) || (BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatLongAccum) || (BT->getKind() >= BuiltinType::SatShortFract && BT->getKind() <= BuiltinType::SatLongFract)); } return false; } inline bool Type::isUnsignedFixedPointType() const { return isFixedPointType() && !isSignedFixedPointType(); } inline bool Type::isScalarType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() > BuiltinType::Void && BT->getKind() <= BuiltinType::NullPtr; if (const EnumType *ET = dyn_cast(CanonicalType)) // Enums are scalar types, but only if they are defined. Incomplete enums // are not treated as scalar types. return IsEnumDeclComplete(ET->getDecl()); return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isIntegralOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; // Check for a complete enum type; incomplete enum types are not properly an // enumeration type in the sense required here. if (const auto *ET = dyn_cast(CanonicalType)) return IsEnumDeclComplete(ET->getDecl()); return false; } inline bool Type::isBooleanType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; return false; } inline bool Type::isUndeducedType() const { auto *DT = getContainedDeducedType(); return DT && !DT->isDeduced(); } /// Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { return isDependentType() || isRecordType() || isEnumeralType(); } /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { return isFunctionType() || isArrayType(); } inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || isObjCObjectPointerType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { return isObjCObjectPointerType(); } inline const Type *Type::getBaseElementTypeUnsafe() const { const Type *type = this; while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) type = arrayType->getElementType().getTypePtr(); return type; } inline const Type *Type::getPointeeOrArrayElementType() const { const Type *type = this; if (type->isAnyPointerType()) return type->getPointeeType().getTypePtr(); else if (type->isArrayType()) return type->getBaseElementTypeUnsafe(); return type; } /// Insertion operator for diagnostics. This allows sending Qualifiers into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Qualifiers Q) { DB.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return DB; } /// Insertion operator for partial diagnostics. This allows sending Qualifiers /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, Qualifiers Q) { PD.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return PD; } /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, QualType T) { DB.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return DB; } /// Insertion operator for partial diagnostics. This allows sending QualType's /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, QualType T) { PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return PD; } // Helper class template that is used by Type::getAs to ensure that one does // not try to look through a qualified type to get to an array type. template using TypeIsArrayType = std::integral_constant::value || std::is_base_of::value>; // Member-template getAs'. template const T *Type::getAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAs!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::getAsAdjusted() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // Strip off type adjustments that do not modify the underlying nature of the // type. const Type *Ty = this; while (Ty) { if (const auto *A = dyn_cast(Ty)) Ty = A->getModifiedType().getTypePtr(); else if (const auto *E = dyn_cast(Ty)) Ty = E->desugar().getTypePtr(); else if (const auto *P = dyn_cast(Ty)) Ty = P->desugar().getTypePtr(); else if (const auto *A = dyn_cast(Ty)) Ty = A->desugar().getTypePtr(); else break; } // Just because the canonical type is correct does not mean we can use cast<>, // since we may not have stripped off all the sugar down to the base type. return dyn_cast(Ty); } inline const ArrayType *Type::getAsArrayTypeUnsafe() const { // If this is directly an array type, return it. if (const auto *arr = dyn_cast(this)) return arr; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::castAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with castAs!"); if (const auto *ty = dyn_cast(this)) return ty; assert(isa(CanonicalType)); return cast(getUnqualifiedDesugaredType()); } inline const ArrayType *Type::castAsArrayTypeUnsafe() const { assert(isa(CanonicalType)); if (const auto *arr = dyn_cast(this)) return arr; return cast(getUnqualifiedDesugaredType()); } DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { #ifndef NDEBUG QualType Adjusted = getAdjustedType(); (void)AttributedType::stripOuterNullability(Adjusted); assert(isa(Adjusted)); #endif } QualType DecayedType::getPointeeType() const { QualType Decayed = getDecayedType(); (void)AttributedType::stripOuterNullability(Decayed); return cast(Decayed)->getPointeeType(); } // Get the decimal string representation of a fixed point type, represented // as a scaled integer. void FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, unsigned Scale); } // namespace clang #endif // LLVM_CLANG_AST_TYPE_H Index: stable/12 =================================================================== --- stable/12 (revision 349966) +++ stable/12 (revision 349967) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r349876