Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 12.5.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 13.4.0
ARM GCC 13.4.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 14.3.0
ARM GCC 14.3.0 (unknown-eabi)
ARM GCC 15.1.0
ARM GCC 15.1.0 (unknown-eabi)
ARM GCC 15.2.0
ARM GCC 15.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (ex-WINE)
ARM msvc v19.10 (ex-WINE)
ARM msvc v19.14 (ex-WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 12.4.0
ARM64 gcc 12.5.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 13.3.0
ARM64 gcc 13.4.0
ARM64 gcc 14.1.0
ARM64 gcc 14.2.0
ARM64 gcc 14.3.0
ARM64 gcc 15.1.0
ARM64 gcc 15.2.0
ARM64 gcc 4.9.4
ARM64 gcc 5.4
ARM64 gcc 5.5.0
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (ex-WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 12.5.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 13.4.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 14.3.0
AVR gcc 15.1.0
AVR gcc 15.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF clang 20.1.0
BPF clang 21.1.0
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
EDG 6.7
EDG 6.7 (GNU mode gcc 14)
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
HPPA gcc 14.3.0
HPPA gcc 15.1.0
HPPA gcc 15.2.0
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LoongArch64 clang (trunk)
LoongArch64 clang 17.0.1
LoongArch64 clang 18.1.0
LoongArch64 clang 19.1.0
LoongArch64 clang 20.1.0
LoongArch64 clang 21.1.0
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 13.4.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68K gcc 14.3.0
M68K gcc 15.1.0
M68K gcc 15.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
MinGW gcc 14.3.0
MinGW gcc 15.2.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 12.5.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 13.4.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 14.3.0
RISC-V (32-bits) gcc 15.1.0
RISC-V (32-bits) gcc 15.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 12.5.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 13.4.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 14.3.0
RISC-V (64-bits) gcc 15.1.0
RISC-V (64-bits) gcc 15.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 20.1.0
RISC-V rv32gc clang 21.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 20.1.0
RISC-V rv64gc clang 21.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 12.5.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 13.4.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC LEON gcc 14.3.0
SPARC LEON gcc 15.1.0
SPARC LEON gcc 15.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 12.5.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 13.4.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC gcc 14.3.0
SPARC gcc 15.1.0
SPARC gcc 15.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 12.5.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 13.4.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
SPARC64 gcc 14.3.0
SPARC64 gcc 15.1.0
SPARC64 gcc 15.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 12.5.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 13.4.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI C6x gcc 14.3.0
TI C6x gcc 15.1.0
TI C6x gcc 15.2.0
TI CL430 21.6.1
Tricore gcc 11.3.0 (EEESlab)
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
VAX gcc NetBSDELF 12.4.0 (Apr 16 05:27 2025)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 14.2.0 (20241119)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 14.2.0 (20241119)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 14.2.0 (20241119)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.41 VS17.11
arm64 msvc v19.42 VS17.12
arm64 msvc v19.43 VS17.13
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 20.1.0
armv7-a clang 21.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 20.1.0
armv8-a clang 21.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clad trunk (clang 21.1.0)
clad v1.10 (clang 20.1.0)
clad v1.8 (clang 18.1.0)
clad v1.9 (clang 19.1.0)
clad v2.00 (clang 20.1.0)
clad v2.1 (clang 21.1.0)
clang-cl 18.1.0
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
ez80-clang 15.0.0
ez80-clang 15.0.7
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 12.5.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 13.4.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
loongarch64 gcc 14.3.0
loongarch64 gcc 15.1.0
loongarch64 gcc 15.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips clang 20.1.0
mips clang 21.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 12.5.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 13.4.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 14.3.0
mips gcc 15.1.0
mips gcc 15.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 12.5.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 13.4.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 14.3.0
mips64 (el) gcc 15.1.0
mips64 (el) gcc 15.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 clang 20.1.0
mips64 clang 21.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 12.5.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 13.4.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 14.3.0
mips64 gcc 15.1.0
mips64 gcc 15.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mips64el clang 20.1.0
mips64el clang 21.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel clang 20.1.0
mipsel clang 21.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 12.4.0
mipsel gcc 12.5.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 13.3.0
mipsel gcc 13.4.0
mipsel gcc 14.1.0
mipsel gcc 14.2.0
mipsel gcc 14.3.0
mipsel gcc 15.1.0
mipsel gcc 15.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 12.5.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 13.4.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 14.3.0
power gcc 15.1.0
power gcc 15.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 12.4.0
power64 gcc 12.5.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 13.3.0
power64 gcc 13.4.0
power64 gcc 14.1.0
power64 gcc 14.2.0
power64 gcc 14.3.0
power64 gcc 15.1.0
power64 gcc 15.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 12.5.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 13.4.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 14.3.0
power64le gcc 15.1.0
power64le gcc 15.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
qnx 8.0.0
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 12.5.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 13.4.0
s390x gcc 14.1.0
s390x gcc 14.2.0
s390x gcc 14.3.0
s390x gcc 15.1.0
s390x gcc 15.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 12.5.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 13.4.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 14.3.0
sh gcc 15.1.0
sh gcc 15.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (ex-WINE)
x64 msvc v19.10 (ex-WINE)
x64 msvc v19.14 (ex-WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.41 VS17.11
x64 msvc v19.42 VS17.12
x64 msvc v19.43 VS17.13
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (ex-WINE)
x86 msvc v19.10 (ex-WINE)
x86 msvc v19.14 (ex-WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.41 VS17.11
x86 msvc v19.42 VS17.12
x86 msvc v19.43 VS17.13
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.11
x86 nvc++ 24.3
x86 nvc++ 24.5
x86 nvc++ 24.7
x86 nvc++ 24.9
x86 nvc++ 25.1
x86 nvc++ 25.3
x86 nvc++ 25.5
x86 nvc++ 25.7
x86 nvc++ 25.9
x86-64 Zapcc 190308
x86-64 clang (-fimplicit-constexpr)
x86-64 clang (Chris Bazley N3089)
x86-64 clang (EricWF contracts)
x86-64 clang (amd-staging)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2998)
x86-64 clang (experimental P3068)
x86-64 clang (experimental P3309)
x86-64 clang (experimental P3367)
x86-64 clang (experimental P3372)
x86-64 clang (experimental P3385)
x86-64 clang (experimental P3776)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (old concepts branch)
x86-64 clang (p1974)
x86-64 clang (pattern matching - P2688)
x86-64 clang (reflection - C++26)
x86-64 clang (reflection - TS)
x86-64 clang (resugar)
x86-64 clang (string interpolation - P3412)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 19.1.0
x86-64 clang 19.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 20.1.0
x86-64 clang 20.1.0 (assertions)
x86-64 clang 21.1.0
x86-64 clang 21.1.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 clang rocm-6.0.2
x86-64 clang rocm-6.1.2
x86-64 clang rocm-6.2.4
x86-64 clang rocm-6.3.3
x86-64 clang rocm-6.4.0
x86-64 gcc (P2034 lambdas)
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.3 (assertions)
x86-64 gcc 10.4
x86-64 gcc 10.4 (assertions)
x86-64 gcc 10.5
x86-64 gcc 10.5 (assertions)
x86-64 gcc 11.1
x86-64 gcc 11.1 (assertions)
x86-64 gcc 11.2
x86-64 gcc 11.2 (assertions)
x86-64 gcc 11.3
x86-64 gcc 11.3 (assertions)
x86-64 gcc 11.4
x86-64 gcc 11.4 (assertions)
x86-64 gcc 12.1
x86-64 gcc 12.1 (assertions)
x86-64 gcc 12.2
x86-64 gcc 12.2 (assertions)
x86-64 gcc 12.3
x86-64 gcc 12.3 (assertions)
x86-64 gcc 12.4
x86-64 gcc 12.4 (assertions)
x86-64 gcc 12.5
x86-64 gcc 12.5 (assertions)
x86-64 gcc 13.1
x86-64 gcc 13.1 (assertions)
x86-64 gcc 13.2
x86-64 gcc 13.2 (assertions)
x86-64 gcc 13.3
x86-64 gcc 13.3 (assertions)
x86-64 gcc 13.4
x86-64 gcc 13.4 (assertions)
x86-64 gcc 14.1
x86-64 gcc 14.1 (assertions)
x86-64 gcc 14.2
x86-64 gcc 14.2 (assertions)
x86-64 gcc 14.3
x86-64 gcc 14.3 (assertions)
x86-64 gcc 15.1
x86-64 gcc 15.1 (assertions)
x86-64 gcc 15.2
x86-64 gcc 15.2 (assertions)
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
x86-64 icx 2024.1.0
x86-64 icx 2024.2.0
x86-64 icx 2024.2.1
x86-64 icx 2025.0.0
x86-64 icx 2025.0.1
x86-64 icx 2025.0.3
x86-64 icx 2025.0.4
x86-64 icx 2025.1.0
x86-64 icx 2025.1.1
x86-64 icx 2025.2.0
x86-64 icx 2025.2.1
x86-64 icx 2025.2.1
z180-clang 15.0.0
z180-clang 15.0.7
z80-clang 15.0.0
z80-clang 15.0.7
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.12.1
zig c++ 0.13.0
zig c++ 0.14.0
zig c++ 0.14.1
zig c++ 0.15.1
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
#include <utility> /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Various compiler checks. */ #ifndef mozilla_Compiler_h #define mozilla_Compiler_h #define MOZ_IS_GCC 0 #if !defined(__clang__) && defined(__GNUC__) # undef MOZ_IS_GCC # define MOZ_IS_GCC 1 /* * These macros should simplify gcc version checking. For example, to check * for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`. */ # define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= \ ((major)*10000 + (minor)*100 + (patchlevel))) # define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= \ ((major)*10000 + (minor)*100 + (patchlevel))) # if !MOZ_GCC_VERSION_AT_LEAST(6, 1, 0) # error "mfbt (and Gecko) require at least gcc 6.1 to build." # endif #endif #endif /* mozilla_Compiler_h */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Implementations of various class and method modifier attributes. */ #ifndef mozilla_Attributes_h #define mozilla_Attributes_h //#include "mozilla/Compiler.h" /* * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the * method decorated with it must be inlined, even if the compiler thinks * otherwise. This is only a (much) stronger version of the inline hint: * compilers are not guaranteed to respect it (although they're much more likely * to do so). * * The MOZ_ALWAYS_INLINE_EVEN_DEBUG macro is yet stronger. It tells the * compiler to inline even in DEBUG builds. It should be used very rarely. */ #if defined(_MSC_VER) # define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline #elif defined(__GNUC__) # define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline #else # define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline #endif #if !defined(DEBUG) # define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG #elif defined(_MSC_VER) && !defined(__cplusplus) # define MOZ_ALWAYS_INLINE __inline #else # define MOZ_ALWAYS_INLINE inline #endif #if defined(_MSC_VER) /* * g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality * without warnings (functionality used by the macros below). These modes are * detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more * standardly, by checking whether __cplusplus has a C++11 or greater value. * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. */ # define MOZ_HAVE_NEVER_INLINE __declspec(noinline) # define MOZ_HAVE_NORETURN __declspec(noreturn) #elif defined(__clang__) /* * Per Clang documentation, "Note that marketing version numbers should not * be used to check for language features, as different vendors use different * numbering schemes. Instead, use the feature checking macros." */ # ifndef __has_extension # define __has_extension \ __has_feature /* compatibility, for older versions of clang */ # endif # if __has_attribute(noinline) # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # endif # if __has_attribute(noreturn) # define MOZ_HAVE_NORETURN __attribute__((noreturn)) # endif #elif defined(__GNUC__) # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # define MOZ_HAVE_NORETURN __attribute__((noreturn)) # define MOZ_HAVE_NORETURN_PTR __attribute__((noreturn)) #endif /* * When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN * to mark some false positives */ #ifdef __clang_analyzer__ # if __has_extension(attribute_analyzer_noreturn) # define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) # endif #endif /* * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the * method decorated with it must never be inlined, even if the compiler would * otherwise choose to inline the method. Compilers aren't absolutely * guaranteed to support this, but most do. */ #if defined(MOZ_HAVE_NEVER_INLINE) # define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE #else # define MOZ_NEVER_INLINE /* no support */ #endif /* * MOZ_NEVER_INLINE_DEBUG is a macro which expands to MOZ_NEVER_INLINE * in debug builds, and nothing in opt builds. */ #if defined(DEBUG) # define MOZ_NEVER_INLINE_DEBUG MOZ_NEVER_INLINE #else # define MOZ_NEVER_INLINE_DEBUG /* don't inline in opt builds */ #endif /* * MOZ_NORETURN, specified at the start of a function declaration, indicates * that the given function does not return. (The function definition does not * need to be annotated.) * * MOZ_NORETURN void abort(const char* msg); * * This modifier permits the compiler to optimize code assuming a call to such a * function will never return. It also enables the compiler to avoid spurious * warnings about not initializing variables, or about any other seemingly-dodgy * operations performed after the function returns. * * There are two variants. The GCC version of NORETURN may be applied to a * function pointer, while for MSVC it may not. * * This modifier does not affect the corresponding function's linking behavior. */ #if defined(MOZ_HAVE_NORETURN) # define MOZ_NORETURN MOZ_HAVE_NORETURN #else # define MOZ_NORETURN /* no support */ #endif #if defined(MOZ_HAVE_NORETURN_PTR) # define MOZ_NORETURN_PTR MOZ_HAVE_NORETURN_PTR #else # define MOZ_NORETURN_PTR /* no support */ #endif /** * MOZ_COLD tells the compiler that a function is "cold", meaning infrequently * executed. This may lead it to optimize for size more aggressively than speed, * or to allocate the body of the function in a distant part of the text segment * to help keep it from taking up unnecessary icache when it isn't in use. * * Place this attribute at the very beginning of a function definition. For * example, write * * MOZ_COLD int foo(); * * or * * MOZ_COLD int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_COLD __attribute__((cold)) #else # define MOZ_COLD #endif /** * MOZ_NONNULL tells the compiler that some of the arguments to a function are * known to be non-null. The arguments are a list of 1-based argument indexes * identifying arguments which are known to be non-null. * * Place this attribute at the very beginning of a function definition. For * example, write * * MOZ_NONNULL(1, 2) int foo(char *p, char *q); */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #else # define MOZ_NONNULL(...) #endif /** * MOZ_NONNULL_RETURN tells the compiler that the function's return value is * guaranteed to be a non-null pointer, which may enable the compiler to * optimize better at call sites. * * Place this attribute at the end of a function declaration. For example, * * char* foo(char *p, char *q) MOZ_NONNULL_RETURN; */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_NONNULL_RETURN __attribute__((returns_nonnull)) #else # define MOZ_NONNULL_RETURN #endif /* * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function * declaration, indicates that for the purposes of static analysis, this * function does not return. (The function definition does not need to be * annotated.) * * MOZ_ReportCrash(const char* s, const char* file, int ln) * MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS * * Some static analyzers, like scan-build from clang, can use this information * to eliminate false positives. From the upstream documentation of scan-build: * "This attribute is useful for annotating assertion handlers that actually * can return, but for the purpose of using the analyzer we want to pretend * that such functions do not return." * */ #if defined(MOZ_HAVE_ANALYZER_NORETURN) # define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN #else # define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ #endif /* * MOZ_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time * instrumentation shipped with Clang and GCC) to not instrument the annotated * function. Furthermore, it will prevent the compiler from inlining the * function because inlining currently breaks the blacklisting mechanism of * AddressSanitizer. */ #if defined(__has_feature) # if __has_feature(address_sanitizer) # define MOZ_HAVE_ASAN_BLACKLIST # endif #elif defined(__GNUC__) # if defined(__SANITIZE_ADDRESS__) # define MOZ_HAVE_ASAN_BLACKLIST # endif #endif #if defined(MOZ_HAVE_ASAN_BLACKLIST) # define MOZ_ASAN_BLACKLIST \ MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) #else # define MOZ_ASAN_BLACKLIST /* nothing */ #endif /* * MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time * instrumentation shipped with Clang) to not instrument the annotated function. * Furthermore, it will prevent the compiler from inlining the function because * inlining currently breaks the blacklisting mechanism of ThreadSanitizer. */ #if defined(__has_feature) # if __has_feature(thread_sanitizer) # define MOZ_TSAN_BLACKLIST \ MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) # else # define MOZ_TSAN_BLACKLIST /* nothing */ # endif #else # define MOZ_TSAN_BLACKLIST /* nothing */ #endif #if defined(__has_attribute) # if __has_attribute(no_sanitize) # define MOZ_HAVE_NO_SANITIZE_ATTR # endif #endif #ifdef __clang__ # ifdef MOZ_HAVE_NO_SANITIZE_ATTR # define MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR # define MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR # endif #endif /* * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW disables *un*signed integer overflow * checking on the function it annotates, in builds configured to perform it. * (Currently this is only Clang using -fsanitize=unsigned-integer-overflow, or * via --enable-unsigned-overflow-sanitizer in Mozilla's build system.) It has * no effect in other builds. * * Place this attribute at the very beginning of a function declaration. * * Unsigned integer overflow isn't *necessarily* a bug. It's well-defined in * C/C++, and code may reasonably depend upon it. For example, * * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline bool * IsDecimal(char aChar) * { * // For chars less than '0', unsigned integer underflow occurs, to a value * // much greater than 10, so the overall test is false. * // For chars greater than '0', no overflow occurs, and only '0' to '9' * // pass the overall test. * return static_cast<unsigned int>(aChar) - '0' < 10; * } * * But even well-defined unsigned overflow often causes bugs when it occurs, so * it should be restricted to functions annotated with this attribute. * * The compiler instrumentation to detect unsigned integer overflow has costs * both at compile time and at runtime. Functions that are repeatedly inlined * at compile time will also implicitly inline the necessary instrumentation, * increasing compile time. Similarly, frequently-executed functions that * require large amounts of instrumentation will also notice significant runtime * slowdown to execute that instrumentation. Use this attribute to eliminate * those costs -- but only after carefully verifying that no overflow can occur. */ #ifdef MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR # define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW \ __attribute__((no_sanitize("unsigned-integer-overflow"))) #else # define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW /* nothing */ #endif /* * MOZ_NO_SANITIZE_SIGNED_OVERFLOW disables *signed* integer overflow checking * on the function it annotates, in builds configured to perform it. (Currently * this is only Clang using -fsanitize=signed-integer-overflow, or via * --enable-signed-overflow-sanitizer in Mozilla's build system. GCC support * will probably be added in the future.) It has no effect in other builds. * * Place this attribute at the very beginning of a function declaration. * * Signed integer overflow is undefined behavior in C/C++: *anything* can happen * when it occurs. *Maybe* wraparound behavior will occur, but maybe also the * compiler will assume no overflow happens and will adversely optimize the rest * of your code. Code that contains signed integer overflow needs to be fixed. * * The compiler instrumentation to detect signed integer overflow has costs both * at compile time and at runtime. Functions that are repeatedly inlined at * compile time will also implicitly inline the necessary instrumentation, * increasing compile time. Similarly, frequently-executed functions that * require large amounts of instrumentation will also notice significant runtime * slowdown to execute that instrumentation. Use this attribute to eliminate * those costs -- but only after carefully verifying that no overflow can occur. */ #ifdef MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR # define MOZ_NO_SANITIZE_SIGNED_OVERFLOW \ __attribute__((no_sanitize("signed-integer-overflow"))) #else # define MOZ_NO_SANITIZE_SIGNED_OVERFLOW /* nothing */ #endif #undef MOZ_HAVE_NO_SANITIZE_ATTR /** * MOZ_ALLOCATOR tells the compiler that the function it marks returns either a * "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the * block is not pointed to by any other reachable pointer in the program. * "Pointer-free" means that the block contains no pointers to any valid object * in the program. It may be initialized with other (non-pointer) values. * * Placing this attribute on appropriate functions helps GCC analyze pointer * aliasing more accurately in their callers. * * GCC warns if a caller ignores the value returned by a function marked with * MOZ_ALLOCATOR: it is hard to imagine cases where dropping the value returned * by a function that meets the criteria above would be intentional. * * Place this attribute after the argument list and 'this' qualifiers of a * function definition. For example, write * * void *my_allocator(size_t) MOZ_ALLOCATOR; * * or * * void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... } */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_ALLOCATOR __attribute__((malloc, warn_unused_result)) #else # define MOZ_ALLOCATOR #endif /** * MOZ_MUST_USE tells the compiler to emit a warning if a function's * return value is not used by the caller. * * Place this attribute at the very beginning of a function declaration. For * example, write * * MOZ_MUST_USE int foo(); * or * MOZ_MUST_USE int foo() { return 42; } * * MOZ_MUST_USE is most appropriate for functions where the return value is * some kind of success/failure indicator -- often |nsresult|, |bool| or |int| * -- because these functions are most commonly the ones that have missing * checks. There are three cases of note. * * - Fallible functions whose return values should always be checked. For * example, a function that opens a file should always be checked because any * subsequent operations on the file will fail if opening it fails. Such * functions should be given a MOZ_MUST_USE annotation. * * - Fallible functions whose return value need not always be checked. For * example, a function that closes a file might not be checked because it's * common that no further operations would be performed on the file. Such * functions do not need a MOZ_MUST_USE annotation. * * - Infallible functions, i.e. ones that always return a value indicating * success. These do not need a MOZ_MUST_USE annotation. Ideally, they would * be converted to not return a success/failure indicator, though sometimes * interface constraints prevent this. */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_MUST_USE __attribute__((warn_unused_result)) #else # define MOZ_MUST_USE #endif /** * MOZ_MAYBE_UNUSED suppresses compiler warnings about functions that are * never called (in this build configuration, at least). * * Place this attribute at the very beginning of a function declaration. For * example, write * * MOZ_MAYBE_UNUSED int foo(); * * or * * MOZ_MAYBE_UNUSED int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) # define MOZ_MAYBE_UNUSED __attribute__((__unused__)) #elif defined(_MSC_VER) # define MOZ_MAYBE_UNUSED __pragma(warning(suppress : 4505)) #else # define MOZ_MAYBE_UNUSED #endif #ifdef __cplusplus /** * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch * cases that fall through without a break or return statement. MOZ_FALLTHROUGH * is only needed on cases that have code. * * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in * debug builds, but intentionally fall through in release builds. See comment * in Assertions.h for more details. * * switch (foo) { * case 1: // These cases have no code. No fallthrough annotations are needed. * case 2: * case 3: // This case has code, so a fallthrough annotation is needed! * foo++; * MOZ_FALLTHROUGH; * case 4: * return foo; * * default: * // This case asserts in debug builds, falls through in release. * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); * case 5: * return 5; * } */ # ifndef __has_cpp_attribute # define __has_cpp_attribute(x) 0 # endif # if __has_cpp_attribute(clang::fallthrough) # define MOZ_FALLTHROUGH [[clang::fallthrough]] # elif __has_cpp_attribute(gnu::fallthrough) # define MOZ_FALLTHROUGH [[gnu::fallthrough]] # elif defined(_MSC_VER) /* * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx */ # include <sal.h> # define MOZ_FALLTHROUGH __fallthrough # else # define MOZ_FALLTHROUGH /* FALLTHROUGH */ # endif /** * C++11 lets unions contain members that have non-trivial special member * functions (default/copy/move constructor, copy/move assignment operator, * destructor) if the user defines the corresponding functions on the union. * (Such user-defined functions must rely on external knowledge about which arm * is active to be safe. Be extra-careful defining these functions!) * * MSVC unfortunately warns/errors for this bog-standard C++11 pattern. Use * these macro-guards around such member functions to disable the warnings: * * union U * { * std::string s; * int x; * * MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS * * // |U| must have a user-defined default constructor because |std::string| * // has a non-trivial default constructor. * U() ... { ... } * * // |U| must have a user-defined destructor because |std::string| has a * // non-trivial destructor. * ~U() { ... } * * MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS * }; */ # if defined(_MSC_VER) # define MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS \ __pragma(warning(push)) __pragma(warning(disable : 4582)) \ __pragma(warning(disable : 4583)) # define MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS __pragma(warning(pop)) # else # define MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS /* nothing */ # define MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS /* nothing */ # endif /* * The following macros are attributes that support the static analysis plugin * included with Mozilla, and will be implemented (when such support is enabled) * as C++11 attributes. Since such attributes are legal pretty much everywhere * and have subtly different semantics depending on their placement, the * following is a guide on where to place the attributes. * * Attributes that apply to a struct or class precede the name of the class: * (Note that this is different from the placement of final for classes!) * * class MOZ_CLASS_ATTRIBUTE SomeClass {}; * * Attributes that apply to functions follow the parentheses and const * qualifiers but precede final, override and the function body: * * void DeclaredFunction() MOZ_FUNCTION_ATTRIBUTE; * void SomeFunction() MOZ_FUNCTION_ATTRIBUTE {} * void PureFunction() const MOZ_FUNCTION_ATTRIBUTE = 0; * void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE override; * * Attributes that apply to variables or parameters follow the variable's name: * * int variable MOZ_VARIABLE_ATTRIBUTE; * * Attributes that apply to types follow the type name: * * typedef int MOZ_TYPE_ATTRIBUTE MagicInt; * int MOZ_TYPE_ATTRIBUTE someVariable; * int* MOZ_TYPE_ATTRIBUTE magicPtrInt; * int MOZ_TYPE_ATTRIBUTE* ptrToMagicInt; * * Attributes that apply to statements precede the statement: * * MOZ_IF_ATTRIBUTE if (x == 0) * MOZ_DO_ATTRIBUTE do { } while (0); * * Attributes that apply to labels precede the label: * * MOZ_LABEL_ATTRIBUTE target: * goto target; * MOZ_CASE_ATTRIBUTE case 5: * MOZ_DEFAULT_ATTRIBUTE default: * * The static analyses that are performed by the plugin are as follows: * * MOZ_CAN_RUN_SCRIPT: Applies to functions which can run script. Callers of * this function must also be marked as MOZ_CAN_RUN_SCRIPT, and all refcounted * arguments must be strongly held in the caller. Note that MOZ_CAN_RUN_SCRIPT * should only be applied to function declarations, not definitions. If you * need to apply it to a definition (eg because both are generated by a macro) * use MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION. * * MOZ_CAN_RUN_SCRIPT can be applied to XPIDL-generated declarations by * annotating the method or attribute as [can_run_script] in the .idl file. * * MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION: Same as MOZ_CAN_RUN_SCRIPT, but usable on * a definition. If the declaration is in a header file, users of that header * file may not see the annotation. * MOZ_CAN_RUN_SCRIPT_BOUNDARY: Applies to functions which need to call * MOZ_CAN_RUN_SCRIPT functions, but should not themselves be considered * MOZ_CAN_RUN_SCRIPT. This is important for some bindings and low level code * which need to opt out of the safety checks performed by MOZ_CAN_RUN_SCRIPT. * MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate * subclasses must provide an exact override of this method; if a subclass * does not override this method, the compiler will emit an error. This * attribute is not limited to virtual methods, so if it is applied to a * nonvirtual method and the subclass does not provide an equivalent * definition, the compiler will emit an error. * MOZ_STATIC_CLASS: Applies to all classes. Any class with this annotation is * expected to live in static memory, so it is a compile-time error to use * it, or an array of such objects, as the type of a variable declaration, or * as a temporary object, or as the type of a new expression (unless * placement new is being used). If a member of another class uses this * class, or if another class inherits from this class, then it is considered * to be a static class as well, although this attribute need not be provided * in such cases. * MOZ_STATIC_LOCAL_CLASS: Applies to all classes. Any class with this * annotation is expected to be a static local variable, so it is * a compile-time error to use it, or an array of such objects, or as a * temporary object, or as the type of a new expression. If another class * inherits from this class then it is considered to be a static local * class as well, although this attribute need not be provided in such cases. * It is also a compile-time error for any class with this annotation to have * a non-trivial destructor. * MOZ_STACK_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the stack, so it is a compile-time error to use it, or * an array of such objects, as a global or static variable, or as the type of * a new expression (unless placement new is being used). If a member of * another class uses this class, or if another class inherits from this * class, then it is considered to be a stack class as well, although this * attribute need not be provided in such cases. * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the stack or in static storage, so it is a compile-time * error to use it, or an array of such objects, as the type of a new * expression. If a member of another class uses this class, or if another * class inherits from this class, then it is considered to be a non-heap * class as well, although this attribute need not be provided in such cases. * MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the heap, so it is a compile-time error to use it, or * an array of such objects, as the type of a variable declaration, or as a * temporary object. If a member of another class uses this class, or if * another class inherits from this class, then it is considered to be a heap * class as well, although this attribute need not be provided in such cases. * MOZ_NON_TEMPORARY_CLASS: Applies to all classes. Any class with this * annotation is expected not to live in a temporary. If a member of another * class uses this class or if another class inherits from this class, then it * is considered to be a non-temporary class as well, although this attribute * need not be provided in such cases. * MOZ_TEMPORARY_CLASS: Applies to all classes. Any class with this annotation * is expected to only live in a temporary. If another class inherits from * this class, then it is considered to be a non-temporary class as well, * although this attribute need not be provided in such cases. * MOZ_RAII: Applies to all classes. Any class with this annotation is assumed * to be a RAII guard, which is expected to live on the stack in an automatic * allocation. It is prohibited from being allocated in a temporary, static * storage, or on the heap. This is a combination of MOZ_STACK_CLASS and * MOZ_NON_TEMPORARY_CLASS. * MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are * intended to prevent introducing static initializers. This attribute * currently makes it a compile-time error to instantiate these classes * anywhere other than at the global scope, or as a static member of a class. * In non-debug mode, it also prohibits non-trivial constructors and * destructors. * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial * or constexpr constructor and a trivial destructor. Setting this attribute * on a class makes it a compile-time error for that class to get a * non-trivial constructor or destructor for any reason. * MOZ_ALLOW_TEMPORARY: Applies to constructors. This indicates that using the * constructor is allowed in temporary expressions, if it would have otherwise * been forbidden by the type being a MOZ_NON_TEMPORARY_CLASS. Useful for * constructors like Maybe(Nothing). * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return * value is allocated on the heap, and will as a result check such allocations * during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking. * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors * are disallowed by default unless they are marked as MOZ_IMPLICIT. This * attribute must be used for constructors which intend to provide implicit * conversions. * MOZ_IS_REFPTR: Applies to class declarations of ref pointer to mark them as * such for use with static-analysis. * A ref pointer is an object wrapping a pointer and automatically taking care * of its refcounting upon construction/destruction/transfer of ownership. * This annotation implies MOZ_IS_SMARTPTR_TO_REFCOUNTED. * MOZ_IS_SMARTPTR_TO_REFCOUNTED: Applies to class declarations of smart * pointers to ref counted classes to mark them as such for use with * static-analysis. * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile * time error to pass arithmetic expressions on variables to the function. * MOZ_OWNING_REF: Applies to declarations of pointers to reference counted * types. This attribute tells the compiler that the raw pointer is a strong * reference, where ownership through methods such as AddRef and Release is * managed manually. This can make the compiler ignore these pointers when * validating the usage of pointers otherwise. * * Example uses include owned pointers inside of unions, and pointers stored * in POD types where a using a smart pointer class would make the object * non-POD. * MOZ_NON_OWNING_REF: Applies to declarations of pointers to reference counted * types. This attribute tells the compiler that the raw pointer is a weak * reference, which is ensured to be valid by a guarantee that the reference * will be nulled before the pointer becomes invalid. This can make the * compiler ignore these pointers when validating the usage of pointers * otherwise. * * Examples include an mOwner pointer, which is nulled by the owning class's * destructor, and is null-checked before dereferencing. * MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted * types. Occasionally there are non-owning references which are valid, but * do not take the form of a MOZ_NON_OWNING_REF. Their safety may be * dependent on the behaviour of API consumers. The string argument passed * to this macro documents the safety conditions. This can make the compiler * ignore these pointers when validating the usage of pointers elsewhere. * * Examples include an nsAtom* member which is known at compile time to point * to a static atom which is valid throughout the lifetime of the program, or * an API which stores a pointer, but doesn't take ownership over it, instead * requiring the API consumer to correctly null the value before it becomes * invalid. * * Use of this annotation is discouraged when a strong reference or one of * the above two annotations can be used instead. * MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it * a compile time error to call AddRef or Release on the return value of a * function. This is intended to be used with operator->() of our smart * pointer classes to ensure that the refcount of an object wrapped in a * smart pointer is not manipulated directly. * MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time * error to not use the return value of a function which has this type. This * is intended to be used with types which it is an error to not use. * MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it * a compile time error to instantiate this template with a type parameter * which has a VTable. * MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe * to be moved in memory using memmove(). * MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the * template arguments are required to be safe to move in memory using * memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a * compile time error. * MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member * must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types * used in members of these classes are compile time errors. * MOZ_NO_DANGLING_ON_TEMPORARIES: Applies to method declarations which return * a pointer that is freed when the destructor of the class is called. This * prevents these methods from being called on temporaries of the class, * reducing risks of use-after-free. * This attribute cannot be applied to && methods. * In some cases, adding a deleted &&-qualified overload is too restrictive as * this method should still be callable as a non-escaping argument to another * function. This annotation can be used in those cases. * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class * declarations where an instance of the template should be considered, for * static analysis purposes, to inherit any type annotations (such as * MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments. * MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally * there are class members that are not initialized in the constructor, * but logic elsewhere in the class ensures they are initialized prior to use. * Using this attribute on a member disables the check that this member must * be initialized in constructors via list-initialization, in the constructor * body, or via functions called from the constructor body. * MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the * constructor doesn't initialize all of the member variables and another * function is used to initialize the rest. This marker is used to make the * static analysis tool aware that the marked function is part of the * initialization process and to include the marked function in the scan * mechanism that determines which member variables still remain * uninitialized. * MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type * in parameter without pointer or reference. * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time * error to use `auto` in place of this type in variable declarations. This * is intended to be used with types which are intended to be implicitly * constructed into other other types before being assigned to variables. * MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations. * Sometimes derived classes override methods that need to be called by their * overridden counterparts. This marker indicates that the marked method must * be called by the method that it overrides. * MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG: Applies to method declarations. * Callers of the annotated method must return from that function within the * calling block using an explicit `return` statement if the "this" value for * the call is a parameter of the caller. Only calls to Constructors, * references to local and member variables, and calls to functions or methods * marked as MOZ_MAY_CALL_AFTER_MUST_RETURN may be made after the * MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG call. * MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations. * Calls to these methods may be made in functions after calls a * MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG method. */ // gcc emits a nuisance warning -Wignored-attributes because attributes do not // affect mangled names, and therefore template arguments do not propagate // their attributes. It is rare that this would affect anything in practice, // and most compilers are silent about it. Similarly, -Wattributes complains // about attributes being ignored during template instantiation. // // Be conservative and only suppress the warning when running in a // configuration where it would be emitted, namely when compiling with the // XGILL_PLUGIN for the rooting hazard analysis (which runs under gcc.) If we // end up wanting these attributes in general GCC builds, change this to // something like // // #if defined(__GNUC__) && ! defined(__clang__) // # ifdef XGILL_PLUGIN # pragma GCC diagnostic ignored "-Wignored-attributes" # pragma GCC diagnostic ignored "-Wattributes" # endif # if defined(MOZ_CLANG_PLUGIN) || defined(XGILL_PLUGIN) # define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script"))) # define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION \ __attribute__((annotate("moz_can_run_script"))) # define MOZ_CAN_RUN_SCRIPT_BOUNDARY \ __attribute__((annotate("moz_can_run_script_boundary"))) # define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) # define MOZ_STATIC_CLASS __attribute__((annotate("moz_global_class"))) # define MOZ_STATIC_LOCAL_CLASS \ __attribute__((annotate("moz_static_local_class"))) \ __attribute__((annotate("moz_trivial_dtor"))) # define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) # define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) # define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) # define MOZ_NON_TEMPORARY_CLASS \ __attribute__((annotate("moz_non_temporary_class"))) # define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class"))) # define MOZ_TRIVIAL_CTOR_DTOR \ __attribute__((annotate("moz_trivial_ctor_dtor"))) # define MOZ_ALLOW_TEMPORARY __attribute__((annotate("moz_allow_temporary"))) # ifdef DEBUG /* in debug builds, these classes do have non-trivial constructors. */ # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ __attribute__((annotate("moz_global_class"))) # else # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ __attribute__((annotate("moz_global_class"))) MOZ_TRIVIAL_CTOR_DTOR # endif # define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) # define MOZ_IS_SMARTPTR_TO_REFCOUNTED \ __attribute__((annotate("moz_is_smartptr_to_refcounted"))) # define MOZ_IS_REFPTR MOZ_IS_SMARTPTR_TO_REFCOUNTED # define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT \ __attribute__((annotate("moz_no_arith_expr_in_arg"))) # define MOZ_OWNING_REF # define MOZ_NON_OWNING_REF # define MOZ_UNSAFE_REF(reason) # define MOZ_NO_ADDREF_RELEASE_ON_RETURN \ __attribute__((annotate("moz_no_addref_release_on_return"))) # define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) # define MOZ_NEEDS_NO_VTABLE_TYPE \ __attribute__((annotate("moz_needs_no_vtable_type"))) # define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) # define MOZ_NEEDS_MEMMOVABLE_TYPE \ __attribute__((annotate("moz_needs_memmovable_type"))) # define MOZ_NEEDS_MEMMOVABLE_MEMBERS \ __attribute__((annotate("moz_needs_memmovable_members"))) # define MOZ_NO_DANGLING_ON_TEMPORARIES \ __attribute__((annotate("moz_no_dangling_on_temporaries"))) # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \ __attribute__( \ (annotate("moz_inherit_type_annotations_from_template_args"))) # define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable"))) # define MOZ_INIT_OUTSIDE_CTOR # define MOZ_IS_CLASS_INIT # define MOZ_NON_PARAM __attribute__((annotate("moz_non_param"))) # define MOZ_REQUIRED_BASE_METHOD \ __attribute__((annotate("moz_required_base_method"))) # define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG \ __attribute__((annotate("moz_must_return_from_caller_if_this_is_arg"))) # define MOZ_MAY_CALL_AFTER_MUST_RETURN \ __attribute__((annotate("moz_may_call_after_must_return"))) /* * It turns out that clang doesn't like void func() __attribute__ {} without a * warning, so use pragmas to disable the warning. */ # ifdef __clang__ # define MOZ_HEAP_ALLOCATOR \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((annotate("moz_heap_allocator"))) \ _Pragma("clang diagnostic pop") # else # define MOZ_HEAP_ALLOCATOR __attribute__((annotate("moz_heap_allocator"))) # endif # else # define MOZ_CAN_RUN_SCRIPT /* nothing */ # define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION /* nothing */ # define MOZ_CAN_RUN_SCRIPT_BOUNDARY /* nothing */ # define MOZ_MUST_OVERRIDE /* nothing */ # define MOZ_STATIC_CLASS /* nothing */ # define MOZ_STATIC_LOCAL_CLASS /* nothing */ # define MOZ_STACK_CLASS /* nothing */ # define MOZ_NONHEAP_CLASS /* nothing */ # define MOZ_HEAP_CLASS /* nothing */ # define MOZ_NON_TEMPORARY_CLASS /* nothing */ # define MOZ_TEMPORARY_CLASS /* nothing */ # define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ # define MOZ_ALLOW_TEMPORARY /* nothing */ # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ # define MOZ_IMPLICIT /* nothing */ # define MOZ_IS_SMARTPTR_TO_REFCOUNTED /* nothing */ # define MOZ_IS_REFPTR /* nothing */ # define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ # define MOZ_HEAP_ALLOCATOR /* nothing */ # define MOZ_OWNING_REF /* nothing */ # define MOZ_NON_OWNING_REF /* nothing */ # define MOZ_UNSAFE_REF(reason) /* nothing */ # define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */ # define MOZ_MUST_USE_TYPE /* nothing */ # define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */ # define MOZ_NON_MEMMOVABLE /* nothing */ # define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */ # define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */ # define MOZ_NO_DANGLING_ON_TEMPORARIES /* nothing */ # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */ # define MOZ_INIT_OUTSIDE_CTOR /* nothing */ # define MOZ_IS_CLASS_INIT /* nothing */ # define MOZ_NON_PARAM /* nothing */ # define MOZ_NON_AUTOABLE /* nothing */ # define MOZ_REQUIRED_BASE_METHOD /* nothing */ # define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG /* nothing */ # define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */ # endif /* defined(MOZ_CLANG_PLUGIN) || defined(XGILL_PLUGIN) */ # define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS // gcc has different rules governing attribute placement. Since none of these // attributes are actually used by the gcc-based static analysis, just // eliminate them rather than updating all of the code. # ifdef XGILL_PLUGIN # undef MOZ_MUST_OVERRIDE # define MOZ_MUST_OVERRIDE /* nothing */ # undef MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION # define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION /* nothing */ # endif #endif /* __cplusplus */ /** * Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a * function or method that is "printf-like"; this will let (some) * compilers check that the arguments match the template string. * * This macro takes two arguments. The first argument is the argument * number of the template string. The second argument is the argument * number of the '...' argument holding the arguments. * * Argument numbers start at 1. Note that the implicit "this" * argument of a non-static member function counts as an argument. * * So, for a simple case like: * void print_something (int whatever, const char *fmt, ...); * The corresponding annotation would be * MOZ_FORMAT_PRINTF(2, 3) * However, if "print_something" were a non-static member function, * then the annotation would be: * MOZ_FORMAT_PRINTF(3, 4) * * The second argument should be 0 for vprintf-like functions; that * is, those taking a va_list argument. * * Note that the checking is limited to standards-conforming * printf-likes, and in particular this should not be used for * PR_snprintf and friends, which are "printf-like" but which assign * different meanings to the various formats. * * MinGW requires special handling due to different format specifiers * on different platforms. The macro __MINGW_PRINTF_FORMAT maps to * either gnu_printf or ms_printf depending on where we are compiling * to avoid warnings on format specifiers that are legal. */ #ifdef __MINGW32__ # define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ __attribute__((format(__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck))) #elif __GNUC__ # define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ __attribute__((format(printf, stringIndex, firstToCheck))) #else # define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) #endif /** * To manually declare an XPCOM ABI-compatible virtual function, the following * macros can be used to handle the non-standard ABI used on Windows for COM * compatibility. E.g.: * * virtual ReturnType MOZ_XPCOM_ABI foo(); */ #if defined(XP_WIN) # define MOZ_XPCOM_ABI __stdcall #else # define MOZ_XPCOM_ABI #endif #endif /* mozilla_Attributes_h */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* mfbt foundational types and macros. */ #ifndef mozilla_Types_h # define mozilla_Types_h /* * This header must be valid C and C++, includable by code embedding either * SpiderMonkey or Gecko. */ /* Expose all <stdint.h> types and size_t. */ # include <stddef.h> # include <stdint.h> /* Implement compiler and linker macros needed for APIs. */ /* * MOZ_EXPORT is used to declare and define a symbol or type which is externally * visible to users of the current library. It encapsulates various decorations * needed to properly export the method's symbol. * * api.h: * extern MOZ_EXPORT int MeaningOfLife(void); * extern MOZ_EXPORT int LuggageCombination; * * api.c: * int MeaningOfLife(void) { return 42; } * int LuggageCombination = 12345; * * If you are merely sharing a method across files, just use plain |extern|. * These macros are designed for use by library interfaces -- not for normal * methods or data used cross-file. */ # if defined(WIN32) # define MOZ_EXPORT __declspec(dllexport) # else /* Unix */ # ifdef HAVE_VISIBILITY_ATTRIBUTE # define MOZ_EXPORT __attribute__((visibility("default"))) # elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) # define MOZ_EXPORT __global # else # define MOZ_EXPORT /* nothing */ # endif # endif /* * Whereas implementers use MOZ_EXPORT to declare and define library symbols, * users use MOZ_IMPORT_API and MOZ_IMPORT_DATA to access them. Most often the * implementer of the library will expose an API macro which expands to either * the export or import version of the macro, depending upon the compilation * mode. */ # ifdef _WIN32 # if defined(__MWERKS__) # define MOZ_IMPORT_API /* nothing */ # else # define MOZ_IMPORT_API __declspec(dllimport) # endif # else # define MOZ_IMPORT_API MOZ_EXPORT # endif # if defined(_WIN32) && !defined(__MWERKS__) # define MOZ_IMPORT_DATA __declspec(dllimport) # else # define MOZ_IMPORT_DATA MOZ_EXPORT # endif /* * Consistent with the above comment, the MFBT_API and MFBT_DATA macros expose * export mfbt declarations when building mfbt, and they expose import mfbt * declarations when using mfbt. */ # if defined(IMPL_MFBT) || \ (defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && \ (defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API))) # define MFBT_API MOZ_EXPORT # define MFBT_DATA MOZ_EXPORT # else # if defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && defined(STATIC_JS_API) # define MFBT_API # define MFBT_DATA # else /* * On linux mozglue is linked in the program and we link libxul.so with * -z,defs. Normally that causes the linker to reject undefined references in * libxul.so, but as a loophole it allows undefined references to weak * symbols. We add the weak attribute to the import version of the MFBT API * macros to exploit this. */ # if defined(MOZ_GLUE_IN_PROGRAM) # define MFBT_API __attribute__((weak)) MOZ_IMPORT_API # define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA # else # define MFBT_API MOZ_IMPORT_API # define MFBT_DATA MOZ_IMPORT_DATA # endif # endif # endif /* * C symbols in C++ code must be declared immediately within |extern "C"| * blocks. However, in C code, they need not be declared specially. This * difference is abstracted behind the MOZ_BEGIN_EXTERN_C and MOZ_END_EXTERN_C * macros, so that the user need not know whether he is being used in C or C++ * code. * * MOZ_BEGIN_EXTERN_C * * extern MOZ_EXPORT int MostRandomNumber(void); * ...other declarations... * * MOZ_END_EXTERN_C * * This said, it is preferable to just use |extern "C"| in C++ header files for * its greater clarity. */ # ifdef __cplusplus # define MOZ_BEGIN_EXTERN_C extern "C" { # define MOZ_END_EXTERN_C } # else # define MOZ_BEGIN_EXTERN_C # define MOZ_END_EXTERN_C # endif /* * GCC's typeof is available when decltype is not. */ # if defined(__GNUC__) && defined(__cplusplus) && \ !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L # define decltype __typeof__ # endif #endif /* mozilla_Types_h */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Template-based metaprogramming and type-testing facilities. */ #ifndef mozilla_TypeTraits_h #define mozilla_TypeTraits_h //#include "mozilla/Types.h" /* * These traits are approximate copies of the traits and semantics from C++11's * <type_traits> header. Don't add traits not in that header! When all * platforms provide that header, we can convert all users and remove this one. */ namespace mozilla { /* Forward declarations. */ template <typename> struct RemoveCV; template <typename> struct AddRvalueReference; /* 20.2.4 Function template declval [declval] */ /** * DeclVal simplifies the definition of expressions which occur as unevaluated * operands. It converts T to a reference type, making it possible to use in * decltype expressions even if T does not have a default constructor, e.g.: * decltype(DeclVal<TWithNoDefaultConstructor>().foo()) */ template <typename T> typename AddRvalueReference<T>::Type DeclVal(); /* 20.9.3 Helper classes [meta.help] */ /** * Helper class used as a base for various type traits, exposed publicly * because <type_traits> exposes it as well. */ template <typename T, T Value> struct IntegralConstant { static constexpr T value = Value; typedef T ValueType; typedef IntegralConstant<T, Value> Type; }; /** Convenient aliases. */ typedef IntegralConstant<bool, true> TrueType; typedef IntegralConstant<bool, false> FalseType; /* 20.9.4 Unary type traits [meta.unary] */ /* 20.9.4.1 Primary type categories [meta.unary.cat] */ namespace detail { template <typename T> struct IsVoidHelper : FalseType {}; template <> struct IsVoidHelper<void> : TrueType {}; } // namespace detail /** * IsVoid determines whether a type is void. * * mozilla::IsVoid<int>::value is false; * mozilla::IsVoid<void>::value is true; * mozilla::IsVoid<void*>::value is false; * mozilla::IsVoid<volatile void>::value is true. */ template <typename T> struct IsVoid : detail::IsVoidHelper<typename RemoveCV<T>::Type> {}; namespace detail { template <typename T> struct IsIntegralHelper : FalseType {}; template <> struct IsIntegralHelper<char> : TrueType {}; template <> struct IsIntegralHelper<signed char> : TrueType {}; template <> struct IsIntegralHelper<unsigned char> : TrueType {}; template <> struct IsIntegralHelper<short> : TrueType {}; template <> struct IsIntegralHelper<unsigned short> : TrueType {}; template <> struct IsIntegralHelper<int> : TrueType {}; template <> struct IsIntegralHelper<unsigned int> : TrueType {}; template <> struct IsIntegralHelper<long> : TrueType {}; template <> struct IsIntegralHelper<unsigned long> : TrueType {}; template <> struct IsIntegralHelper<long long> : TrueType {}; template <> struct IsIntegralHelper<unsigned long long> : TrueType {}; template <> struct IsIntegralHelper<bool> : TrueType {}; template <> struct IsIntegralHelper<wchar_t> : TrueType {}; template <> struct IsIntegralHelper<char16_t> : TrueType {}; template <> struct IsIntegralHelper<char32_t> : TrueType {}; } /* namespace detail */ /** * IsIntegral determines whether a type is an integral type. * * mozilla::IsIntegral<int>::value is true; * mozilla::IsIntegral<unsigned short>::value is true; * mozilla::IsIntegral<const long>::value is true; * mozilla::IsIntegral<int*>::value is false; * mozilla::IsIntegral<double>::value is false; */ template <typename T> struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type> {}; template <typename T, typename U> struct IsSame; namespace detail { template <typename T> struct IsFloatingPointHelper : IntegralConstant<bool, IsSame<T, float>::value || IsSame<T, double>::value || IsSame<T, long double>::value> {}; } // namespace detail /** * IsFloatingPoint determines whether a type is a floating point type (float, * double, long double). * * mozilla::IsFloatingPoint<int>::value is false; * mozilla::IsFloatingPoint<const float>::value is true; * mozilla::IsFloatingPoint<long double>::value is true; * mozilla::IsFloatingPoint<double*>::value is false. */ template <typename T> struct IsFloatingPoint : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type> {}; namespace detail { template <typename T> struct IsArrayHelper : FalseType {}; template <typename T, decltype(sizeof(1)) N> struct IsArrayHelper<T[N]> : TrueType {}; template <typename T> struct IsArrayHelper<T[]> : TrueType {}; } // namespace detail /** * IsArray determines whether a type is an array type, of known or unknown * length. * * mozilla::IsArray<int>::value is false; * mozilla::IsArray<int[]>::value is true; * mozilla::IsArray<int[5]>::value is true. */ template <typename T> struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type> {}; namespace detail { template <typename T> struct IsFunPtr; template <typename> struct IsFunPtr : public FalseType {}; template <typename Result, typename... ArgTypes> struct IsFunPtr<Result (*)(ArgTypes...)> : public TrueType {}; }; // namespace detail /** * IsFunction determines whether a type is a function type. Function pointers * don't qualify here--only the type of an actual function symbol. We do not * correctly handle varags function types because of a bug in MSVC. * * Given the function: * void f(int) {} * * mozilla::IsFunction<void(int)> is true; * mozilla::IsFunction<void(*)(int)> is false; * mozilla::IsFunction<decltype(f)> is true. */ template <typename T> struct IsFunction : public detail::IsFunPtr<typename RemoveCV<T>::Type*> {}; namespace detail { template <typename T> struct IsPointerHelper : FalseType {}; template <typename T> struct IsPointerHelper<T*> : TrueType {}; } // namespace detail /** * IsPointer determines whether a type is a possibly-CV-qualified pointer type * (but not a pointer-to-member type). * * mozilla::IsPointer<struct S*>::value is true; * mozilla::IsPointer<int*>::value is true; * mozilla::IsPointer<int**>::value is true; * mozilla::IsPointer<const int*>::value is true; * mozilla::IsPointer<int* const>::value is true; * mozilla::IsPointer<int* volatile>::value is true; * mozilla::IsPointer<void (*)(void)>::value is true; * mozilla::IsPointer<int>::value is false; * mozilla::IsPointer<struct S>::value is false. * mozilla::IsPointer<int(struct S::*)>::value is false */ template <typename T> struct IsPointer : detail::IsPointerHelper<typename RemoveCV<T>::Type> {}; /** * IsLvalueReference determines whether a type is an lvalue reference. * * mozilla::IsLvalueReference<struct S*>::value is false; * mozilla::IsLvalueReference<int**>::value is false; * mozilla::IsLvalueReference<void (*)(void)>::value is false; * mozilla::IsLvalueReference<int>::value is false; * mozilla::IsLvalueReference<struct S>::value is false; * mozilla::IsLvalueReference<struct S*&>::value is true; * mozilla::IsLvalueReference<struct S&&>::value is false. */ template <typename T> struct IsLvalueReference : FalseType {}; template <typename T> struct IsLvalueReference<T&> : TrueType {}; /** * IsRvalueReference determines whether a type is an rvalue reference. * * mozilla::IsRvalueReference<struct S*>::value is false; * mozilla::IsRvalueReference<int**>::value is false; * mozilla::IsRvalueReference<void (*)(void)>::value is false; * mozilla::IsRvalueReference<int>::value is false; * mozilla::IsRvalueReference<struct S>::value is false; * mozilla::IsRvalueReference<struct S*&>::value is false; * mozilla::IsRvalueReference<struct S&&>::value is true. */ template <typename T> struct IsRvalueReference : FalseType {}; template <typename T> struct IsRvalueReference<T&&> : TrueType {}; namespace detail { // __is_enum is a supported extension across all of our supported compilers. template <typename T> struct IsEnumHelper : IntegralConstant<bool, __is_enum(T)> {}; } // namespace detail /** * IsEnum determines whether a type is an enum type. * * mozilla::IsEnum<enum S>::value is true; * mozilla::IsEnum<enum S*>::value is false; * mozilla::IsEnum<int>::value is false; */ template <typename T> struct IsEnum : detail::IsEnumHelper<typename RemoveCV<T>::Type> {}; namespace detail { // __is_class is a supported extension across all of our supported compilers: // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx template <typename T> struct IsClassHelper : IntegralConstant<bool, __is_class(T)> {}; } // namespace detail /** * IsClass determines whether a type is a class type (but not a union). * * struct S {}; * union U {}; * mozilla::IsClass<int>::value is false; * mozilla::IsClass<const S>::value is true; * mozilla::IsClass<U>::value is false; */ template <typename T> struct IsClass : detail::IsClassHelper<typename RemoveCV<T>::Type> {}; /* 20.9.4.2 Composite type traits [meta.unary.comp] */ /** * IsReference determines whether a type is an lvalue or rvalue reference. * * mozilla::IsReference<struct S*>::value is false; * mozilla::IsReference<int**>::value is false; * mozilla::IsReference<int&>::value is true; * mozilla::IsReference<void (*)(void)>::value is false; * mozilla::IsReference<const int&>::value is true; * mozilla::IsReference<int>::value is false; * mozilla::IsReference<struct S>::value is false; * mozilla::IsReference<struct S&>::value is true; * mozilla::IsReference<struct S*&>::value is true; * mozilla::IsReference<struct S&&>::value is true. */ template <typename T> struct IsReference : IntegralConstant<bool, IsLvalueReference<T>::value || IsRvalueReference<T>::value> {}; /** * IsArithmetic determines whether a type is arithmetic. A type is arithmetic * iff it is an integral type or a floating point type. * * mozilla::IsArithmetic<int>::value is true; * mozilla::IsArithmetic<double>::value is true; * mozilla::IsArithmetic<long double*>::value is false. */ template <typename T> struct IsArithmetic : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value> {}; namespace detail { template <typename T> struct IsMemberPointerHelper : FalseType {}; template <typename T, typename U> struct IsMemberPointerHelper<T U::*> : TrueType {}; } // namespace detail /** * IsMemberPointer determines whether a type is pointer to non-static member * object or a pointer to non-static member function. * * mozilla::IsMemberPointer<int(cls::*)>::value is true * mozilla::IsMemberPointer<int*>::value is false */ template <typename T> struct IsMemberPointer : detail::IsMemberPointerHelper<typename RemoveCV<T>::Type> {}; /** * IsScalar determines whether a type is a scalar type. * * mozilla::IsScalar<int>::value is true * mozilla::IsScalar<int*>::value is true * mozilla::IsScalar<cls>::value is false */ template <typename T> struct IsScalar : IntegralConstant<bool, IsArithmetic<T>::value || IsEnum<T>::value || IsPointer<T>::value || IsMemberPointer<T>::value> {}; /* 20.9.4.3 Type properties [meta.unary.prop] */ /** * IsConst determines whether a type is const or not. * * mozilla::IsConst<int>::value is false; * mozilla::IsConst<void* const>::value is true; * mozilla::IsConst<const char*>::value is false. */ template <typename T> struct IsConst : FalseType {}; template <typename T> struct IsConst<const T> : TrueType {}; /** * IsVolatile determines whether a type is volatile or not. * * mozilla::IsVolatile<int>::value is false; * mozilla::IsVolatile<void* volatile>::value is true; * mozilla::IsVolatile<volatile char*>::value is false. */ template <typename T> struct IsVolatile : FalseType {}; template <typename T> struct IsVolatile<volatile T> : TrueType {}; /** * Traits class for identifying POD types. Until C++11 there's no automatic * way to detect PODs, so for the moment this is done manually. Users may * define specializations of this class that inherit from mozilla::TrueType and * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or * false>, or conveniently from mozilla::IsPod for composite types) as needed to * ensure correct IsPod behavior. */ template <typename T> struct IsPod : public FalseType {}; template <> struct IsPod<char> : TrueType {}; template <> struct IsPod<signed char> : TrueType {}; template <> struct IsPod<unsigned char> : TrueType {}; template <> struct IsPod<short> : TrueType {}; template <> struct IsPod<unsigned short> : TrueType {}; template <> struct IsPod<int> : TrueType {}; template <> struct IsPod<unsigned int> : TrueType {}; template <> struct IsPod<long> : TrueType {}; template <> struct IsPod<unsigned long> : TrueType {}; template <> struct IsPod<long long> : TrueType {}; template <> struct IsPod<unsigned long long> : TrueType {}; template <> struct IsPod<bool> : TrueType {}; template <> struct IsPod<float> : TrueType {}; template <> struct IsPod<double> : TrueType {}; template <> struct IsPod<wchar_t> : TrueType {}; template <> struct IsPod<char16_t> : TrueType {}; template <typename T> struct IsPod<T*> : TrueType {}; namespace detail { // __is_empty is a supported extension across all of our supported compilers: // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx template <typename T> struct IsEmptyHelper : IntegralConstant<bool, IsClass<T>::value&& __is_empty(T)> {}; } // namespace detail /** * IsEmpty determines whether a type is a class (but not a union) that is empty. * * A class is empty iff it and all its base classes have no non-static data * members (except bit-fields of length 0) and no virtual member functions, and * no base class is empty or a virtual base class. * * Intuitively, empty classes don't have any data that has to be stored in * instances of those classes. (The size of the class must still be non-zero, * because distinct array elements of any type must have different addresses. * However, if the Empty Base Optimization is implemented by the compiler [most * compilers implement it, and in certain cases C++11 requires it], the size of * a class inheriting from an empty |Base| class need not be inflated by * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or * vtable pointers that must be stored in each instance for proper behavior. * * static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty"); * union U1 { int x; }; * static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty"); * struct E1 {}; * struct E2 { int : 0 }; * struct E3 : E1 {}; * struct E4 : E2 {}; * static_assert(mozilla::IsEmpty<E1>::value && * mozilla::IsEmpty<E2>::value && * mozilla::IsEmpty<E3>::value && * mozilla::IsEmpty<E4>::value, * "all empty"); * union U2 { E1 e1; }; * static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty"); * struct NE1 { int x; }; * struct NE2 : virtual E1 {}; * struct NE3 : E2 { virtual ~NE3() {} }; * struct NE4 { virtual void f() {} }; * static_assert(!mozilla::IsEmpty<NE1>::value && * !mozilla::IsEmpty<NE2>::value && * !mozilla::IsEmpty<NE3>::value && * !mozilla::IsEmpty<NE4>::value, * "all empty"); */ template <typename T> struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type> {}; namespace detail { template <typename T, bool = IsFloatingPoint<T>::value, bool = IsIntegral<T>::value, typename NoCV = typename RemoveCV<T>::Type> struct IsSignedHelper; // Floating point is signed. template <typename T, typename NoCV> struct IsSignedHelper<T, true, false, NoCV> : TrueType {}; // Integral is conditionally signed. template <typename T, typename NoCV> struct IsSignedHelper<T, false, true, NoCV> : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))> {}; // Non-floating point, non-integral is not signed. template <typename T, typename NoCV> struct IsSignedHelper<T, false, false, NoCV> : FalseType {}; } // namespace detail /** * IsSigned determines whether a type is a signed arithmetic type. |char| is * considered a signed type if it has the same representation as |signed char|. * * mozilla::IsSigned<int>::value is true; * mozilla::IsSigned<const unsigned int>::value is false; * mozilla::IsSigned<unsigned char>::value is false; * mozilla::IsSigned<float>::value is true. */ template <typename T> struct IsSigned : detail::IsSignedHelper<T> {}; namespace detail { template <typename T, bool = IsFloatingPoint<T>::value, bool = IsIntegral<T>::value, typename NoCV = typename RemoveCV<T>::Type> struct IsUnsignedHelper; // Floating point is not unsigned. template <typename T, typename NoCV> struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {}; // Integral is conditionally unsigned. template <typename T, typename NoCV> struct IsUnsignedHelper<T, false, true, NoCV> : IntegralConstant<bool, (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))> {}; // Non-floating point, non-integral is not unsigned. template <typename T, typename NoCV> struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {}; } // namespace detail /** * IsUnsigned determines whether a type is an unsigned arithmetic type. * * mozilla::IsUnsigned<int>::value is false; * mozilla::IsUnsigned<const unsigned int>::value is true; * mozilla::IsUnsigned<unsigned char>::value is true; * mozilla::IsUnsigned<float>::value is false. */ template <typename T> struct IsUnsigned : detail::IsUnsignedHelper<T> {}; namespace detail { struct DoIsDefaultConstructibleImpl { template <typename T, typename = decltype(T())> static TrueType test(int); template <typename T> static FalseType test(...); }; template <typename T> struct IsDefaultConstructibleImpl : public DoIsDefaultConstructibleImpl { typedef decltype(test<T>(0)) Type; }; } // namespace detail /** * IsDefaultConstructible determines whether a type has a public default * constructor. * * struct S0 {}; // Implicit default constructor. * struct S1 { S1(); }; * struct S2 { explicit S2(int); }; // No implicit default constructor when * // another one is present. * struct S3 { S3() = delete; }; * class C4 { C4(); }; // Default constructor is private. * * mozilla::IsDefaultConstructible<int>::value is true; * mozilla::IsDefaultConstructible<S0>::value is true; * mozilla::IsDefaultConstructible<S1>::value is true; * mozilla::IsDefaultConstructible<S2>::value is false; * mozilla::IsDefaultConstructible<S3>::value is false; * mozilla::IsDefaultConstructible<S4>::value is false. */ template <typename T> struct IsDefaultConstructible : public detail::IsDefaultConstructibleImpl<T>::Type {}; namespace detail { struct DoIsDestructibleImpl { template <typename T, typename = decltype(DeclVal<T&>().~T())> static TrueType test(int); template <typename T> static FalseType test(...); }; template <typename T> struct IsDestructibleImpl : public DoIsDestructibleImpl { typedef decltype(test<T>(0)) Type; }; } // namespace detail /** * IsDestructible determines whether a type has a public destructor. * * struct S0 {}; // Implicit default destructor. * struct S1 { ~S1(); }; * class C2 { ~C2(); }; // private destructor. * * mozilla::IsDestructible<S0>::value is true; * mozilla::IsDestructible<S1>::value is true; * mozilla::IsDestructible<C2>::value is false. */ template <typename T> struct IsDestructible : public detail::IsDestructibleImpl<T>::Type {}; /* 20.9.5 Type property queries [meta.unary.prop.query] */ /* 20.9.6 Relationships between types [meta.rel] */ /** * IsSame tests whether two types are the same type. * * mozilla::IsSame<int, int>::value is true; * mozilla::IsSame<int*, int*>::value is true; * mozilla::IsSame<int, unsigned int>::value is false; * mozilla::IsSame<void, void>::value is true; * mozilla::IsSame<const int, int>::value is false; * mozilla::IsSame<struct S, struct S>::value is true. */ template <typename T, typename U> struct IsSame : FalseType {}; template <typename T> struct IsSame<T, T> : TrueType {}; namespace detail { #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) template <class Base, class Derived> struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {}; #else // The trickery used to implement IsBaseOf here makes it possible to use it for // the cases of private and multiple inheritance. This code was inspired by the // sample code here: // // http://stackoverflow.com/questions/2910979/how-is-base-of-works template <class Base, class Derived> struct BaseOfHelper { public: operator Base*() const; operator Derived*(); }; template <class Base, class Derived> struct BaseOfTester { private: template <class T> static char test(Derived*, T); static int test(Base*, int); public: static const bool value = sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char); }; template <class Base, class Derived> struct BaseOfTester<Base, const Derived> { private: template <class T> static char test(Derived*, T); static int test(Base*, int); public: static const bool value = sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char); }; template <class Base, class Derived> struct BaseOfTester<Base&, Derived&> : FalseType {}; template <class Type> struct BaseOfTester<Type, Type> : TrueType {}; template <class Type> struct BaseOfTester<Type, const Type> : TrueType {}; #endif } /* namespace detail */ /* * IsBaseOf allows to know whether a given class is derived from another. * * Consider the following class definitions: * * class A {}; * class B : public A {}; * class C {}; * * mozilla::IsBaseOf<A, A>::value is true; * mozilla::IsBaseOf<A, B>::value is true; * mozilla::IsBaseOf<A, C>::value is false; */ template <class Base, class Derived> struct IsBaseOf : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value> {}; namespace detail { template <typename From, typename To> struct ConvertibleTester { private: template <typename To1> static char test_helper(To1); template <typename From1, typename To1> static decltype(test_helper<To1>(DeclVal<From1>())) test(int); template <typename From1, typename To1> static int test(...); public: static const bool value = sizeof(test<From, To>(0)) == sizeof(char); }; } // namespace detail /** * IsConvertible determines whether a value of type From will implicitly convert * to a value of type To. For example: * * struct A {}; * struct B : public A {}; * struct C {}; * * mozilla::IsConvertible<A, A>::value is true; * mozilla::IsConvertible<A*, A*>::value is true; * mozilla::IsConvertible<B, A>::value is true; * mozilla::IsConvertible<B*, A*>::value is true; * mozilla::IsConvertible<C, A>::value is false; * mozilla::IsConvertible<A, C>::value is false; * mozilla::IsConvertible<A*, C*>::value is false; * mozilla::IsConvertible<C*, A*>::value is false. * * For obscure reasons, you can't use IsConvertible when the types being tested * are related through private inheritance, and you'll get a compile error if * you try. Just don't do it! * * Note - we need special handling for void, which ConvertibleTester doesn't * handle. The void handling here doesn't handle const/volatile void correctly, * which could be easily fixed if the need arises. */ template <typename From, typename To> struct IsConvertible : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value> {}; template <typename B> struct IsConvertible<void, B> : IntegralConstant<bool, IsVoid<B>::value> {}; template <typename A> struct IsConvertible<A, void> : IntegralConstant<bool, IsVoid<A>::value> {}; template <> struct IsConvertible<void, void> : TrueType {}; /* 20.9.7 Transformations between types [meta.trans] */ /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */ /** * RemoveConst removes top-level const qualifications on a type. * * mozilla::RemoveConst<int>::Type is int; * mozilla::RemoveConst<const int>::Type is int; * mozilla::RemoveConst<const int*>::Type is const int*; * mozilla::RemoveConst<int* const>::Type is int*. */ template <typename T> struct RemoveConst { typedef T Type; }; template <typename T> struct RemoveConst<const T> { typedef T Type; }; /** * RemoveVolatile removes top-level volatile qualifications on a type. * * mozilla::RemoveVolatile<int>::Type is int; * mozilla::RemoveVolatile<volatile int>::Type is int; * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*; * mozilla::RemoveVolatile<int* volatile>::Type is int*. */ template <typename T> struct RemoveVolatile { typedef T Type; }; template <typename T> struct RemoveVolatile<volatile T> { typedef T Type; }; /** * RemoveCV removes top-level const and volatile qualifications on a type. * * mozilla::RemoveCV<int>::Type is int; * mozilla::RemoveCV<const int>::Type is int; * mozilla::RemoveCV<volatile int>::Type is int; * mozilla::RemoveCV<int* const volatile>::Type is int*. */ template <typename T> struct RemoveCV { typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type; }; /* 20.9.7.2 Reference modifications [meta.trans.ref] */ /** * Converts reference types to the underlying types. * * mozilla::RemoveReference<T>::Type is T; * mozilla::RemoveReference<T&>::Type is T; * mozilla::RemoveReference<T&&>::Type is T; */ template <typename T> struct RemoveReference { typedef T Type; }; template <typename T> struct RemoveReference<T&> { typedef T Type; }; template <typename T> struct RemoveReference<T&&> { typedef T Type; }; template <bool Condition, typename A, typename B> struct Conditional; namespace detail { enum Voidness { TIsVoid, TIsNotVoid }; template <typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid> struct AddLvalueReferenceHelper; template <typename T> struct AddLvalueReferenceHelper<T, TIsVoid> { typedef void Type; }; template <typename T> struct AddLvalueReferenceHelper<T, TIsNotVoid> { typedef T& Type; }; } // namespace detail /** * AddLvalueReference adds an lvalue & reference to T if one isn't already * present. (Note: adding an lvalue reference to an rvalue && reference in * essence replaces the && with a &&, per C+11 reference collapsing rules. For * example, int&& would become int&.) * * The final computed type will only *not* be an lvalue reference if T is void. * * mozilla::AddLvalueReference<int>::Type is int&; * mozilla::AddLvalueRference<volatile int&>::Type is volatile int&; * mozilla::AddLvalueReference<void*>::Type is void*&; * mozilla::AddLvalueReference<void>::Type is void; * mozilla::AddLvalueReference<struct S&&>::Type is struct S&. */ template <typename T> struct AddLvalueReference : detail::AddLvalueReferenceHelper<T> {}; namespace detail { template <typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid> struct AddRvalueReferenceHelper; template <typename T> struct AddRvalueReferenceHelper<T, TIsVoid> { typedef void Type; }; template <typename T> struct AddRvalueReferenceHelper<T, TIsNotVoid> { typedef T&& Type; }; } // namespace detail /** * AddRvalueReference adds an rvalue && reference to T if one isn't already * present. (Note: adding an rvalue reference to an lvalue & reference in * essence keeps the &, per C+11 reference collapsing rules. For example, * int& would remain int&.) * * The final computed type will only *not* be a reference if T is void. * * mozilla::AddRvalueReference<int>::Type is int&&; * mozilla::AddRvalueRference<volatile int&>::Type is volatile int&; * mozilla::AddRvalueRference<const int&&>::Type is const int&&; * mozilla::AddRvalueReference<void*>::Type is void*&&; * mozilla::AddRvalueReference<void>::Type is void; * mozilla::AddRvalueReference<struct S&>::Type is struct S&. */ template <typename T> struct AddRvalueReference : detail::AddRvalueReferenceHelper<T> {}; /* 20.9.7.3 Sign modifications [meta.trans.sign] */ template <bool B, typename T = void> struct EnableIf; namespace detail { template <bool MakeConst, typename T> struct WithC : Conditional<MakeConst, const T, T> {}; template <bool MakeVolatile, typename T> struct WithV : Conditional<MakeVolatile, volatile T, T> {}; template <bool MakeConst, bool MakeVolatile, typename T> struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type> {}; template <typename T> struct CorrespondingSigned; template <> struct CorrespondingSigned<char> { typedef signed char Type; }; template <> struct CorrespondingSigned<unsigned char> { typedef signed char Type; }; template <> struct CorrespondingSigned<unsigned short> { typedef short Type; }; template <> struct CorrespondingSigned<unsigned int> { typedef int Type; }; template <> struct CorrespondingSigned<unsigned long> { typedef long Type; }; template <> struct CorrespondingSigned<unsigned long long> { typedef long long Type; }; template <typename T, typename CVRemoved = typename RemoveCV<T>::Type, bool IsSignedIntegerType = IsSigned<CVRemoved>::value && !IsSame<char, CVRemoved>::value> struct MakeSigned; template <typename T, typename CVRemoved> struct MakeSigned<T, CVRemoved, true> { typedef T Type; }; template <typename T, typename CVRemoved> struct MakeSigned<T, CVRemoved, false> : WithCV<IsConst<T>::value, IsVolatile<T>::value, typename CorrespondingSigned<CVRemoved>::Type> {}; } // namespace detail /** * MakeSigned produces the corresponding signed integer type for a given * integral type T, with the const/volatile qualifiers of T. T must be a * possibly-const/volatile-qualified integral type that isn't bool. * * If T is already a signed integer type (not including char!), then T is * produced. * * Otherwise, if T is an unsigned integer type, the signed variety of T, with * T's const/volatile qualifiers, is produced. * * Otherwise, the integral type of the same size as T, with the lowest rank, * with T's const/volatile qualifiers, is produced. (This basically only acts * to produce signed char when T = char.) * * mozilla::MakeSigned<unsigned long>::Type is signed long; * mozilla::MakeSigned<volatile int>::Type is volatile int; * mozilla::MakeSigned<const unsigned short>::Type is const signed short; * mozilla::MakeSigned<const char>::Type is const signed char; * mozilla::MakeSigned<bool> is an error; * mozilla::MakeSigned<void*> is an error. */ template <typename T> struct MakeSigned : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value, typename detail::MakeSigned<T> >::Type {}; namespace detail { template <typename T> struct CorrespondingUnsigned; template <> struct CorrespondingUnsigned<char> { typedef unsigned char Type; }; template <> struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; }; template <> struct CorrespondingUnsigned<short> { typedef unsigned short Type; }; template <> struct CorrespondingUnsigned<int> { typedef unsigned int Type; }; template <> struct CorrespondingUnsigned<long> { typedef unsigned long Type; }; template <> struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; }; template <typename T, typename CVRemoved = typename RemoveCV<T>::Type, bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value && !IsSame<char, CVRemoved>::value> struct MakeUnsigned; template <typename T, typename CVRemoved> struct MakeUnsigned<T, CVRemoved, true> { typedef T Type; }; template <typename T, typename CVRemoved> struct MakeUnsigned<T, CVRemoved, false> : WithCV<IsConst<T>::value, IsVolatile<T>::value, typename CorrespondingUnsigned<CVRemoved>::Type> {}; } // namespace detail /** * MakeUnsigned produces the corresponding unsigned integer type for a given * integral type T, with the const/volatile qualifiers of T. T must be a * possibly-const/volatile-qualified integral type that isn't bool. * * If T is already an unsigned integer type (not including char!), then T is * produced. * * Otherwise, if T is an signed integer type, the unsigned variety of T, with * T's const/volatile qualifiers, is produced. * * Otherwise, the unsigned integral type of the same size as T, with the lowest * rank, with T's const/volatile qualifiers, is produced. (This basically only * acts to produce unsigned char when T = char.) * * mozilla::MakeUnsigned<signed long>::Type is unsigned long; * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int; * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short; * mozilla::MakeUnsigned<const char>::Type is const unsigned char; * mozilla::MakeUnsigned<bool> is an error; * mozilla::MakeUnsigned<void*> is an error. */ template <typename T> struct MakeUnsigned : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value, typename detail::MakeUnsigned<T> >::Type {}; /* 20.9.7.4 Array modifications [meta.trans.arr] */ /** * RemoveExtent produces either the type of the elements of the array T, or T * itself. * * mozilla::RemoveExtent<int>::Type is int; * mozilla::RemoveExtent<const int[]>::Type is const int; * mozilla::RemoveExtent<volatile int[5]>::Type is volatile int; * mozilla::RemoveExtent<long[][17]>::Type is long[17]. */ template <typename T> struct RemoveExtent { typedef T Type; }; template <typename T> struct RemoveExtent<T[]> { typedef T Type; }; template <typename T, decltype(sizeof(1)) N> struct RemoveExtent<T[N]> { typedef T Type; }; /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ namespace detail { template <typename T, typename CVRemoved> struct RemovePointerHelper { typedef T Type; }; template <typename T, typename Pointee> struct RemovePointerHelper<T, Pointee*> { typedef Pointee Type; }; } // namespace detail /** * Produces the pointed-to type if a pointer is provided, else returns the input * type. Note that this does not dereference pointer-to-member pointers. * * struct S { bool m; void f(); }; * mozilla::RemovePointer<int>::Type is int; * mozilla::RemovePointer<int*>::Type is int; * mozilla::RemovePointer<int* const>::Type is int; * mozilla::RemovePointer<int* volatile>::Type is int; * mozilla::RemovePointer<const long*>::Type is const long; * mozilla::RemovePointer<void* const>::Type is void; * mozilla::RemovePointer<void (S::*)()>::Type is void (S::*)(); * mozilla::RemovePointer<void (*)()>::Type is void(); * mozilla::RemovePointer<bool S::*>::Type is bool S::*. */ template <typename T> struct RemovePointer : detail::RemovePointerHelper<T, typename RemoveCV<T>::Type> {}; /** * Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants * std::add_pointer to work differently for function types. We don't implement * that behavior here. * * mozilla::AddPointer<int> is int*; * mozilla::AddPointer<int*> is int**; * mozilla::AddPointer<int&> is int*; * mozilla::AddPointer<int* const> is int** const. */ template <typename T> struct AddPointer { typedef typename RemoveReference<T>::Type* Type; }; /* 20.9.7.6 Other transformations [meta.trans.other] */ /** * EnableIf is a struct containing a typedef of T if and only if B is true. * * mozilla::EnableIf<true, int>::Type is int; * mozilla::EnableIf<false, int>::Type is a compile-time error. * * Use this template to implement SFINAE-style (Substitution Failure Is not An * Error) requirements. For example, you might use it to impose a restriction * on a template parameter: * * template<typename T> * class PodVector // vector optimized to store POD (memcpy-able) types * { * EnableIf<IsPod<T>::value, T>::Type* vector; * size_t length; * ... * }; */ template <bool B, typename T> struct EnableIf {}; template <typename T> struct EnableIf<true, T> { typedef T Type; }; /** * Conditional selects a class between two, depending on a given boolean value. * * mozilla::Conditional<true, A, B>::Type is A; * mozilla::Conditional<false, A, B>::Type is B; */ template <bool Condition, typename A, typename B> struct Conditional { typedef A Type; }; template <class A, class B> struct Conditional<false, A, B> { typedef B Type; }; namespace detail { template <typename U, bool IsArray = IsArray<U>::value, bool IsFunction = IsFunction<U>::value> struct DecaySelector; template <typename U> struct DecaySelector<U, false, false> { typedef typename RemoveCV<U>::Type Type; }; template <typename U> struct DecaySelector<U, true, false> { typedef typename RemoveExtent<U>::Type* Type; }; template <typename U> struct DecaySelector<U, false, true> { typedef typename AddPointer<U>::Type Type; }; }; // namespace detail /** * Strips const/volatile off a type and decays it from an lvalue to an * rvalue. So function types are converted to function pointers, arrays to * pointers, and references are removed. * * mozilla::Decay<int>::Type is int * mozilla::Decay<int&>::Type is int * mozilla::Decay<int&&>::Type is int * mozilla::Decay<const int&>::Type is int * mozilla::Decay<int[2]>::Type is int* * mozilla::Decay<int(int)>::Type is int(*)(int) */ template <typename T> class Decay : public detail::DecaySelector<typename RemoveReference<T>::Type> { }; } /* namespace mozilla */ #endif /* mozilla_TypeTraits_h */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* A class holding a pair of objects that tries to conserve storage space. */ #ifndef mozilla_Pair_h #define mozilla_Pair_h //#include "mozilla/Attributes.h" //#include "mozilla/Move.h" //#include "mozilla/TypeTraits.h" namespace mozilla { namespace detail { enum StorageType { AsBase, AsMember }; // Optimize storage using the Empty Base Optimization -- that empty base classes // don't take up space -- to optimize size when one or the other class is // stateless and can be used as a base class. // // The extra conditions on storage for B are necessary so that PairHelper won't // ambiguously inherit from either A or B, such that one or the other base class // would be inaccessible. template <typename A, typename B, detail::StorageType = IsEmpty<A>::value ? detail::AsBase : detail::AsMember, detail::StorageType = IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value ? detail::AsBase : detail::AsMember> struct PairHelper; template <typename A, typename B> struct PairHelper<A, B, AsMember, AsMember> { protected: template <typename AArg, typename BArg> PairHelper(AArg&& aA, BArg&& aB) : mFirstA(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(mSecondB, aOther.mSecondB); } private: A mFirstA; B mSecondB; }; template <typename A, typename B> struct PairHelper<A, B, AsMember, AsBase> : private B { protected: template <typename AArg, typename BArg> PairHelper(AArg&& aA, BArg&& aB) : B(std::forward<BArg>(aB)), mFirstA(std::forward<AArg>(aA)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return *this; } const B& second() const { return *this; } void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(static_cast<B&>(*this), static_cast<B&>(aOther)); } private: A mFirstA; }; template <typename A, typename B> struct PairHelper<A, B, AsBase, AsMember> : private A { protected: template <typename AArg, typename BArg> PairHelper(AArg&& aA, BArg&& aB) : A(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {} A& first() { return *this; } const A& first() const { return *this; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } void swap(PairHelper& aOther) { Swap(static_cast<A&>(*this), static_cast<A&>(aOther)); Swap(mSecondB, aOther.mSecondB); } private: B mSecondB; }; template <typename A, typename B> struct PairHelper<A, B, AsBase, AsBase> : private A, private B { protected: template <typename AArg, typename BArg> PairHelper(AArg&& aA, BArg&& aB) : A(std::forward<AArg>(aA)), B(std::forward<BArg>(aB)) {} A& first() { return static_cast<A&>(*this); } const A& first() const { return static_cast<A&>(*this); } B& second() { return static_cast<B&>(*this); } const B& second() const { return static_cast<B&>(*this); } void swap(PairHelper& aOther) { Swap(static_cast<A&>(*this), static_cast<A&>(aOther)); Swap(static_cast<B&>(*this), static_cast<B&>(aOther)); } }; } // namespace detail /** * Pair is the logical concatenation of an instance of A with an instance B. * Space is conserved when possible. Neither A nor B may be a final class. * * It's typically clearer to have individual A and B member fields. Except if * you want the space-conserving qualities of Pair, you're probably better off * not using this! * * No guarantees are provided about the memory layout of A and B, the order of * initialization or destruction of A and B, and so on. (This is approximately * required to optimize space usage.) The first/second names are merely * conceptual! */ template <typename A, typename B> struct Pair : private detail::PairHelper<A, B> { typedef typename detail::PairHelper<A, B> Base; public: template <typename AArg, typename BArg> Pair(AArg&& aA, BArg&& aB) : Base(std::forward<AArg>(aA), std::forward<BArg>(aB)) {} Pair(Pair&& aOther) : Base(std::move(aOther.first()), std::move(aOther.second())) {} Pair(const Pair& aOther) = default; Pair& operator=(Pair&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); first() = std::move(aOther.first()); second() = std::move(aOther.second()); return *this; } Pair& operator=(const Pair& aOther) = default; /** The A instance. */ using Base::first; /** The B instance. */ using Base::second; /** Swap this pair with another pair. */ void swap(Pair& aOther) { Base::swap(aOther); } }; template <typename A, class B> void Swap(Pair<A, B>& aX, Pair<A, B>& aY) { aX.swap(aY); } /** * MakePair allows you to construct a Pair instance using type inference. A call * like this: * * MakePair(Foo(), Bar()) * * will return a Pair<Foo, Bar>. */ template <typename A, typename B> Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type, typename RemoveCV<typename RemoveReference<B>::Type>::Type> MakePair(A&& aA, B&& aB) { return Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type, typename RemoveCV<typename RemoveReference<B>::Type>::Type>( std::forward<A>(aA), std::forward<B>(aB)); } } // namespace mozilla #endif /* mozilla_Pair_h */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Smart pointer managing sole ownership of a resource. */ #ifndef mozilla_UniquePtr_h #define mozilla_UniquePtr_h //#include "mozilla/Assertions.h" //#include "mozilla/Attributes.h" //#include "mozilla/Compiler.h" //#include "mozilla/Move.h" //#include "mozilla/Pair.h" //#include "mozilla/TypeTraits.h" namespace mozilla { template <typename T> class DefaultDelete; template <typename T, class D = DefaultDelete<T>> class UniquePtr; } // namespace mozilla namespace mozilla { namespace detail { struct HasPointerTypeHelper { template <class U> static double Test(...); template <class U> static char Test(typename U::pointer* = 0); }; template <class T> class HasPointerType : public IntegralConstant<bool, sizeof(HasPointerTypeHelper::Test<T>(0)) == 1> {}; template <class T, class D, bool = HasPointerType<D>::value> struct PointerTypeImpl { typedef typename D::pointer Type; }; template <class T, class D> struct PointerTypeImpl<T, D, false> { typedef T* Type; }; template <class T, class D> struct PointerType { typedef typename PointerTypeImpl<T, typename RemoveReference<D>::Type>::Type Type; }; } // namespace detail /** * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be * transferred out of a UniquePtr through explicit action, but otherwise the * resource is destroyed when the UniquePtr is destroyed. * * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr * obviously *can't* copy ownership of its singly-owned resource. So what * happens if you try to copy one? Bizarrely, ownership is implicitly * *transferred*, preserving single ownership but breaking code that assumes a * copy of an object is identical to the original. (This is why auto_ptr is * prohibited in STL containers.) * * UniquePtr solves this problem by being *movable* rather than copyable. * Instead of passing a |UniquePtr u| directly to the constructor or assignment * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* * ownership out of |u|, into the target of the construction/assignment. After * the transfer completes, |u| contains |nullptr| and may be safely destroyed. * This preserves single ownership but also allows UniquePtr to be moved by * algorithms that have been made move-safe. (Note: if |u| is instead a * temporary expression, don't use |Move()|: just pass the expression, because * it's already move-ready. For more information see Move.h.) * * UniquePtr is also better than std::auto_ptr in that the deletion operation is * customizable. An optional second template parameter specifies a class that * (through its operator()(T*)) implements the desired deletion policy. If no * policy is specified, mozilla::DefaultDelete<T> is used -- which will either * |delete| or |delete[]| the resource, depending whether the resource is an * array. Custom deletion policies ideally should be empty classes (no member * fields, no member fields in base classes, no virtual methods/inheritance), * because then UniquePtr can be just as efficient as a raw pointer. * * Use of UniquePtr proceeds like so: * * UniquePtr<int> g1; // initializes to nullptr * g1.reset(new int); // switch resources using reset() * g1 = nullptr; // clears g1, deletes the int * * UniquePtr<int> g2(new int); // owns that int * int* p = g2.release(); // g2 leaks its int -- still requires deletion * delete p; // now freed * * struct S { int x; S(int x) : x(x) {} }; * UniquePtr<S> g3, g4(new S(5)); * g3 = std::move(g4); // g3 owns the S, g4 cleared * S* p = g3.get(); // g3 still owns |p| * assert(g3->x == 5); // operator-> works (if .get() != nullptr) * assert((*g3).x == 5); // also operator* (again, if not cleared) * Swap(g3, g4); // g4 now owns the S, g3 cleared * g3.swap(g4); // g3 now owns the S, g4 cleared * UniquePtr<S> g5(std::move(g3)); // g5 owns the S, g3 cleared * g5.reset(); // deletes the S, g5 cleared * * struct FreePolicy { void operator()(void* p) { free(p); } }; * UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); * int* ptr = g6.get(); * g6 = nullptr; // calls free(ptr) * * Now, carefully note a few things you *can't* do: * * UniquePtr<int> b1; * b1 = new int; // BAD: can only assign another UniquePtr * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() * * UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr * UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr * * (Note that changing a UniquePtr to store a direct |new| expression is * permitted, but usually you should use MakeUnique, defined at the end of this * header.) * * A few miscellaneous notes: * * UniquePtr, when not instantiated for an array type, can be move-constructed * and move-assigned, not only from itself but from "derived" UniquePtr<U, E> * instantiations where U converts to T and E converts to D. If you want to use * this, you're going to have to specify a deletion policy for both UniquePtr * instantations, and T pretty much has to have a virtual destructor. In other * words, this doesn't work: * * struct Base { virtual ~Base() {} }; * struct Derived : Base {}; * * UniquePtr<Base> b1; * // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert * UniquePtr<Derived> d1(std::move(b)); * * UniquePtr<Base> b2; * UniquePtr<Derived, DefaultDelete<Base>> d2(std::move(b2)); // okay * * UniquePtr is specialized for array types. Specializing with an array type * creates a smart-pointer version of that array -- not a pointer to such an * array. * * UniquePtr<int[]> arr(new int[5]); * arr[0] = 4; * * What else is different? Deletion of course uses |delete[]|. An operator[] * is provided. Functionality that doesn't make sense for arrays is removed. * The constructors and mutating methods only accept array pointers (not T*, U* * that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|. * * It's perfectly okay for a function to return a UniquePtr. This transfers * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created * in the calling function, that will then solely own that data. Such functions * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. * * UniquePtr will commonly be a member of a class, with lifetime equivalent to * that of that class. If you want to expose the related resource, you could * expose a raw pointer via |get()|, but ownership of a raw pointer is * inherently unclear. So it's better to expose a |const UniquePtr&| instead. * This prohibits mutation but still allows use of |get()| when needed (but * operator-> is preferred). Of course, you can only use this smart pointer as * long as the enclosing class instance remains live -- no different than if you * exposed the |get()| raw pointer. * * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| * argument. To specify an inout parameter (where the method may or may not * take ownership of the resource, or reset it), or to specify an out parameter * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| * argument. To unconditionally transfer ownership of a UniquePtr * into a method, use a |UniquePtr| argument. To conditionally transfer * ownership of a resource into a method, should the method want it, use a * |UniquePtr&&| argument. */ template <typename T, class D> class UniquePtr { public: typedef T ElementType; typedef D DeleterType; typedef typename detail::PointerType<T, DeleterType>::Type Pointer; private: Pair<Pointer, DeleterType> mTuple; Pointer& ptr() { return mTuple.first(); } const Pointer& ptr() const { return mTuple.first(); } DeleterType& del() { return mTuple.second(); } const DeleterType& del() const { return mTuple.second(); } public: /** * Construct a UniquePtr containing |nullptr|. */ constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } /** * Construct a UniquePtr containing |aPtr|. */ explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } UniquePtr(Pointer aPtr, typename Conditional<IsReference<D>::value, D, const D&>::Type aD1) : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template // argument list": don't use UniquePtr<T, reference to function>! Ideally // you should make deletion use the same function every time, using a // deleter policy: // // // BAD, won't compile with MSVC10, deleter doesn't need to be a // // variable at all // typedef void (&FreeSignature)(void*); // UniquePtr<int, FreeSignature> ptr((int*) malloc(sizeof(int)), free); // // // GOOD, compiles with MSVC10, deletion behavior statically known and // // optimizable // struct DeleteByFreeing // { // void operator()(void* aPtr) { free(aPtr); } // }; // // If deletion really, truly, must be a variable: you might be able to work // around this with a deleter class that contains the function reference. // But this workaround is untried and untested, because variable deletion // behavior really isn't something you should use. UniquePtr(Pointer aPtr, typename RemoveReference<D>::Type&& aD2) : mTuple(aPtr, std::move(aD2)) { static_assert(!IsReference<D>::value, "rvalue deleter can't be stored by reference"); } UniquePtr(UniquePtr&& aOther) : mTuple(aOther.release(), std::forward<DeleterType>(aOther.get_deleter())) {} MOZ_IMPLICIT UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } template <typename U, class E> MOZ_IMPLICIT UniquePtr( UniquePtr<U, E>&& aOther, typename EnableIf< IsConvertible<typename UniquePtr<U, E>::Pointer, Pointer>::value && !IsArray<U>::value && (IsReference<D>::value ? IsSame<D, E>::value : IsConvertible<E, D>::value), int>::Type aDummy = 0) : mTuple(aOther.release(), std::forward<E>(aOther.get_deleter())) {} ~UniquePtr() { reset(nullptr); } UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); return *this; } template <typename U, typename E> UniquePtr& operator=(UniquePtr<U, E>&& aOther) { static_assert( IsConvertible<typename UniquePtr<U, E>::Pointer, Pointer>::value, "incompatible UniquePtr pointees"); static_assert(!IsArray<U>::value, "can't assign from UniquePtr holding an array"); reset(aOther.release()); get_deleter() = std::forward<E>(aOther.get_deleter()); return *this; } UniquePtr& operator=(decltype(nullptr)) { reset(nullptr); return *this; } typename AddLvalueReference<T>::Type operator*() const { return *get(); } Pointer operator->() const { MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); return get(); } explicit operator bool() const { return get() != nullptr; } Pointer get() const { return ptr(); } DeleterType& get_deleter() { return del(); } const DeleterType& get_deleter() const { return del(); } MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; return p; } void reset(Pointer aPtr = Pointer()) { Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { get_deleter()(old); } } void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! void operator=(const UniquePtr& aOther) = delete; // assign using std::move()! }; // In case you didn't read the comment by the main definition (you should!): the // UniquePtr<T[]> specialization exists to manage array pointers. It deletes // such pointers using delete[], it will reject construction and modification // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. template <typename T, class D> class UniquePtr<T[], D> { public: typedef T* Pointer; typedef T ElementType; typedef D DeleterType; private: Pair<Pointer, DeleterType> mTuple; public: /** * Construct a UniquePtr containing nullptr. */ constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } /** * Construct a UniquePtr containing |aPtr|. */ explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } // delete[] knows how to handle *only* an array of a single class type. For // delete[] to work correctly, it must know the size of each element, the // fields and base classes of each element requiring destruction, and so on. // So forbid all overloads which would end up invoking delete[] on a pointer // of the wrong type. template <typename U> UniquePtr( U&& aU, typename EnableIf<IsPointer<U>::value && IsConvertible<U, Pointer>::value, int>::Type aDummy = 0) = delete; UniquePtr(Pointer aPtr, typename Conditional<IsReference<D>::value, D, const D&>::Type aD1) : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template // argument list": don't use UniquePtr<T[], reference to function>! See the // comment by this constructor in the non-T[] specialization above. UniquePtr(Pointer aPtr, typename RemoveReference<D>::Type&& aD2) : mTuple(aPtr, std::move(aD2)) { static_assert(!IsReference<D>::value, "rvalue deleter can't be stored by reference"); } // Forbidden for the same reasons as stated above. template <typename U, typename V> UniquePtr( U&& aU, V&& aV, typename EnableIf<IsPointer<U>::value && IsConvertible<U, Pointer>::value, int>::Type aDummy = 0) = delete; UniquePtr(UniquePtr&& aOther) : mTuple(aOther.release(), std::forward<DeleterType>(aOther.get_deleter())) {} MOZ_IMPLICIT UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer<D>::value, "must provide a deleter instance"); static_assert(!IsReference<D>::value, "must provide a deleter instance"); } ~UniquePtr() { reset(nullptr); } UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); return *this; } UniquePtr& operator=(decltype(nullptr)) { reset(); return *this; } explicit operator bool() const { return get() != nullptr; } T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } Pointer get() const { return mTuple.first(); } DeleterType& get_deleter() { return mTuple.second(); } const DeleterType& get_deleter() const { return mTuple.second(); } MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; return p; } void reset(Pointer aPtr = Pointer()) { Pointer old = mTuple.first(); mTuple.first() = aPtr; if (old != nullptr) { mTuple.second()(old); } } void reset(decltype(nullptr)) { Pointer old = mTuple.first(); mTuple.first() = nullptr; if (old != nullptr) { mTuple.second()(old); } } template <typename U> void reset(U) = delete; void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! void operator=(const UniquePtr& aOther) = delete; // assign using std::move()! }; /** * A default deletion policy using plain old operator delete. * * Note that this type can be specialized, but authors should beware of the risk * that the specialization may at some point cease to match (either because it * gets moved to a different compilation unit or the signature changes). If the * non-specialized (|delete|-based) version compiles for that type but does the * wrong thing, bad things could happen. * * This is a non-issue for types which are always incomplete (i.e. opaque handle * types), since |delete|-ing such a type will always trigger a compilation * error. */ template <typename T> class DefaultDelete { public: constexpr DefaultDelete() {} template <typename U> MOZ_IMPLICIT DefaultDelete( const DefaultDelete<U>& aOther, typename EnableIf<mozilla::IsConvertible<U*, T*>::value, int>::Type aDummy = 0) {} void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete aPtr; } }; /** A default deletion policy using operator delete[]. */ template <typename T> class DefaultDelete<T[]> { public: constexpr DefaultDelete() {} void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete[] aPtr; } template <typename U> void operator()(U* aPtr) const = delete; }; template <typename T, class D> void Swap(UniquePtr<T, D>& aX, UniquePtr<T, D>& aY) { aX.swap(aY); } template <typename T, class D, typename U, class E> bool operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { return aX.get() == aY.get(); } template <typename T, class D, typename U, class E> bool operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { return aX.get() != aY.get(); } template <typename T, class D> bool operator==(const UniquePtr<T, D>& aX, decltype(nullptr)) { return !aX; } template <typename T, class D> bool operator==(decltype(nullptr), const UniquePtr<T, D>& aX) { return !aX; } template <typename T, class D> bool operator!=(const UniquePtr<T, D>& aX, decltype(nullptr)) { return bool(aX); } template <typename T, class D> bool operator!=(decltype(nullptr), const UniquePtr<T, D>& aX) { return bool(aX); } // No operator<, operator>, operator<=, operator>= for now because simplicity. namespace detail { template <typename T> struct UniqueSelector { typedef UniquePtr<T> SingleObject; }; template <typename T> struct UniqueSelector<T[]> { typedef UniquePtr<T[]> UnknownBound; }; template <typename T, decltype(sizeof(int)) N> struct UniqueSelector<T[N]> { typedef UniquePtr<T[N]> KnownBound; }; } // namespace detail /** * MakeUnique is a helper function for allocating new'd objects and arrays, * returning a UniquePtr containing the resulting pointer. The semantics of * MakeUnique<Type>(...) are as follows. * * If Type is an array T[n]: * Disallowed, deleted, no overload for you! * If Type is an array T[]: * MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned * is as if by |new T[n]()|, which value-initializes each element. (If T * isn't a class type, this will zero each element. If T is a class type, * then roughly speaking, each element will be constructed using its default * constructor. See C++11 [dcl.init]p7 for the full gory details.) * If Type is non-array T: * The arguments passed to MakeUnique<T>(...) are forwarded into a * |new T(...)| call, initializing the T as would happen if executing * |T(...)|. * * There are various benefits to using MakeUnique instead of |new| expressions. * * First, MakeUnique eliminates use of |new| from code entirely. If objects are * only created through UniquePtr, then (assuming all explicit release() calls * are safe, including transitively, and no type-safety casting funniness) * correctly maintained ownership of the UniquePtr guarantees no leaks are * possible. (This pays off best if a class is only ever created through a * factory method on the class, using a private constructor.) * * Second, initializing a UniquePtr using a |new| expression requires repeating * the name of the new'd type, whereas MakeUnique in concert with the |auto| * keyword names it only once: * * UniquePtr<char> ptr1(new char()); // repetitive * auto ptr2 = MakeUnique<char>(); // shorter * * Of course this assumes the reader understands the operation MakeUnique * performs. In the long run this is probably a reasonable assumption. In the * short run you'll have to use your judgment about what readers can be expected * to know, or to quickly look up. * * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In * contrast you can't assign a pointer into a UniquePtr without using the * cumbersome reset(). * * UniquePtr<char> p; * p = new char; // ERROR * p.reset(new char); // works, but fugly * p = MakeUnique<char>(); // preferred * * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. * An exception thrown after |new T| succeeds will leak that memory, unless the * pointer is assigned to an object that will manage its ownership. UniquePtr * ably serves this function.) */ template <typename T, typename... Args> typename detail::UniqueSelector<T>::SingleObject MakeUnique(Args&&... aArgs) { return UniquePtr<T>(new T(std::forward<Args>(aArgs)...)); } template <typename T> typename detail::UniqueSelector<T>::UnknownBound MakeUnique( decltype(sizeof(int)) aN) { typedef typename RemoveExtent<T>::Type ArrayType; return UniquePtr<T>(new ArrayType[aN]()); } template <typename T, typename... Args> typename detail::UniqueSelector<T>::KnownBound MakeUnique(Args&&... aArgs) = delete; /** * WrapUnique is a helper function to transfer ownership from a raw pointer * into a UniquePtr<T>. It can only be used with a single non-array type. * * It is generally used this way: * * auto p = WrapUnique(new char); * * It can be used when MakeUnique is not usable, for example, when the * constructor you are using is private, or you want to use aggregate * initialization. */ template <typename T> typename detail::UniqueSelector<T>::SingleObject WrapUnique(T* aPtr) { return UniquePtr<T>(aPtr); } } // namespace mozilla #endif /* mozilla_UniquePtr_h */ void bar(int* ptr); #ifdef TEST_VAL void baz(mozilla::UniquePtr<int> ptr); void foo(mozilla::UniquePtr<int> ptr) { if (*ptr > 42) { bar(ptr.get()); *ptr = 42; } baz(std::move(ptr)); } #endif #ifdef TEST_RREF void baz(mozilla::UniquePtr<int>&& ptr); void foo(mozilla::UniquePtr<int> ptr) { if (*ptr > 42) { bar(ptr.get()); *ptr = 42; } baz(std::move(ptr)); } #endif
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree