authorgravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-28 17:24:19-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-03-28 17:24:19-06:00
log457f557c37947af6ce90a82a70e08e59526af0dc
tree0912f2ff48f2c9b72cd755bc5eb17f3ca8c3bf1c
parentc7f4e68464e0ebd6e6d0f3230114d189e25e3dc9
parentf9db21f03eaf0b800e531d12c2677d579eceaff0
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge branch 'master' into feature-file-locks


127 files changed, 31202 insertions(+), 298 deletions(-)

CMakeLists.txt+24-10
...@@ -62,6 +62,9 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)...@@ -62,6 +62,9 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)
62# LLD to the tree. This option does nothing.62# LLD to the tree. This option does nothing.
63option(ZIG_FORCE_EXTERNAL_LLD "does nothing" OFF)63option(ZIG_FORCE_EXTERNAL_LLD "does nothing" OFF)
6464
65set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for")
66set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary")
67
65find_package(llvm)68find_package(llvm)
66find_package(clang)69find_package(clang)
67find_package(lld)70find_package(lld)
...@@ -338,7 +341,7 @@ if(MSVC)...@@ -338,7 +341,7 @@ if(MSVC)
338 if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")341 if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel")
339 set(EXE_LDFLAGS "${EXE_LDFLAGS} /debug:fastlink")342 set(EXE_LDFLAGS "${EXE_LDFLAGS} /debug:fastlink")
340 endif()343 endif()
341elseif(MINGW) 344elseif(MINGW)
342 set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")345 set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
343endif()346endif()
344347
...@@ -353,7 +356,7 @@ if(ZIG_STATIC)...@@ -353,7 +356,7 @@ if(ZIG_STATIC)
353else()356else()
354 if(MINGW)357 if(MINGW)
355 set(EXE_LDFLAGS "${EXE_LDFLAGS} -lz3")358 set(EXE_LDFLAGS "${EXE_LDFLAGS} -lz3")
356 endif() 359 endif()
357endif()360endif()
358361
359if(ZIG_TEST_COVERAGE)362if(ZIG_TEST_COVERAGE)
...@@ -424,6 +427,7 @@ endif()...@@ -424,6 +427,7 @@ endif()
424427
425set(BUILD_LIBSTAGE2_ARGS "build-lib"428set(BUILD_LIBSTAGE2_ARGS "build-lib"
426 "src-self-hosted/stage2.zig"429 "src-self-hosted/stage2.zig"
430 -target "${ZIG_TARGET_TRIPLE}"
427 -mcpu=baseline431 -mcpu=baseline
428 --name zigstage2432 --name zigstage2
429 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"433 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
...@@ -436,12 +440,22 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib"...@@ -436,12 +440,22 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib"
436 ${LIBSTAGE2_WINDOWS_ARGS}440 ${LIBSTAGE2_WINDOWS_ARGS}
437)441)
438442
439add_custom_target(zig_build_libstage2 ALL443if("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
440 COMMAND zig0 ${BUILD_LIBSTAGE2_ARGS}444 add_custom_target(zig_build_libstage2 ALL
441 DEPENDS zig0445 COMMAND zig0 ${BUILD_LIBSTAGE2_ARGS}
442 BYPRODUCTS "${LIBSTAGE2}"446 DEPENDS zig0
443 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"447 BYPRODUCTS "${LIBSTAGE2}"
444)448 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
449 )
450 set(ZIG_EXECUTABLE "${zig_BINARY_DIR}/zig")
451else()
452 add_custom_target(zig_build_libstage2 ALL
453 COMMAND "${ZIG_EXECUTABLE}" ${BUILD_LIBSTAGE2_ARGS}
454 BYPRODUCTS "${LIBSTAGE2}"
455 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
456 )
457endif()
458
445add_executable(zig "${ZIG_MAIN_SRC}")459add_executable(zig "${ZIG_MAIN_SRC}")
446460
447set_target_properties(zig PROPERTIES461set_target_properties(zig PROPERTIES
...@@ -451,7 +465,7 @@ set_target_properties(zig PROPERTIES...@@ -451,7 +465,7 @@ set_target_properties(zig PROPERTIES
451target_link_libraries(zig zigcompiler "${LIBSTAGE2}")465target_link_libraries(zig zigcompiler "${LIBSTAGE2}")
452if(MSVC)466if(MSVC)
453 target_link_libraries(zig ntdll.lib)467 target_link_libraries(zig ntdll.lib)
454elseif(MINGW) 468elseif(MINGW)
455 target_link_libraries(zig ntdll)469 target_link_libraries(zig ntdll)
456endif()470endif()
457add_dependencies(zig zig_build_libstage2)471add_dependencies(zig zig_build_libstage2)
...@@ -480,7 +494,7 @@ if(MSVC)...@@ -480,7 +494,7 @@ if(MSVC)
480 endif()494 endif()
481else()495else()
482 get_target_property(zig_BINARY_DIR zig BINARY_DIR)496 get_target_property(zig_BINARY_DIR zig BINARY_DIR)
483 install(CODE "set(zig_EXE \"${zig_BINARY_DIR}/zig\")")497 install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
484 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")498 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
485 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")499 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
486 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)500 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
ci/drone/linux_script-15
...@@ -15,21 +15,6 @@ pip3 install s3cmd...@@ -15,21 +15,6 @@ pip3 install s3cmd
15# This will affect the cmake command below.15# This will affect the cmake command below.
16git config core.abbrev 916git config core.abbrev 9
1717
18# This patch is a workaround for
19# https://github.com/ziglang/zig/issues/4822
20patch <<'END_PATCH'
21--- CMakeLists.txt
22+++ CMakeLists.txt
23@@ -430,7 +430,6 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib"
24 --cache on
25 --output-dir "${CMAKE_BINARY_DIR}"
26 ${LIBSTAGE2_RELEASE_ARG}
27- --bundle-compiler-rt
28 -fPIC
29 -lc
30 ${LIBSTAGE2_WINDOWS_ARGS}
31END_PATCH
32
33mkdir build18mkdir build
34cd build19cd build
35cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local20cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local
cmake/Findclang.cmake+1-1
...@@ -56,6 +56,6 @@ FIND_AND_ADD_CLANG_LIB(clangCrossTU)...@@ -56,6 +56,6 @@ FIND_AND_ADD_CLANG_LIB(clangCrossTU)
56FIND_AND_ADD_CLANG_LIB(clangIndex)56FIND_AND_ADD_CLANG_LIB(clangIndex)
5757
58include(FindPackageHandleStandardArgs)58include(FindPackageHandleStandardArgs)
59find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)59find_package_handle_standard_args(clang DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)
6060
61mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES CLANG_LIBDIRS)61mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES CLANG_LIBDIRS)
cmake/Findlld.cmake+1-1
...@@ -47,6 +47,6 @@ else()...@@ -47,6 +47,6 @@ else()
47endif()47endif()
4848
49include(FindPackageHandleStandardArgs)49include(FindPackageHandleStandardArgs)
50find_package_handle_standard_args(LLD DEFAULT_MSG LLD_LIBRARIES LLD_INCLUDE_DIRS)50find_package_handle_standard_args(lld DEFAULT_MSG LLD_LIBRARIES LLD_INCLUDE_DIRS)
5151
52mark_as_advanced(LLD_INCLUDE_DIRS LLD_LIBRARIES)52mark_as_advanced(LLD_INCLUDE_DIRS LLD_LIBRARIES)
cmake/Findllvm.cmake+280-96
...@@ -7,119 +7,303 @@...@@ -7,119 +7,303 @@
7# LLVM_LIBRARIES7# LLVM_LIBRARIES
8# LLVM_LIBDIRS8# LLVM_LIBDIRS
99
10find_program(LLVM_CONFIG_EXE10if("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
11 NAMES llvm-config-10 llvm-config-10.0 llvm-config100 llvm-config11 find_program(LLVM_CONFIG_EXE
12 PATHS12 NAMES llvm-config-10 llvm-config-10.0 llvm-config100 llvm-config
13 "/mingw64/bin"13 PATHS
14 "/c/msys64/mingw64/bin"14 "/mingw64/bin"
15 "c:/msys64/mingw64/bin"15 "/c/msys64/mingw64/bin"
16 "C:/Libraries/llvm-10.0.0/bin")16 "c:/msys64/mingw64/bin"
17 "C:/Libraries/llvm-10.0.0/bin")
1718
18if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")19 if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")
19 message(FATAL_ERROR "unable to find llvm-config")20 message(FATAL_ERROR "unable to find llvm-config")
20endif()21 endif()
2122
22if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")23 if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")
23 message(FATAL_ERROR "unable to find llvm-config")24 message(FATAL_ERROR "unable to find llvm-config")
24endif()25 endif()
2526
26execute_process(27 execute_process(
27 COMMAND ${LLVM_CONFIG_EXE} --version28 COMMAND ${LLVM_CONFIG_EXE} --version
28 OUTPUT_VARIABLE LLVM_CONFIG_VERSION29 OUTPUT_VARIABLE LLVM_CONFIG_VERSION
29 OUTPUT_STRIP_TRAILING_WHITESPACE)30 OUTPUT_STRIP_TRAILING_WHITESPACE)
3031
31if("${LLVM_CONFIG_VERSION}" VERSION_LESS 10)32 if("${LLVM_CONFIG_VERSION}" VERSION_LESS 10)
32 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")33 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")
33endif()34 endif()
34if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 11)35 if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 11)
35 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")36 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")
36endif()37 endif()
37if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 11)38 if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 11)
38 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")39 message(FATAL_ERROR "expected LLVM 10.x but found ${LLVM_CONFIG_VERSION}")
39endif()40 endif()
4041
41execute_process(
42 COMMAND ${LLVM_CONFIG_EXE} --targets-built
43 OUTPUT_VARIABLE LLVM_TARGETS_BUILT_SPACES
44 OUTPUT_STRIP_TRAILING_WHITESPACE)
45string(REPLACE " " ";" LLVM_TARGETS_BUILT "${LLVM_TARGETS_BUILT_SPACES}")
46function(NEED_TARGET TARGET_NAME)
47 list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index)
48 if (${_index} EQUAL -1)
49 message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.")
50 endif()
51endfunction(NEED_TARGET)
52NEED_TARGET("AArch64")
53NEED_TARGET("AMDGPU")
54NEED_TARGET("ARM")
55NEED_TARGET("BPF")
56NEED_TARGET("Hexagon")
57NEED_TARGET("Lanai")
58NEED_TARGET("Mips")
59NEED_TARGET("MSP430")
60NEED_TARGET("NVPTX")
61NEED_TARGET("PowerPC")
62NEED_TARGET("RISCV")
63NEED_TARGET("Sparc")
64NEED_TARGET("SystemZ")
65NEED_TARGET("WebAssembly")
66NEED_TARGET("X86")
67NEED_TARGET("XCore")
68
69if(ZIG_STATIC_LLVM)
70 execute_process(42 execute_process(
71 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static43 COMMAND ${LLVM_CONFIG_EXE} --targets-built
72 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES44 OUTPUT_VARIABLE LLVM_TARGETS_BUILT_SPACES
73 OUTPUT_STRIP_TRAILING_WHITESPACE)45 OUTPUT_STRIP_TRAILING_WHITESPACE)
74 string(REPLACE " " ";" LLVM_LIBRARIES "${LLVM_LIBRARIES_SPACES}")46 string(REPLACE " " ";" LLVM_TARGETS_BUILT "${LLVM_TARGETS_BUILT_SPACES}")
47 function(NEED_TARGET TARGET_NAME)
48 list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index)
49 if (${_index} EQUAL -1)
50 message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.")
51 endif()
52 endfunction(NEED_TARGET)
53 NEED_TARGET("AArch64")
54 NEED_TARGET("AMDGPU")
55 NEED_TARGET("ARM")
56 NEED_TARGET("BPF")
57 NEED_TARGET("Hexagon")
58 NEED_TARGET("Lanai")
59 NEED_TARGET("Mips")
60 NEED_TARGET("MSP430")
61 NEED_TARGET("NVPTX")
62 NEED_TARGET("PowerPC")
63 NEED_TARGET("RISCV")
64 NEED_TARGET("Sparc")
65 NEED_TARGET("SystemZ")
66 NEED_TARGET("WebAssembly")
67 NEED_TARGET("X86")
68 NEED_TARGET("XCore")
7569
76 execute_process(70 if(ZIG_STATIC_LLVM)
77 COMMAND ${LLVM_CONFIG_EXE} --system-libs --link-static71 execute_process(
78 OUTPUT_VARIABLE LLVM_SYSTEM_LIBS_SPACES72 COMMAND ${LLVM_CONFIG_EXE} --libfiles --link-static
79 OUTPUT_STRIP_TRAILING_WHITESPACE)73 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
80 string(REPLACE " " ";" LLVM_SYSTEM_LIBS "${LLVM_SYSTEM_LIBS_SPACES}")74 OUTPUT_STRIP_TRAILING_WHITESPACE)
75 string(REPLACE " " ";" LLVM_LIBRARIES "${LLVM_LIBRARIES_SPACES}")
8176
82 execute_process(77 execute_process(
83 COMMAND ${LLVM_CONFIG_EXE} --libdir --link-static78 COMMAND ${LLVM_CONFIG_EXE} --system-libs --link-static
84 OUTPUT_VARIABLE LLVM_LIBDIRS_SPACES79 OUTPUT_VARIABLE LLVM_SYSTEM_LIBS_SPACES
85 OUTPUT_STRIP_TRAILING_WHITESPACE)80 OUTPUT_STRIP_TRAILING_WHITESPACE)
86 string(REPLACE " " ";" LLVM_LIBDIRS "${LLVM_LIBDIRS_SPACES}")81 string(REPLACE " " ";" LLVM_SYSTEM_LIBS "${LLVM_SYSTEM_LIBS_SPACES}")
87endif()
88if(NOT LLVM_LIBRARIES)
89 execute_process(
90 COMMAND ${LLVM_CONFIG_EXE} --libs
91 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
92 OUTPUT_STRIP_TRAILING_WHITESPACE)
93 string(REPLACE " " ";" LLVM_LIBRARIES "${LLVM_LIBRARIES_SPACES}")
9482
95 execute_process(83 execute_process(
96 COMMAND ${LLVM_CONFIG_EXE} --system-libs84 COMMAND ${LLVM_CONFIG_EXE} --libdir --link-static
97 OUTPUT_VARIABLE LLVM_SYSTEM_LIBS_SPACES85 OUTPUT_VARIABLE LLVM_LIBDIRS_SPACES
98 OUTPUT_STRIP_TRAILING_WHITESPACE)86 OUTPUT_STRIP_TRAILING_WHITESPACE)
99 string(REPLACE " " ";" LLVM_SYSTEM_LIBS "${LLVM_SYSTEM_LIBS_SPACES}")87 string(REPLACE " " ";" LLVM_LIBDIRS "${LLVM_LIBDIRS_SPACES}")
88 endif()
89 if(NOT LLVM_LIBRARIES)
90 execute_process(
91 COMMAND ${LLVM_CONFIG_EXE} --libs
92 OUTPUT_VARIABLE LLVM_LIBRARIES_SPACES
93 OUTPUT_STRIP_TRAILING_WHITESPACE)
94 string(REPLACE " " ";" LLVM_LIBRARIES "${LLVM_LIBRARIES_SPACES}")
95
96 execute_process(
97 COMMAND ${LLVM_CONFIG_EXE} --system-libs
98 OUTPUT_VARIABLE LLVM_SYSTEM_LIBS_SPACES
99 OUTPUT_STRIP_TRAILING_WHITESPACE)
100 string(REPLACE " " ";" LLVM_SYSTEM_LIBS "${LLVM_SYSTEM_LIBS_SPACES}")
101
102 execute_process(
103 COMMAND ${LLVM_CONFIG_EXE} --libdir
104 OUTPUT_VARIABLE LLVM_LIBDIRS_SPACES
105 OUTPUT_STRIP_TRAILING_WHITESPACE)
106 string(REPLACE " " ";" LLVM_LIBDIRS "${LLVM_LIBDIRS_SPACES}")
107 endif()
100108
101 execute_process(109 execute_process(
102 COMMAND ${LLVM_CONFIG_EXE} --libdir110 COMMAND ${LLVM_CONFIG_EXE} --includedir
103 OUTPUT_VARIABLE LLVM_LIBDIRS_SPACES111 OUTPUT_VARIABLE LLVM_INCLUDE_DIRS
104 OUTPUT_STRIP_TRAILING_WHITESPACE)112 OUTPUT_STRIP_TRAILING_WHITESPACE)
105 string(REPLACE " " ";" LLVM_LIBDIRS "${LLVM_LIBDIRS_SPACES}")
106endif()
107113
108execute_process(114 set(LLVM_LIBRARIES ${LLVM_LIBRARIES} ${LLVM_SYSTEM_LIBS})
109 COMMAND ${LLVM_CONFIG_EXE} --includedir
110 OUTPUT_VARIABLE LLVM_INCLUDE_DIRS
111 OUTPUT_STRIP_TRAILING_WHITESPACE)
112115
113set(LLVM_LIBRARIES ${LLVM_LIBRARIES} ${LLVM_SYSTEM_LIBS})116 if(NOT LLVM_LIBRARIES)
117 find_library(LLVM_LIBRARIES NAMES LLVM LLVM-10 LLVM-10.0)
118 endif()
114119
115if(NOT LLVM_LIBRARIES)120 link_directories("${CMAKE_PREFIX_PATH}/lib")
116 find_library(LLVM_LIBRARIES NAMES LLVM LLVM-10 LLVM-10.0)121 link_directories("${LLVM_LIBDIRS}")
117endif()122else()
123 # Here we assume that we're cross compiling with Zig, of course. No reason
124 # to support more complicated setups. We also assume the experimental target
125 # AVR is enabled.
118126
119link_directories("${CMAKE_PREFIX_PATH}/lib")127 find_path(LLVM_INCLUDE_DIRS NAMES llvm/IR/IRBuilder.h
120link_directories("${LLVM_LIBDIRS}")128 PATHS
129 /usr/lib/llvm/10/include
130 /usr/lib/llvm-10/include
131 /usr/lib/llvm-10.0/include
132 /usr/local/llvm100/include
133 /mingw64/include)
134
135 macro(FIND_AND_ADD_LLVM_LIB _libname_)
136 string(TOUPPER ${_libname_} _prettylibname_)
137 find_library(LLVM_${_prettylibname_}_LIB NAMES ${_libname_}
138 PATHS
139 ${LLVM_LIBDIRS}
140 /usr/lib/llvm/10/lib
141 /usr/lib/llvm-10/lib
142 /usr/lib/llvm-10.0/lib
143 /usr/local/llvm100/lib
144 /mingw64/lib
145 /c/msys64/mingw64/lib
146 c:\\msys64\\mingw64\\lib)
147 if(LLVM_${_prettylibname_}_LIB)
148 set(LLVM_LIBRARIES ${LLVM_LIBRARIES} ${LLVM_${_prettylibname_}_LIB})
149 endif()
150 endmacro(FIND_AND_ADD_LLVM_LIB)
151
152 # This list can be re-generated with `llvm-config --libfiles` and then
153 # reformatting using your favorite text editor. Note we do not execute
154 # `llvm-config` here because we are cross compiling.
155 FIND_AND_ADD_LLVM_LIB(LLVMXRay)
156 FIND_AND_ADD_LLVM_LIB(LLVMWindowsManifest)
157 FIND_AND_ADD_LLVM_LIB(LLVMTableGen)
158 FIND_AND_ADD_LLVM_LIB(LLVMSymbolize)
159 FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoPDB)
160 FIND_AND_ADD_LLVM_LIB(LLVMOrcJIT)
161 FIND_AND_ADD_LLVM_LIB(LLVMOrcError)
162 FIND_AND_ADD_LLVM_LIB(LLVMJITLink)
163 FIND_AND_ADD_LLVM_LIB(LLVMObjectYAML)
164 FIND_AND_ADD_LLVM_LIB(LLVMMCA)
165 FIND_AND_ADD_LLVM_LIB(LLVMLTO)
166 FIND_AND_ADD_LLVM_LIB(LLVMPasses)
167 FIND_AND_ADD_LLVM_LIB(LLVMObjCARCOpts)
168 FIND_AND_ADD_LLVM_LIB(LLVMLineEditor)
169 FIND_AND_ADD_LLVM_LIB(LLVMLibDriver)
170 FIND_AND_ADD_LLVM_LIB(LLVMInterpreter)
171 FIND_AND_ADD_LLVM_LIB(LLVMFuzzMutate)
172 FIND_AND_ADD_LLVM_LIB(LLVMFrontendOpenMP)
173 FIND_AND_ADD_LLVM_LIB(LLVMMCJIT)
174 FIND_AND_ADD_LLVM_LIB(LLVMExecutionEngine)
175 FIND_AND_ADD_LLVM_LIB(LLVMRuntimeDyld)
176 FIND_AND_ADD_LLVM_LIB(LLVMDWARFLinker)
177 FIND_AND_ADD_LLVM_LIB(LLVMDlltoolDriver)
178 FIND_AND_ADD_LLVM_LIB(LLVMOption)
179 FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoGSYM)
180 FIND_AND_ADD_LLVM_LIB(LLVMCoverage)
181 FIND_AND_ADD_LLVM_LIB(LLVMCoroutines)
182 FIND_AND_ADD_LLVM_LIB(LLVMAVRDisassembler)
183 FIND_AND_ADD_LLVM_LIB(LLVMAVRCodeGen)
184 FIND_AND_ADD_LLVM_LIB(LLVMAVRAsmParser)
185 FIND_AND_ADD_LLVM_LIB(LLVMAVRDesc)
186 FIND_AND_ADD_LLVM_LIB(LLVMAVRInfo)
187 FIND_AND_ADD_LLVM_LIB(LLVMXCoreDisassembler)
188 FIND_AND_ADD_LLVM_LIB(LLVMXCoreCodeGen)
189 FIND_AND_ADD_LLVM_LIB(LLVMXCoreDesc)
190 FIND_AND_ADD_LLVM_LIB(LLVMXCoreInfo)
191 FIND_AND_ADD_LLVM_LIB(LLVMX86Disassembler)
192 FIND_AND_ADD_LLVM_LIB(LLVMX86AsmParser)
193 FIND_AND_ADD_LLVM_LIB(LLVMX86CodeGen)
194 FIND_AND_ADD_LLVM_LIB(LLVMX86Desc)
195 FIND_AND_ADD_LLVM_LIB(LLVMX86Utils)
196 FIND_AND_ADD_LLVM_LIB(LLVMX86Info)
197 FIND_AND_ADD_LLVM_LIB(LLVMWebAssemblyDisassembler)
198 FIND_AND_ADD_LLVM_LIB(LLVMWebAssemblyCodeGen)
199 FIND_AND_ADD_LLVM_LIB(LLVMWebAssemblyDesc)
200 FIND_AND_ADD_LLVM_LIB(LLVMWebAssemblyAsmParser)
201 FIND_AND_ADD_LLVM_LIB(LLVMWebAssemblyInfo)
202 FIND_AND_ADD_LLVM_LIB(LLVMSystemZDisassembler)
203 FIND_AND_ADD_LLVM_LIB(LLVMSystemZCodeGen)
204 FIND_AND_ADD_LLVM_LIB(LLVMSystemZAsmParser)
205 FIND_AND_ADD_LLVM_LIB(LLVMSystemZDesc)
206 FIND_AND_ADD_LLVM_LIB(LLVMSystemZInfo)
207 FIND_AND_ADD_LLVM_LIB(LLVMSparcDisassembler)
208 FIND_AND_ADD_LLVM_LIB(LLVMSparcCodeGen)
209 FIND_AND_ADD_LLVM_LIB(LLVMSparcAsmParser)
210 FIND_AND_ADD_LLVM_LIB(LLVMSparcDesc)
211 FIND_AND_ADD_LLVM_LIB(LLVMSparcInfo)
212 FIND_AND_ADD_LLVM_LIB(LLVMRISCVDisassembler)
213 FIND_AND_ADD_LLVM_LIB(LLVMRISCVCodeGen)
214 FIND_AND_ADD_LLVM_LIB(LLVMRISCVAsmParser)
215 FIND_AND_ADD_LLVM_LIB(LLVMRISCVDesc)
216 FIND_AND_ADD_LLVM_LIB(LLVMRISCVUtils)
217 FIND_AND_ADD_LLVM_LIB(LLVMRISCVInfo)
218 FIND_AND_ADD_LLVM_LIB(LLVMPowerPCDisassembler)
219 FIND_AND_ADD_LLVM_LIB(LLVMPowerPCCodeGen)
220 FIND_AND_ADD_LLVM_LIB(LLVMPowerPCAsmParser)
221 FIND_AND_ADD_LLVM_LIB(LLVMPowerPCDesc)
222 FIND_AND_ADD_LLVM_LIB(LLVMPowerPCInfo)
223 FIND_AND_ADD_LLVM_LIB(LLVMNVPTXCodeGen)
224 FIND_AND_ADD_LLVM_LIB(LLVMNVPTXDesc)
225 FIND_AND_ADD_LLVM_LIB(LLVMNVPTXInfo)
226 FIND_AND_ADD_LLVM_LIB(LLVMMSP430Disassembler)
227 FIND_AND_ADD_LLVM_LIB(LLVMMSP430CodeGen)
228 FIND_AND_ADD_LLVM_LIB(LLVMMSP430AsmParser)
229 FIND_AND_ADD_LLVM_LIB(LLVMMSP430Desc)
230 FIND_AND_ADD_LLVM_LIB(LLVMMSP430Info)
231 FIND_AND_ADD_LLVM_LIB(LLVMMipsDisassembler)
232 FIND_AND_ADD_LLVM_LIB(LLVMMipsCodeGen)
233 FIND_AND_ADD_LLVM_LIB(LLVMMipsAsmParser)
234 FIND_AND_ADD_LLVM_LIB(LLVMMipsDesc)
235 FIND_AND_ADD_LLVM_LIB(LLVMMipsInfo)
236 FIND_AND_ADD_LLVM_LIB(LLVMLanaiDisassembler)
237 FIND_AND_ADD_LLVM_LIB(LLVMLanaiCodeGen)
238 FIND_AND_ADD_LLVM_LIB(LLVMLanaiAsmParser)
239 FIND_AND_ADD_LLVM_LIB(LLVMLanaiDesc)
240 FIND_AND_ADD_LLVM_LIB(LLVMLanaiInfo)
241 FIND_AND_ADD_LLVM_LIB(LLVMHexagonDisassembler)
242 FIND_AND_ADD_LLVM_LIB(LLVMHexagonCodeGen)
243 FIND_AND_ADD_LLVM_LIB(LLVMHexagonAsmParser)
244 FIND_AND_ADD_LLVM_LIB(LLVMHexagonDesc)
245 FIND_AND_ADD_LLVM_LIB(LLVMHexagonInfo)
246 FIND_AND_ADD_LLVM_LIB(LLVMBPFDisassembler)
247 FIND_AND_ADD_LLVM_LIB(LLVMBPFCodeGen)
248 FIND_AND_ADD_LLVM_LIB(LLVMBPFAsmParser)
249 FIND_AND_ADD_LLVM_LIB(LLVMBPFDesc)
250 FIND_AND_ADD_LLVM_LIB(LLVMBPFInfo)
251 FIND_AND_ADD_LLVM_LIB(LLVMARMDisassembler)
252 FIND_AND_ADD_LLVM_LIB(LLVMARMCodeGen)
253 FIND_AND_ADD_LLVM_LIB(LLVMARMAsmParser)
254 FIND_AND_ADD_LLVM_LIB(LLVMARMDesc)
255 FIND_AND_ADD_LLVM_LIB(LLVMARMUtils)
256 FIND_AND_ADD_LLVM_LIB(LLVMARMInfo)
257 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUDisassembler)
258 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUCodeGen)
259 FIND_AND_ADD_LLVM_LIB(LLVMMIRParser)
260 FIND_AND_ADD_LLVM_LIB(LLVMipo)
261 FIND_AND_ADD_LLVM_LIB(LLVMInstrumentation)
262 FIND_AND_ADD_LLVM_LIB(LLVMVectorize)
263 FIND_AND_ADD_LLVM_LIB(LLVMLinker)
264 FIND_AND_ADD_LLVM_LIB(LLVMIRReader)
265 FIND_AND_ADD_LLVM_LIB(LLVMAsmParser)
266 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUAsmParser)
267 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUDesc)
268 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUUtils)
269 FIND_AND_ADD_LLVM_LIB(LLVMAMDGPUInfo)
270 FIND_AND_ADD_LLVM_LIB(LLVMAArch64Disassembler)
271 FIND_AND_ADD_LLVM_LIB(LLVMMCDisassembler)
272 FIND_AND_ADD_LLVM_LIB(LLVMAArch64CodeGen)
273 FIND_AND_ADD_LLVM_LIB(LLVMCFGuard)
274 FIND_AND_ADD_LLVM_LIB(LLVMGlobalISel)
275 FIND_AND_ADD_LLVM_LIB(LLVMSelectionDAG)
276 FIND_AND_ADD_LLVM_LIB(LLVMAsmPrinter)
277 FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoDWARF)
278 FIND_AND_ADD_LLVM_LIB(LLVMCodeGen)
279 FIND_AND_ADD_LLVM_LIB(LLVMTarget)
280 FIND_AND_ADD_LLVM_LIB(LLVMScalarOpts)
281 FIND_AND_ADD_LLVM_LIB(LLVMInstCombine)
282 FIND_AND_ADD_LLVM_LIB(LLVMAggressiveInstCombine)
283 FIND_AND_ADD_LLVM_LIB(LLVMTransformUtils)
284 FIND_AND_ADD_LLVM_LIB(LLVMBitWriter)
285 FIND_AND_ADD_LLVM_LIB(LLVMAnalysis)
286 FIND_AND_ADD_LLVM_LIB(LLVMProfileData)
287 FIND_AND_ADD_LLVM_LIB(LLVMObject)
288 FIND_AND_ADD_LLVM_LIB(LLVMTextAPI)
289 FIND_AND_ADD_LLVM_LIB(LLVMBitReader)
290 FIND_AND_ADD_LLVM_LIB(LLVMCore)
291 FIND_AND_ADD_LLVM_LIB(LLVMRemarks)
292 FIND_AND_ADD_LLVM_LIB(LLVMBitstreamReader)
293 FIND_AND_ADD_LLVM_LIB(LLVMAArch64AsmParser)
294 FIND_AND_ADD_LLVM_LIB(LLVMMCParser)
295 FIND_AND_ADD_LLVM_LIB(LLVMAArch64Desc)
296 FIND_AND_ADD_LLVM_LIB(LLVMMC)
297 FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoCodeView)
298 FIND_AND_ADD_LLVM_LIB(LLVMDebugInfoMSF)
299 FIND_AND_ADD_LLVM_LIB(LLVMBinaryFormat)
300 FIND_AND_ADD_LLVM_LIB(LLVMAArch64Utils)
301 FIND_AND_ADD_LLVM_LIB(LLVMAArch64Info)
302 FIND_AND_ADD_LLVM_LIB(LLVMSupport)
303 FIND_AND_ADD_LLVM_LIB(LLVMDemangle)
304endif()
121305
122include(FindPackageHandleStandardArgs)306include(FindPackageHandleStandardArgs)
123find_package_handle_standard_args(LLVM DEFAULT_MSG LLVM_LIBRARIES LLVM_INCLUDE_DIRS)307find_package_handle_standard_args(llvm DEFAULT_MSG LLVM_LIBRARIES LLVM_INCLUDE_DIRS)
124308
125mark_as_advanced(LLVM_INCLUDE_DIRS LLVM_LIBRARIES LLVM_LIBDIRS)309mark_as_advanced(LLVM_INCLUDE_DIRS LLVM_LIBRARIES LLVM_LIBDIRS)
lib/libc/mingw/misc/_create_locale.c created+33
...@@ -0,0 +1,33 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7#include <windows.h>
8#include <locale.h>
9#include <msvcrt.h>
10
11static _locale_t __cdecl init_func(int category, const char *locale);
12_locale_t (__cdecl *__MINGW_IMP_SYMBOL(_create_locale))(int, const char *) = init_func;
13
14static _locale_t __cdecl null_func(int category, const char *locale)
15{
16 (void)category;
17 (void)locale;
18 return NULL;
19}
20
21static _locale_t __cdecl init_func(int category, const char *locale)
22{
23 HMODULE msvcrt = __mingw_get_msvcrt_handle();
24 _locale_t (__cdecl *func)(int, const char *) = NULL;
25
26 if (msvcrt)
27 func = (void*)GetProcAddress(msvcrt, "_create_locale");
28
29 if (!func)
30 func = null_func;
31
32 return (__MINGW_IMP_SYMBOL(_create_locale) = func)(category, locale);
33}
lib/libc/mingw/misc/_free_locale.c created+31
...@@ -0,0 +1,31 @@
1/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6
7#include <windows.h>
8#include <locale.h>
9#include <msvcrt.h>
10
11static void __cdecl init_func(_locale_t locale);
12void (__cdecl *__MINGW_IMP_SYMBOL(_free_locale))(_locale_t) = init_func;
13
14static void __cdecl stub_func(_locale_t locale)
15{
16 (void)locale;
17}
18
19static void __cdecl init_func(_locale_t locale)
20{
21 HMODULE msvcrt = __mingw_get_msvcrt_handle();
22 void (__cdecl *func)(_locale_t) = NULL;
23
24 if (msvcrt)
25 func = (void*)GetProcAddress(msvcrt, "_free_locale");
26
27 if (!func)
28 func = stub_func;
29
30 (__MINGW_IMP_SYMBOL(_free_locale) = func)(locale);
31}
lib/libcxx/src/algorithm.cpp created+95
...@@ -0,0 +1,95 @@
1//===----------------------- algorithm.cpp --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "algorithm"
10#include "random"
11#ifndef _LIBCPP_HAS_NO_THREADS
12#include "mutex"
13#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
14#pragma comment(lib, "pthread")
15#endif
16#endif
17
18_LIBCPP_BEGIN_NAMESPACE_STD
19
20template void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
21template void __sort<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
22template void __sort<__less<signed char>&, signed char*>(signed char*, signed char*, __less<signed char>&);
23template void __sort<__less<unsigned char>&, unsigned char*>(unsigned char*, unsigned char*, __less<unsigned char>&);
24template void __sort<__less<short>&, short*>(short*, short*, __less<short>&);
25template void __sort<__less<unsigned short>&, unsigned short*>(unsigned short*, unsigned short*, __less<unsigned short>&);
26template void __sort<__less<int>&, int*>(int*, int*, __less<int>&);
27template void __sort<__less<unsigned>&, unsigned*>(unsigned*, unsigned*, __less<unsigned>&);
28template void __sort<__less<long>&, long*>(long*, long*, __less<long>&);
29template void __sort<__less<unsigned long>&, unsigned long*>(unsigned long*, unsigned long*, __less<unsigned long>&);
30template void __sort<__less<long long>&, long long*>(long long*, long long*, __less<long long>&);
31template void __sort<__less<unsigned long long>&, unsigned long long*>(unsigned long long*, unsigned long long*, __less<unsigned long long>&);
32template void __sort<__less<float>&, float*>(float*, float*, __less<float>&);
33template void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
34template void __sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
35
36template bool __insertion_sort_incomplete<__less<char>&, char*>(char*, char*, __less<char>&);
37template bool __insertion_sort_incomplete<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
38template bool __insertion_sort_incomplete<__less<signed char>&, signed char*>(signed char*, signed char*, __less<signed char>&);
39template bool __insertion_sort_incomplete<__less<unsigned char>&, unsigned char*>(unsigned char*, unsigned char*, __less<unsigned char>&);
40template bool __insertion_sort_incomplete<__less<short>&, short*>(short*, short*, __less<short>&);
41template bool __insertion_sort_incomplete<__less<unsigned short>&, unsigned short*>(unsigned short*, unsigned short*, __less<unsigned short>&);
42template bool __insertion_sort_incomplete<__less<int>&, int*>(int*, int*, __less<int>&);
43template bool __insertion_sort_incomplete<__less<unsigned>&, unsigned*>(unsigned*, unsigned*, __less<unsigned>&);
44template bool __insertion_sort_incomplete<__less<long>&, long*>(long*, long*, __less<long>&);
45template bool __insertion_sort_incomplete<__less<unsigned long>&, unsigned long*>(unsigned long*, unsigned long*, __less<unsigned long>&);
46template bool __insertion_sort_incomplete<__less<long long>&, long long*>(long long*, long long*, __less<long long>&);
47template bool __insertion_sort_incomplete<__less<unsigned long long>&, unsigned long long*>(unsigned long long*, unsigned long long*, __less<unsigned long long>&);
48template bool __insertion_sort_incomplete<__less<float>&, float*>(float*, float*, __less<float>&);
49template bool __insertion_sort_incomplete<__less<double>&, double*>(double*, double*, __less<double>&);
50template bool __insertion_sort_incomplete<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
51
52template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
53
54#ifndef _LIBCPP_HAS_NO_THREADS
55_LIBCPP_SAFE_STATIC static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER;
56#endif
57unsigned __rs_default::__c_ = 0;
58
59__rs_default::__rs_default()
60{
61#ifndef _LIBCPP_HAS_NO_THREADS
62 __libcpp_mutex_lock(&__rs_mut);
63#endif
64 __c_ = 1;
65}
66
67__rs_default::__rs_default(const __rs_default&)
68{
69 ++__c_;
70}
71
72__rs_default::~__rs_default()
73{
74#ifndef _LIBCPP_HAS_NO_THREADS
75 if (--__c_ == 0)
76 __libcpp_mutex_unlock(&__rs_mut);
77#else
78 --__c_;
79#endif
80}
81
82__rs_default::result_type
83__rs_default::operator()()
84{
85 static mt19937 __rs_g;
86 return __rs_g();
87}
88
89__rs_default
90__rs_get()
91{
92 return __rs_default();
93}
94
95_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/any.cpp created+34
...@@ -0,0 +1,34 @@
1//===---------------------------- any.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "any"
10
11namespace std {
12const char* bad_any_cast::what() const _NOEXCEPT {
13 return "bad any cast";
14}
15}
16
17
18#include <experimental/__config>
19
20// Preserve std::experimental::any_bad_cast for ABI compatibility
21// Even though it no longer exists in a header file
22_LIBCPP_BEGIN_NAMESPACE_LFTS
23
24class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_ANY_CAST bad_any_cast : public bad_cast
25{
26public:
27 virtual const char* what() const _NOEXCEPT;
28};
29
30const char* bad_any_cast::what() const _NOEXCEPT {
31 return "bad any cast";
32}
33
34_LIBCPP_END_NAMESPACE_LFTS
lib/libcxx/src/bind.cpp created+29
...@@ -0,0 +1,29 @@
1//===-------------------------- bind.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "functional"
10
11_LIBCPP_BEGIN_NAMESPACE_STD
12
13namespace placeholders
14{
15
16const __ph<1> _1{};
17const __ph<2> _2{};
18const __ph<3> _3{};
19const __ph<4> _4{};
20const __ph<5> _5{};
21const __ph<6> _6{};
22const __ph<7> _7{};
23const __ph<8> _8{};
24const __ph<9> _9{};
25const __ph<10> _10{};
26
27} // placeholders
28
29_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/charconv.cpp created+160
...@@ -0,0 +1,160 @@
1//===------------------------- charconv.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "charconv"
10#include <string.h>
11
12_LIBCPP_BEGIN_NAMESPACE_STD
13
14namespace __itoa
15{
16
17static constexpr char cDigitsLut[200] = {
18 '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
19 '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
20 '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
21 '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
22 '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
23 '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
24 '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
25 '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
26 '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
27 '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
28 '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
29 '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
30 '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
31 '7', '9', '8', '9', '9'};
32
33template <typename T>
34inline _LIBCPP_INLINE_VISIBILITY char*
35append1(char* buffer, T i)
36{
37 *buffer = '0' + static_cast<char>(i);
38 return buffer + 1;
39}
40
41template <typename T>
42inline _LIBCPP_INLINE_VISIBILITY char*
43append2(char* buffer, T i)
44{
45 memcpy(buffer, &cDigitsLut[(i)*2], 2);
46 return buffer + 2;
47}
48
49template <typename T>
50inline _LIBCPP_INLINE_VISIBILITY char*
51append3(char* buffer, T i)
52{
53 return append2(append1(buffer, (i) / 100), (i) % 100);
54}
55
56template <typename T>
57inline _LIBCPP_INLINE_VISIBILITY char*
58append4(char* buffer, T i)
59{
60 return append2(append2(buffer, (i) / 100), (i) % 100);
61}
62
63template <typename T>
64inline _LIBCPP_INLINE_VISIBILITY char*
65append2_no_zeros(char* buffer, T v)
66{
67 if (v < 10)
68 return append1(buffer, v);
69 else
70 return append2(buffer, v);
71}
72
73template <typename T>
74inline _LIBCPP_INLINE_VISIBILITY char*
75append4_no_zeros(char* buffer, T v)
76{
77 if (v < 100)
78 return append2_no_zeros(buffer, v);
79 else if (v < 1000)
80 return append3(buffer, v);
81 else
82 return append4(buffer, v);
83}
84
85template <typename T>
86inline _LIBCPP_INLINE_VISIBILITY char*
87append8_no_zeros(char* buffer, T v)
88{
89 if (v < 10000)
90 {
91 buffer = append4_no_zeros(buffer, v);
92 }
93 else
94 {
95 buffer = append4_no_zeros(buffer, v / 10000);
96 buffer = append4(buffer, v % 10000);
97 }
98 return buffer;
99}
100
101char*
102__u32toa(uint32_t value, char* buffer)
103{
104 if (value < 100000000)
105 {
106 buffer = append8_no_zeros(buffer, value);
107 }
108 else
109 {
110 // value = aabbbbcccc in decimal
111 const uint32_t a = value / 100000000; // 1 to 42
112 value %= 100000000;
113
114 buffer = append2_no_zeros(buffer, a);
115 buffer = append4(buffer, value / 10000);
116 buffer = append4(buffer, value % 10000);
117 }
118
119 return buffer;
120}
121
122char*
123__u64toa(uint64_t value, char* buffer)
124{
125 if (value < 100000000)
126 {
127 uint32_t v = static_cast<uint32_t>(value);
128 buffer = append8_no_zeros(buffer, v);
129 }
130 else if (value < 10000000000000000)
131 {
132 const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
133 const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
134
135 buffer = append8_no_zeros(buffer, v0);
136 buffer = append4(buffer, v1 / 10000);
137 buffer = append4(buffer, v1 % 10000);
138 }
139 else
140 {
141 const uint32_t a =
142 static_cast<uint32_t>(value / 10000000000000000); // 1 to 1844
143 value %= 10000000000000000;
144
145 buffer = append4_no_zeros(buffer, a);
146
147 const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
148 const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
149 buffer = append4(buffer, v0 / 10000);
150 buffer = append4(buffer, v0 % 10000);
151 buffer = append4(buffer, v1 / 10000);
152 buffer = append4(buffer, v1 % 10000);
153 }
154
155 return buffer;
156}
157
158} // namespace __itoa
159
160_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/chrono.cpp created+233
...@@ -0,0 +1,233 @@
1//===------------------------- chrono.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "chrono"
10#include "cerrno" // errno
11#include "system_error" // __throw_system_error
12#include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
13#include "include/apple_availability.h"
14
15#if !defined(__APPLE__)
16#define _LIBCPP_USE_CLOCK_GETTIME
17#endif // __APPLE__
18
19#if defined(_LIBCPP_WIN32API)
20#define WIN32_LEAN_AND_MEAN
21#define VC_EXTRA_LEAN
22#include <windows.h>
23#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
24#include <winapifamily.h>
25#endif
26#else
27#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
28#include <sys/time.h> // for gettimeofday and timeval
29#endif // !defined(CLOCK_REALTIME)
30#endif // defined(_LIBCPP_WIN32API)
31
32#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
33#if __APPLE__
34#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
35#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
36#error "Monotonic clock not implemented"
37#endif
38#endif
39
40#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
41#pragma comment(lib, "rt")
42#endif
43
44_LIBCPP_BEGIN_NAMESPACE_STD
45
46namespace chrono
47{
48
49// system_clock
50
51const bool system_clock::is_steady;
52
53system_clock::time_point
54system_clock::now() _NOEXCEPT
55{
56#if defined(_LIBCPP_WIN32API)
57 // FILETIME is in 100ns units
58 using filetime_duration =
59 _VSTD::chrono::duration<__int64,
60 _VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
61 nanoseconds::period>>;
62
63 // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
64 static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};
65
66 FILETIME ft;
67#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
68#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
69 GetSystemTimePreciseAsFileTime(&ft);
70#else
71 GetSystemTimeAsFileTime(&ft);
72#endif
73#else
74 GetSystemTimeAsFileTime(&ft);
75#endif
76
77 filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
78 static_cast<__int64>(ft.dwLowDateTime)};
79 return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
80#else
81#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
82 struct timespec tp;
83 if (0 != clock_gettime(CLOCK_REALTIME, &tp))
84 __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
85 return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
86#else
87 timeval tv;
88 gettimeofday(&tv, 0);
89 return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
90#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
91#endif
92}
93
94time_t
95system_clock::to_time_t(const time_point& t) _NOEXCEPT
96{
97 return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
98}
99
100system_clock::time_point
101system_clock::from_time_t(time_t t) _NOEXCEPT
102{
103 return system_clock::time_point(seconds(t));
104}
105
106#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
107// steady_clock
108//
109// Warning: If this is not truly steady, then it is non-conforming. It is
110// better for it to not exist and have the rest of libc++ use system_clock
111// instead.
112
113const bool steady_clock::is_steady;
114
115#if defined(__APPLE__)
116
117// Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
118#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
119steady_clock::time_point
120steady_clock::now() _NOEXCEPT
121{
122 struct timespec tp;
123 if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
124 __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
125 return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
126}
127
128#else
129// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
130// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
131// are run time constants supplied by the OS. This clock has no relationship
132// to the Gregorian calendar. It's main use is as a high resolution timer.
133
134// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
135// for that case as an optimization.
136
137static
138steady_clock::rep
139steady_simplified()
140{
141 return static_cast<steady_clock::rep>(mach_absolute_time());
142}
143
144static
145double
146compute_steady_factor()
147{
148 mach_timebase_info_data_t MachInfo;
149 mach_timebase_info(&MachInfo);
150 return static_cast<double>(MachInfo.numer) / MachInfo.denom;
151}
152
153static
154steady_clock::rep
155steady_full()
156{
157 static const double factor = compute_steady_factor();
158 return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
159}
160
161typedef steady_clock::rep (*FP)();
162
163static
164FP
165init_steady_clock()
166{
167 mach_timebase_info_data_t MachInfo;
168 mach_timebase_info(&MachInfo);
169 if (MachInfo.numer == MachInfo.denom)
170 return &steady_simplified;
171 return &steady_full;
172}
173
174steady_clock::time_point
175steady_clock::now() _NOEXCEPT
176{
177 static FP fp = init_steady_clock();
178 return time_point(duration(fp()));
179}
180#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
181
182#elif defined(_LIBCPP_WIN32API)
183
184// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says:
185// If the function fails, the return value is zero. <snip>
186// On systems that run Windows XP or later, the function will always succeed
187// and will thus never return zero.
188
189static LARGE_INTEGER
190__QueryPerformanceFrequency()
191{
192 LARGE_INTEGER val;
193 (void) QueryPerformanceFrequency(&val);
194 return val;
195}
196
197steady_clock::time_point
198steady_clock::now() _NOEXCEPT
199{
200 static const LARGE_INTEGER freq = __QueryPerformanceFrequency();
201
202 LARGE_INTEGER counter;
203 (void) QueryPerformanceCounter(&counter);
204 return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
205}
206
207#elif defined(CLOCK_MONOTONIC)
208
209// On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
210// time functions in the nanosecond range. Thus, they are the only acceptable
211// implementations of steady_clock.
212#ifdef __APPLE__
213#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
214#endif
215
216steady_clock::time_point
217steady_clock::now() _NOEXCEPT
218{
219 struct timespec tp;
220 if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
221 __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
222 return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
223}
224
225#else
226#error "Monotonic clock not implemented"
227#endif
228
229#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
230
231}
232
233_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/condition_variable.cpp created+93
...@@ -0,0 +1,93 @@
1//===-------------------- condition_variable.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10
11#ifndef _LIBCPP_HAS_NO_THREADS
12
13#include "condition_variable"
14#include "thread"
15#include "system_error"
16#include "__undef_macros"
17
18#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
19#pragma comment(lib, "pthread")
20#endif
21
22_LIBCPP_BEGIN_NAMESPACE_STD
23
24// ~condition_variable is defined elsewhere.
25
26void
27condition_variable::notify_one() _NOEXCEPT
28{
29 __libcpp_condvar_signal(&__cv_);
30}
31
32void
33condition_variable::notify_all() _NOEXCEPT
34{
35 __libcpp_condvar_broadcast(&__cv_);
36}
37
38void
39condition_variable::wait(unique_lock<mutex>& lk) _NOEXCEPT
40{
41 if (!lk.owns_lock())
42 __throw_system_error(EPERM,
43 "condition_variable::wait: mutex not locked");
44 int ec = __libcpp_condvar_wait(&__cv_, lk.mutex()->native_handle());
45 if (ec)
46 __throw_system_error(ec, "condition_variable wait failed");
47}
48
49void
50condition_variable::__do_timed_wait(unique_lock<mutex>& lk,
51 chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) _NOEXCEPT
52{
53 using namespace chrono;
54 if (!lk.owns_lock())
55 __throw_system_error(EPERM,
56 "condition_variable::timed wait: mutex not locked");
57 nanoseconds d = tp.time_since_epoch();
58 if (d > nanoseconds(0x59682F000000E941))
59 d = nanoseconds(0x59682F000000E941);
60 __libcpp_timespec_t ts;
61 seconds s = duration_cast<seconds>(d);
62 typedef decltype(ts.tv_sec) ts_sec;
63 _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
64 if (s.count() < ts_sec_max)
65 {
66 ts.tv_sec = static_cast<ts_sec>(s.count());
67 ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
68 }
69 else
70 {
71 ts.tv_sec = ts_sec_max;
72 ts.tv_nsec = giga::num - 1;
73 }
74 int ec = __libcpp_condvar_timedwait(&__cv_, lk.mutex()->native_handle(), &ts);
75 if (ec != 0 && ec != ETIMEDOUT)
76 __throw_system_error(ec, "condition_variable timed_wait failed");
77}
78
79void
80notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
81{
82 auto& tl_ptr = __thread_local_data();
83 // If this thread was not created using std::thread then it will not have
84 // previously allocated.
85 if (tl_ptr.get() == nullptr) {
86 tl_ptr.set_pointer(new __thread_struct);
87 }
88 __thread_local_data()->notify_all_at_thread_exit(&cond, lk.release());
89}
90
91_LIBCPP_END_NAMESPACE_STD
92
93#endif // !_LIBCPP_HAS_NO_THREADS
lib/libcxx/src/condition_variable_destructor.cpp created+46
...@@ -0,0 +1,46 @@
1//===---------------- condition_variable_destructor.cpp ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Define ~condition_variable.
10//
11// On some platforms ~condition_variable has been made trivial and the
12// definition is only provided for ABI compatibility.
13
14#include "__config"
15#include "__threading_support"
16
17#if !defined(_LIBCPP_HAS_NO_THREADS)
18# if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION)
19# define NEEDS_CONDVAR_DESTRUCTOR
20# endif
21#endif
22
23_LIBCPP_BEGIN_NAMESPACE_STD
24
25#ifdef NEEDS_CONDVAR_DESTRUCTOR
26
27class _LIBCPP_TYPE_VIS condition_variable
28{
29 __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER;
30public:
31 _LIBCPP_INLINE_VISIBILITY
32 constexpr condition_variable() noexcept = default;
33
34 ~condition_variable();
35
36 condition_variable(const condition_variable&) = delete;
37 condition_variable& operator=(const condition_variable&) = delete;
38};
39
40condition_variable::~condition_variable()
41{
42 __libcpp_condvar_destroy(&__cv_);
43}
44#endif
45
46_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/debug.cpp created+578
...@@ -0,0 +1,578 @@
1//===-------------------------- debug.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10#include "__debug"
11#include "functional"
12#include "algorithm"
13#include "string"
14#include "cstdio"
15#include "__hash_table"
16#ifndef _LIBCPP_HAS_NO_THREADS
17#include "mutex"
18#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
19#pragma comment(lib, "pthread")
20#endif
21#endif
22
23_LIBCPP_BEGIN_NAMESPACE_STD
24
25std::string __libcpp_debug_info::what() const {
26 string msg = __file_;
27 msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
28 msg += __pred_;
29 msg += "' failed. ";
30 msg += __msg_;
31 return msg;
32}
33_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
34 std::fprintf(stderr, "%s\n", info.what().c_str());
35 std::abort();
36}
37
38_LIBCPP_SAFE_STATIC __libcpp_debug_function_type
39 __libcpp_debug_function = __libcpp_abort_debug_function;
40
41bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
42 __libcpp_debug_function = __func;
43 return true;
44}
45
46_LIBCPP_FUNC_VIS
47__libcpp_db*
48__get_db()
49{
50 static _LIBCPP_NO_DESTROY __libcpp_db db;
51 return &db;
52}
53
54_LIBCPP_FUNC_VIS
55const __libcpp_db*
56__get_const_db()
57{
58 return __get_db();
59}
60
61namespace
62{
63
64#ifndef _LIBCPP_HAS_NO_THREADS
65typedef mutex mutex_type;
66typedef lock_guard<mutex_type> WLock;
67typedef lock_guard<mutex_type> RLock;
68
69mutex_type&
70mut()
71{
72 static _LIBCPP_NO_DESTROY mutex_type m;
73 return m;
74}
75#endif // !_LIBCPP_HAS_NO_THREADS
76
77} // unnamed namespace
78
79__i_node::~__i_node()
80{
81 if (__next_)
82 {
83 __next_->~__i_node();
84 free(__next_);
85 }
86}
87
88__c_node::~__c_node()
89{
90 free(beg_);
91 if (__next_)
92 {
93 __next_->~__c_node();
94 free(__next_);
95 }
96}
97
98__libcpp_db::__libcpp_db()
99 : __cbeg_(nullptr),
100 __cend_(nullptr),
101 __csz_(0),
102 __ibeg_(nullptr),
103 __iend_(nullptr),
104 __isz_(0)
105{
106}
107
108__libcpp_db::~__libcpp_db()
109{
110 if (__cbeg_)
111 {
112 for (__c_node** p = __cbeg_; p != __cend_; ++p)
113 {
114 if (*p != nullptr)
115 {
116 (*p)->~__c_node();
117 free(*p);
118 }
119 }
120 free(__cbeg_);
121 }
122 if (__ibeg_)
123 {
124 for (__i_node** p = __ibeg_; p != __iend_; ++p)
125 {
126 if (*p != nullptr)
127 {
128 (*p)->~__i_node();
129 free(*p);
130 }
131 }
132 free(__ibeg_);
133 }
134}
135
136void*
137__libcpp_db::__find_c_from_i(void* __i) const
138{
139#ifndef _LIBCPP_HAS_NO_THREADS
140 RLock _(mut());
141#endif
142 __i_node* i = __find_iterator(__i);
143 _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
144 return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
145}
146
147void
148__libcpp_db::__insert_ic(void* __i, const void* __c)
149{
150#ifndef _LIBCPP_HAS_NO_THREADS
151 WLock _(mut());
152#endif
153 if (__cbeg_ == __cend_)
154 return;
155 size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
156 __c_node* c = __cbeg_[hc];
157 if (c == nullptr)
158 return;
159 while (c->__c_ != __c)
160 {
161 c = c->__next_;
162 if (c == nullptr)
163 return;
164 }
165 __i_node* i = __insert_iterator(__i);
166 c->__add(i);
167 i->__c_ = c;
168}
169
170void
171__libcpp_db::__insert_c(void* __c, __libcpp_db::_InsertConstruct *__fn)
172{
173#ifndef _LIBCPP_HAS_NO_THREADS
174 WLock _(mut());
175#endif
176 if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
177 {
178 size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
179 __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(__c_node*)));
180 if (cbeg == nullptr)
181 __throw_bad_alloc();
182
183 for (__c_node** p = __cbeg_; p != __cend_; ++p)
184 {
185 __c_node* q = *p;
186 while (q != nullptr)
187 {
188 size_t h = hash<void*>()(q->__c_) % nc;
189 __c_node* r = q->__next_;
190 q->__next_ = cbeg[h];
191 cbeg[h] = q;
192 q = r;
193 }
194 }
195 free(__cbeg_);
196 __cbeg_ = cbeg;
197 __cend_ = __cbeg_ + nc;
198 }
199 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
200 __c_node* p = __cbeg_[hc];
201 void *buf = malloc(sizeof(__c_node));
202 if (buf == nullptr)
203 __throw_bad_alloc();
204 __cbeg_[hc] = __fn(buf, __c, p);
205
206 ++__csz_;
207}
208
209void
210__libcpp_db::__erase_i(void* __i)
211{
212#ifndef _LIBCPP_HAS_NO_THREADS
213 WLock _(mut());
214#endif
215 if (__ibeg_ != __iend_)
216 {
217 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
218 __i_node* p = __ibeg_[hi];
219 if (p != nullptr)
220 {
221 __i_node* q = nullptr;
222 while (p->__i_ != __i)
223 {
224 q = p;
225 p = p->__next_;
226 if (p == nullptr)
227 return;
228 }
229 if (q == nullptr)
230 __ibeg_[hi] = p->__next_;
231 else
232 q->__next_ = p->__next_;
233 __c_node* c = p->__c_;
234 --__isz_;
235 if (c != nullptr)
236 c->__remove(p);
237 free(p);
238 }
239 }
240}
241
242void
243__libcpp_db::__invalidate_all(void* __c)
244{
245#ifndef _LIBCPP_HAS_NO_THREADS
246 WLock _(mut());
247#endif
248 if (__cend_ != __cbeg_)
249 {
250 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
251 __c_node* p = __cbeg_[hc];
252 if (p == nullptr)
253 return;
254 while (p->__c_ != __c)
255 {
256 p = p->__next_;
257 if (p == nullptr)
258 return;
259 }
260 while (p->end_ != p->beg_)
261 {
262 --p->end_;
263 (*p->end_)->__c_ = nullptr;
264 }
265 }
266}
267
268__c_node*
269__libcpp_db::__find_c_and_lock(void* __c) const
270{
271#ifndef _LIBCPP_HAS_NO_THREADS
272 mut().lock();
273#endif
274 if (__cend_ == __cbeg_)
275 {
276#ifndef _LIBCPP_HAS_NO_THREADS
277 mut().unlock();
278#endif
279 return nullptr;
280 }
281 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
282 __c_node* p = __cbeg_[hc];
283 if (p == nullptr)
284 {
285#ifndef _LIBCPP_HAS_NO_THREADS
286 mut().unlock();
287#endif
288 return nullptr;
289 }
290 while (p->__c_ != __c)
291 {
292 p = p->__next_;
293 if (p == nullptr)
294 {
295#ifndef _LIBCPP_HAS_NO_THREADS
296 mut().unlock();
297#endif
298 return nullptr;
299 }
300 }
301 return p;
302}
303
304__c_node*
305__libcpp_db::__find_c(void* __c) const
306{
307 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
308 __c_node* p = __cbeg_[hc];
309 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
310 while (p->__c_ != __c)
311 {
312 p = p->__next_;
313 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
314 }
315 return p;
316}
317
318void
319__libcpp_db::unlock() const
320{
321#ifndef _LIBCPP_HAS_NO_THREADS
322 mut().unlock();
323#endif
324}
325
326void
327__libcpp_db::__erase_c(void* __c)
328{
329#ifndef _LIBCPP_HAS_NO_THREADS
330 WLock _(mut());
331#endif
332 if (__cend_ != __cbeg_)
333 {
334 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
335 __c_node* p = __cbeg_[hc];
336 if (p == nullptr)
337 return;
338 __c_node* q = nullptr;
339 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
340 while (p->__c_ != __c)
341 {
342 q = p;
343 p = p->__next_;
344 if (p == nullptr)
345 return;
346 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
347 }
348 if (q == nullptr)
349 __cbeg_[hc] = p->__next_;
350 else
351 q->__next_ = p->__next_;
352 while (p->end_ != p->beg_)
353 {
354 --p->end_;
355 (*p->end_)->__c_ = nullptr;
356 }
357 free(p->beg_);
358 free(p);
359 --__csz_;
360 }
361}
362
363void
364__libcpp_db::__iterator_copy(void* __i, const void* __i0)
365{
366#ifndef _LIBCPP_HAS_NO_THREADS
367 WLock _(mut());
368#endif
369 __i_node* i = __find_iterator(__i);
370 __i_node* i0 = __find_iterator(__i0);
371 __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
372 if (i == nullptr && i0 != nullptr)
373 i = __insert_iterator(__i);
374 __c_node* c = i != nullptr ? i->__c_ : nullptr;
375 if (c != c0)
376 {
377 if (c != nullptr)
378 c->__remove(i);
379 if (i != nullptr)
380 {
381 i->__c_ = nullptr;
382 if (c0 != nullptr)
383 {
384 i->__c_ = c0;
385 i->__c_->__add(i);
386 }
387 }
388 }
389}
390
391bool
392__libcpp_db::__dereferenceable(const void* __i) const
393{
394#ifndef _LIBCPP_HAS_NO_THREADS
395 RLock _(mut());
396#endif
397 __i_node* i = __find_iterator(__i);
398 return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
399}
400
401bool
402__libcpp_db::__decrementable(const void* __i) const
403{
404#ifndef _LIBCPP_HAS_NO_THREADS
405 RLock _(mut());
406#endif
407 __i_node* i = __find_iterator(__i);
408 return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
409}
410
411bool
412__libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
413{
414#ifndef _LIBCPP_HAS_NO_THREADS
415 RLock _(mut());
416#endif
417 __i_node* i = __find_iterator(__i);
418 return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
419}
420
421bool
422__libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
423{
424#ifndef _LIBCPP_HAS_NO_THREADS
425 RLock _(mut());
426#endif
427 __i_node* i = __find_iterator(__i);
428 return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
429}
430
431bool
432__libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
433{
434#ifndef _LIBCPP_HAS_NO_THREADS
435 RLock _(mut());
436#endif
437 __i_node* i = __find_iterator(__i);
438 __i_node* j = __find_iterator(__j);
439 __c_node* ci = i != nullptr ? i->__c_ : nullptr;
440 __c_node* cj = j != nullptr ? j->__c_ : nullptr;
441 return ci != nullptr && ci == cj;
442}
443
444void
445__libcpp_db::swap(void* c1, void* c2)
446{
447#ifndef _LIBCPP_HAS_NO_THREADS
448 WLock _(mut());
449#endif
450 size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
451 __c_node* p1 = __cbeg_[hc];
452 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
453 while (p1->__c_ != c1)
454 {
455 p1 = p1->__next_;
456 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
457 }
458 hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
459 __c_node* p2 = __cbeg_[hc];
460 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
461 while (p2->__c_ != c2)
462 {
463 p2 = p2->__next_;
464 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
465 }
466 std::swap(p1->beg_, p2->beg_);
467 std::swap(p1->end_, p2->end_);
468 std::swap(p1->cap_, p2->cap_);
469 for (__i_node** p = p1->beg_; p != p1->end_; ++p)
470 (*p)->__c_ = p1;
471 for (__i_node** p = p2->beg_; p != p2->end_; ++p)
472 (*p)->__c_ = p2;
473}
474
475void
476__libcpp_db::__insert_i(void* __i)
477{
478#ifndef _LIBCPP_HAS_NO_THREADS
479 WLock _(mut());
480#endif
481 __insert_iterator(__i);
482}
483
484void
485__c_node::__add(__i_node* i)
486{
487 if (end_ == cap_)
488 {
489 size_t nc = 2*static_cast<size_t>(cap_ - beg_);
490 if (nc == 0)
491 nc = 1;
492 __i_node** beg =
493 static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
494 if (beg == nullptr)
495 __throw_bad_alloc();
496
497 if (nc > 1)
498 memcpy(beg, beg_, nc/2*sizeof(__i_node*));
499 free(beg_);
500 beg_ = beg;
501 end_ = beg_ + nc/2;
502 cap_ = beg_ + nc;
503 }
504 *end_++ = i;
505}
506
507// private api
508
509_LIBCPP_HIDDEN
510__i_node*
511__libcpp_db::__insert_iterator(void* __i)
512{
513 if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
514 {
515 size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
516 __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(__i_node*)));
517 if (ibeg == nullptr)
518 __throw_bad_alloc();
519
520 for (__i_node** p = __ibeg_; p != __iend_; ++p)
521 {
522 __i_node* q = *p;
523 while (q != nullptr)
524 {
525 size_t h = hash<void*>()(q->__i_) % nc;
526 __i_node* r = q->__next_;
527 q->__next_ = ibeg[h];
528 ibeg[h] = q;
529 q = r;
530 }
531 }
532 free(__ibeg_);
533 __ibeg_ = ibeg;
534 __iend_ = __ibeg_ + nc;
535 }
536 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
537 __i_node* p = __ibeg_[hi];
538 __i_node* r = __ibeg_[hi] =
539 static_cast<__i_node*>(malloc(sizeof(__i_node)));
540 if (r == nullptr)
541 __throw_bad_alloc();
542
543 ::new(r) __i_node(__i, p, nullptr);
544 ++__isz_;
545 return r;
546}
547
548_LIBCPP_HIDDEN
549__i_node*
550__libcpp_db::__find_iterator(const void* __i) const
551{
552 __i_node* r = nullptr;
553 if (__ibeg_ != __iend_)
554 {
555 size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
556 for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
557 {
558 if (nd->__i_ == __i)
559 {
560 r = nd;
561 break;
562 }
563 }
564 }
565 return r;
566}
567
568_LIBCPP_HIDDEN
569void
570__c_node::__remove(__i_node* p)
571{
572 __i_node** r = find(beg_, end_, p);
573 _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
574 if (--end_ != r)
575 memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
576}
577
578_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/exception.cpp created+35
...@@ -0,0 +1,35 @@
1//===------------------------ exception.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "exception"
10#include "new"
11#include "typeinfo"
12
13#if defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
14 #include <cxxabi.h>
15 using namespace __cxxabiv1;
16 #define HAVE_DEPENDENT_EH_ABI 1
17#endif
18
19#if defined(_LIBCPP_ABI_MICROSOFT)
20#include "support/runtime/exception_msvc.ipp"
21#include "support/runtime/exception_pointer_msvc.ipp"
22#elif defined(_LIBCPPABI_VERSION)
23#include "support/runtime/exception_libcxxabi.ipp"
24#include "support/runtime/exception_pointer_cxxabi.ipp"
25#elif defined(LIBCXXRT)
26#include "support/runtime/exception_libcxxrt.ipp"
27#include "support/runtime/exception_pointer_cxxabi.ipp"
28#elif defined(__GLIBCXX__)
29#include "support/runtime/exception_glibcxx.ipp"
30#include "support/runtime/exception_pointer_glibcxx.ipp"
31#else
32#include "include/atomic_support.h"
33#include "support/runtime/exception_fallback.ipp"
34#include "support/runtime/exception_pointer_unimplemented.ipp"
35#endif
lib/libcxx/src/experimental/memory_resource.cpp created+161
...@@ -0,0 +1,161 @@
1//===------------------------ memory_resource.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "experimental/memory_resource"
10
11#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
12#include "atomic"
13#elif !defined(_LIBCPP_HAS_NO_THREADS)
14#include "mutex"
15#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
16#pragma comment(lib, "pthread")
17#endif
18#endif
19
20_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
21
22// memory_resource
23
24//memory_resource::~memory_resource() {}
25
26// new_delete_resource()
27
28class _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
29 : public memory_resource
30{
31 void *do_allocate(size_t size, size_t align) override {
32#ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
33 if (__is_overaligned_for_new(align))
34 __throw_bad_alloc();
35#endif
36 return _VSTD::__libcpp_allocate(size, align);
37 }
38
39 void do_deallocate(void *p, size_t n, size_t align) override {
40 _VSTD::__libcpp_deallocate(p, n, align);
41 }
42
43 bool do_is_equal(memory_resource const & other) const _NOEXCEPT override
44 { return &other == this; }
45
46public:
47 ~__new_delete_memory_resource_imp() override = default;
48};
49
50// null_memory_resource()
51
52class _LIBCPP_TYPE_VIS __null_memory_resource_imp
53 : public memory_resource
54{
55public:
56 ~__null_memory_resource_imp() = default;
57
58protected:
59 virtual void* do_allocate(size_t, size_t) {
60 __throw_bad_alloc();
61 }
62 virtual void do_deallocate(void *, size_t, size_t) {}
63 virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
64 { return &__other == this; }
65};
66
67namespace {
68
69union ResourceInitHelper {
70 struct {
71 __new_delete_memory_resource_imp new_delete_res;
72 __null_memory_resource_imp null_res;
73 } resources;
74 char dummy;
75 _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
76 ~ResourceInitHelper() {}
77};
78
79// Detect if the init_priority attribute is supported.
80#if (defined(_LIBCPP_COMPILER_GCC) && defined(__APPLE__)) \
81 || defined(_LIBCPP_COMPILER_MSVC)
82// GCC on Apple doesn't support the init priority attribute,
83// and MSVC doesn't support any GCC attributes.
84# define _LIBCPP_INIT_PRIORITY_MAX
85#else
86# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101)))
87#endif
88
89// When compiled in C++14 this initialization should be a constant expression.
90// Only in C++11 is "init_priority" needed to ensure initialization order.
91#if _LIBCPP_STD_VER > 11
92_LIBCPP_SAFE_STATIC
93#endif
94ResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX;
95
96} // end namespace
97
98
99memory_resource * new_delete_resource() _NOEXCEPT {
100 return &res_init.resources.new_delete_res;
101}
102
103memory_resource * null_memory_resource() _NOEXCEPT {
104 return &res_init.resources.null_res;
105}
106
107// default_memory_resource()
108
109static memory_resource *
110__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
111{
112#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
113 _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
114 ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
115 if (set) {
116 new_res = new_res ? new_res : new_delete_resource();
117 // TODO: Can a weaker ordering be used?
118 return _VSTD::atomic_exchange_explicit(
119 &__res, new_res, memory_order_acq_rel);
120 }
121 else {
122 return _VSTD::atomic_load_explicit(
123 &__res, memory_order_acquire);
124 }
125#elif !defined(_LIBCPP_HAS_NO_THREADS)
126 _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
127 static mutex res_lock;
128 if (set) {
129 new_res = new_res ? new_res : new_delete_resource();
130 lock_guard<mutex> guard(res_lock);
131 memory_resource * old_res = res;
132 res = new_res;
133 return old_res;
134 } else {
135 lock_guard<mutex> guard(res_lock);
136 return res;
137 }
138#else
139 _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
140 if (set) {
141 new_res = new_res ? new_res : new_delete_resource();
142 memory_resource * old_res = res;
143 res = new_res;
144 return old_res;
145 } else {
146 return res;
147 }
148#endif
149}
150
151memory_resource * get_default_resource() _NOEXCEPT
152{
153 return __default_memory_resource();
154}
155
156memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
157{
158 return __default_memory_resource(true, __new_res);
159}
160
161_LIBCPP_END_NAMESPACE_LFTS_PMR
lib/libcxx/src/filesystem/directory_iterator.cpp created+398
...@@ -0,0 +1,398 @@
1//===------------------ directory_iterator.cpp ----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "filesystem"
10#include "__config"
11#if defined(_LIBCPP_WIN32API)
12#define WIN32_LEAN_AND_MEAN
13#include <windows.h>
14#else
15#include <dirent.h>
16#endif
17#include <errno.h>
18
19#include "filesystem_common.h"
20
21_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
22
23namespace detail {
24namespace {
25
26#if !defined(_LIBCPP_WIN32API)
27
28#if defined(DT_BLK)
29template <class DirEntT, class = decltype(DirEntT::d_type)>
30static file_type get_file_type(DirEntT* ent, int) {
31 switch (ent->d_type) {
32 case DT_BLK:
33 return file_type::block;
34 case DT_CHR:
35 return file_type::character;
36 case DT_DIR:
37 return file_type::directory;
38 case DT_FIFO:
39 return file_type::fifo;
40 case DT_LNK:
41 return file_type::symlink;
42 case DT_REG:
43 return file_type::regular;
44 case DT_SOCK:
45 return file_type::socket;
46 // Unlike in lstat, hitting "unknown" here simply means that the underlying
47 // filesystem doesn't support d_type. Report is as 'none' so we correctly
48 // set the cache to empty.
49 case DT_UNKNOWN:
50 break;
51 }
52 return file_type::none;
53}
54#endif // defined(DT_BLK)
55
56template <class DirEntT>
57static file_type get_file_type(DirEntT* ent, long) {
58 return file_type::none;
59}
60
61static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
62 error_code& ec) {
63 struct dirent* dir_entry_ptr = nullptr;
64 errno = 0; // zero errno in order to detect errors
65 ec.clear();
66 if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
67 if (errno)
68 ec = capture_errno();
69 return {};
70 } else {
71 return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
72 }
73}
74#else
75
76static file_type get_file_type(const WIN32_FIND_DATA& data) {
77 //auto attrs = data.dwFileAttributes;
78 // FIXME(EricWF)
79 return file_type::unknown;
80}
81static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
82 return (data.nFileSizeHigh * (MAXDWORD + 1)) + data.nFileSizeLow;
83}
84static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
85 ULARGE_INTEGER tmp;
86 const FILETIME& time = data.ftLastWriteTime;
87 tmp.u.LowPart = time.dwLowDateTime;
88 tmp.u.HighPart = time.dwHighDateTime;
89 return file_time_type(file_time_type::duration(tmp.QuadPart));
90}
91
92#endif
93
94} // namespace
95} // namespace detail
96
97using detail::ErrorHandler;
98
99#if defined(_LIBCPP_WIN32API)
100class __dir_stream {
101public:
102 __dir_stream() = delete;
103 __dir_stream& operator=(const __dir_stream&) = delete;
104
105 __dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_),
106 __root_(move(__ds.__root_)),
107 __entry_(move(__ds.__entry_)) {
108 __ds.__stream_ = INVALID_HANDLE_VALUE;
109 }
110
111 __dir_stream(const path& root, directory_options opts, error_code& ec)
112 : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
113 __stream_ = ::FindFirstFile(root.c_str(), &__data_);
114 if (__stream_ == INVALID_HANDLE_VALUE) {
115 ec = error_code(::GetLastError(), generic_category());
116 const bool ignore_permission_denied =
117 bool(opts & directory_options::skip_permission_denied);
118 if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
119 ec.clear();
120 return;
121 }
122 }
123
124 ~__dir_stream() noexcept {
125 if (__stream_ == INVALID_HANDLE_VALUE)
126 return;
127 close();
128 }
129
130 bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
131
132 bool advance(error_code& ec) {
133 while (::FindNextFile(__stream_, &__data_)) {
134 if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
135 continue;
136 // FIXME: Cache more of this
137 //directory_entry::__cached_data cdata;
138 //cdata.__type_ = get_file_type(__data_);
139 //cdata.__size_ = get_file_size(__data_);
140 //cdata.__write_time_ = get_write_time(__data_);
141 __entry_.__assign_iter_entry(
142 __root_ / __data_.cFileName,
143 directory_entry::__create_iter_result(detail::get_file_type(__data)));
144 return true;
145 }
146 ec = error_code(::GetLastError(), generic_category());
147 close();
148 return false;
149 }
150
151private:
152 error_code close() noexcept {
153 error_code ec;
154 if (!::FindClose(__stream_))
155 ec = error_code(::GetLastError(), generic_category());
156 __stream_ = INVALID_HANDLE_VALUE;
157 return ec;
158 }
159
160 HANDLE __stream_{INVALID_HANDLE_VALUE};
161 WIN32_FIND_DATA __data_;
162
163public:
164 path __root_;
165 directory_entry __entry_;
166};
167#else
168class __dir_stream {
169public:
170 __dir_stream() = delete;
171 __dir_stream& operator=(const __dir_stream&) = delete;
172
173 __dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_),
174 __root_(move(other.__root_)),
175 __entry_(move(other.__entry_)) {
176 other.__stream_ = nullptr;
177 }
178
179 __dir_stream(const path& root, directory_options opts, error_code& ec)
180 : __stream_(nullptr), __root_(root) {
181 if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
182 ec = detail::capture_errno();
183 const bool allow_eacess =
184 bool(opts & directory_options::skip_permission_denied);
185 if (allow_eacess && ec.value() == EACCES)
186 ec.clear();
187 return;
188 }
189 advance(ec);
190 }
191
192 ~__dir_stream() noexcept {
193 if (__stream_)
194 close();
195 }
196
197 bool good() const noexcept { return __stream_ != nullptr; }
198
199 bool advance(error_code& ec) {
200 while (true) {
201 auto str_type_pair = detail::posix_readdir(__stream_, ec);
202 auto& str = str_type_pair.first;
203 if (str == "." || str == "..") {
204 continue;
205 } else if (ec || str.empty()) {
206 close();
207 return false;
208 } else {
209 __entry_.__assign_iter_entry(
210 __root_ / str,
211 directory_entry::__create_iter_result(str_type_pair.second));
212 return true;
213 }
214 }
215 }
216
217private:
218 error_code close() noexcept {
219 error_code m_ec;
220 if (::closedir(__stream_) == -1)
221 m_ec = detail::capture_errno();
222 __stream_ = nullptr;
223 return m_ec;
224 }
225
226 DIR* __stream_{nullptr};
227
228public:
229 path __root_;
230 directory_entry __entry_;
231};
232#endif
233
234// directory_iterator
235
236directory_iterator::directory_iterator(const path& p, error_code* ec,
237 directory_options opts) {
238 ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
239
240 error_code m_ec;
241 __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
242 if (ec)
243 *ec = m_ec;
244 if (!__imp_->good()) {
245 __imp_.reset();
246 if (m_ec)
247 err.report(m_ec);
248 }
249}
250
251directory_iterator& directory_iterator::__increment(error_code* ec) {
252 _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
253 ErrorHandler<void> err("directory_iterator::operator++()", ec);
254
255 error_code m_ec;
256 if (!__imp_->advance(m_ec)) {
257 path root = move(__imp_->__root_);
258 __imp_.reset();
259 if (m_ec)
260 err.report(m_ec, "at root \"%s\"", root);
261 }
262 return *this;
263}
264
265directory_entry const& directory_iterator::__dereference() const {
266 _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
267 return __imp_->__entry_;
268}
269
270// recursive_directory_iterator
271
272struct recursive_directory_iterator::__shared_imp {
273 stack<__dir_stream> __stack_;
274 directory_options __options_;
275};
276
277recursive_directory_iterator::recursive_directory_iterator(
278 const path& p, directory_options opt, error_code* ec)
279 : __imp_(nullptr), __rec_(true) {
280 ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
281
282 error_code m_ec;
283 __dir_stream new_s(p, opt, m_ec);
284 if (m_ec)
285 err.report(m_ec);
286 if (m_ec || !new_s.good())
287 return;
288
289 __imp_ = make_shared<__shared_imp>();
290 __imp_->__options_ = opt;
291 __imp_->__stack_.push(move(new_s));
292}
293
294void recursive_directory_iterator::__pop(error_code* ec) {
295 _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
296 if (ec)
297 ec->clear();
298 __imp_->__stack_.pop();
299 if (__imp_->__stack_.size() == 0)
300 __imp_.reset();
301 else
302 __advance(ec);
303}
304
305directory_options recursive_directory_iterator::options() const {
306 return __imp_->__options_;
307}
308
309int recursive_directory_iterator::depth() const {
310 return __imp_->__stack_.size() - 1;
311}
312
313const directory_entry& recursive_directory_iterator::__dereference() const {
314 return __imp_->__stack_.top().__entry_;
315}
316
317recursive_directory_iterator&
318recursive_directory_iterator::__increment(error_code* ec) {
319 if (ec)
320 ec->clear();
321 if (recursion_pending()) {
322 if (__try_recursion(ec) || (ec && *ec))
323 return *this;
324 }
325 __rec_ = true;
326 __advance(ec);
327 return *this;
328}
329
330void recursive_directory_iterator::__advance(error_code* ec) {
331 ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
332
333 const directory_iterator end_it;
334 auto& stack = __imp_->__stack_;
335 error_code m_ec;
336 while (stack.size() > 0) {
337 if (stack.top().advance(m_ec))
338 return;
339 if (m_ec)
340 break;
341 stack.pop();
342 }
343
344 if (m_ec) {
345 path root = move(stack.top().__root_);
346 __imp_.reset();
347 err.report(m_ec, "at root \"%s\"", root);
348 } else {
349 __imp_.reset();
350 }
351}
352
353bool recursive_directory_iterator::__try_recursion(error_code* ec) {
354 ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
355
356 bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
357
358 auto& curr_it = __imp_->__stack_.top();
359
360 bool skip_rec = false;
361 error_code m_ec;
362 if (!rec_sym) {
363 file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
364 if (m_ec && status_known(st))
365 m_ec.clear();
366 if (m_ec || is_symlink(st) || !is_directory(st))
367 skip_rec = true;
368 } else {
369 file_status st(curr_it.__entry_.__get_ft(&m_ec));
370 if (m_ec && status_known(st))
371 m_ec.clear();
372 if (m_ec || !is_directory(st))
373 skip_rec = true;
374 }
375
376 if (!skip_rec) {
377 __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
378 if (new_it.good()) {
379 __imp_->__stack_.push(move(new_it));
380 return true;
381 }
382 }
383 if (m_ec) {
384 const bool allow_eacess =
385 bool(__imp_->__options_ & directory_options::skip_permission_denied);
386 if (m_ec.value() == EACCES && allow_eacess) {
387 if (ec)
388 ec->clear();
389 } else {
390 path at_ent = move(curr_it.__entry_.__p_);
391 __imp_.reset();
392 err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
393 }
394 }
395 return false;
396}
397
398_LIBCPP_END_NAMESPACE_FILESYSTEM
lib/libcxx/src/filesystem/filesystem_common.h created+435
...@@ -0,0 +1,435 @@
1//===----------------------------------------------------------------------===////
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===////
8
9#ifndef FILESYSTEM_COMMON_H
10#define FILESYSTEM_COMMON_H
11
12#include "__config"
13#include "filesystem"
14#include "array"
15#include "chrono"
16#include "cstdlib"
17#include "climits"
18
19#include <unistd.h>
20#include <sys/stat.h>
21#include <sys/statvfs.h>
22#include <sys/time.h> // for ::utimes as used in __last_write_time
23#include <fcntl.h> /* values for fchmodat */
24
25#include "../include/apple_availability.h"
26
27#if !defined(__APPLE__)
28// We can use the presence of UTIME_OMIT to detect platforms that provide
29// utimensat.
30#if defined(UTIME_OMIT)
31#define _LIBCPP_USE_UTIMENSAT
32#endif
33#endif
34
35#if defined(__GNUC__)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wunused-function"
38#endif
39
40_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
41
42namespace detail {
43namespace {
44
45static string format_string_imp(const char* msg, ...) {
46 // we might need a second shot at this, so pre-emptivly make a copy
47 struct GuardVAList {
48 va_list& target;
49 bool active = true;
50 GuardVAList(va_list& target) : target(target), active(true) {}
51 void clear() {
52 if (active)
53 va_end(target);
54 active = false;
55 }
56 ~GuardVAList() {
57 if (active)
58 va_end(target);
59 }
60 };
61 va_list args;
62 va_start(args, msg);
63 GuardVAList args_guard(args);
64
65 va_list args_cp;
66 va_copy(args_cp, args);
67 GuardVAList args_copy_guard(args_cp);
68
69 std::string result;
70
71 array<char, 256> local_buff;
72 size_t size_with_null = local_buff.size();
73 auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
74
75 args_copy_guard.clear();
76
77 // handle empty expansion
78 if (ret == 0)
79 return result;
80 if (static_cast<size_t>(ret) < size_with_null) {
81 result.assign(local_buff.data(), static_cast<size_t>(ret));
82 return result;
83 }
84
85 // we did not provide a long enough buffer on our first attempt. The
86 // return value is the number of bytes (excluding the null byte) that are
87 // needed for formatting.
88 size_with_null = static_cast<size_t>(ret) + 1;
89 result.__resize_default_init(size_with_null - 1);
90 ret = ::vsnprintf(&result[0], size_with_null, msg, args);
91 _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
92
93 return result;
94}
95
96const char* unwrap(string const& s) { return s.c_str(); }
97const char* unwrap(path const& p) { return p.native().c_str(); }
98template <class Arg>
99Arg const& unwrap(Arg const& a) {
100 static_assert(!is_class<Arg>::value, "cannot pass class here");
101 return a;
102}
103
104template <class... Args>
105string format_string(const char* fmt, Args const&... args) {
106 return format_string_imp(fmt, unwrap(args)...);
107}
108
109error_code capture_errno() {
110 _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
111 return error_code(errno, generic_category());
112}
113
114template <class T>
115T error_value();
116template <>
117_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
118template <>
119bool error_value<bool>() {
120 return false;
121}
122template <>
123uintmax_t error_value<uintmax_t>() {
124 return uintmax_t(-1);
125}
126template <>
127_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
128 return file_time_type::min();
129}
130template <>
131path error_value<path>() {
132 return {};
133}
134
135template <class T>
136struct ErrorHandler {
137 const char* func_name;
138 error_code* ec = nullptr;
139 const path* p1 = nullptr;
140 const path* p2 = nullptr;
141
142 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
143 const path* p2 = nullptr)
144 : func_name(fname), ec(ec), p1(p1), p2(p2) {
145 if (ec)
146 ec->clear();
147 }
148
149 T report(const error_code& m_ec) const {
150 if (ec) {
151 *ec = m_ec;
152 return error_value<T>();
153 }
154 string what = string("in ") + func_name;
155 switch (bool(p1) + bool(p2)) {
156 case 0:
157 __throw_filesystem_error(what, m_ec);
158 case 1:
159 __throw_filesystem_error(what, *p1, m_ec);
160 case 2:
161 __throw_filesystem_error(what, *p1, *p2, m_ec);
162 }
163 _LIBCPP_UNREACHABLE();
164 }
165
166 template <class... Args>
167 T report(const error_code& m_ec, const char* msg, Args const&... args) const {
168 if (ec) {
169 *ec = m_ec;
170 return error_value<T>();
171 }
172 string what =
173 string("in ") + func_name + ": " + format_string(msg, args...);
174 switch (bool(p1) + bool(p2)) {
175 case 0:
176 __throw_filesystem_error(what, m_ec);
177 case 1:
178 __throw_filesystem_error(what, *p1, m_ec);
179 case 2:
180 __throw_filesystem_error(what, *p1, *p2, m_ec);
181 }
182 _LIBCPP_UNREACHABLE();
183 }
184
185 T report(errc const& err) const { return report(make_error_code(err)); }
186
187 template <class... Args>
188 T report(errc const& err, const char* msg, Args const&... args) const {
189 return report(make_error_code(err), msg, args...);
190 }
191
192private:
193 ErrorHandler(ErrorHandler const&) = delete;
194 ErrorHandler& operator=(ErrorHandler const&) = delete;
195};
196
197using chrono::duration;
198using chrono::duration_cast;
199
200using TimeSpec = struct ::timespec;
201using StatT = struct ::stat;
202
203template <class FileTimeT, class TimeT,
204 bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
205struct time_util_base {
206 using rep = typename FileTimeT::rep;
207 using fs_duration = typename FileTimeT::duration;
208 using fs_seconds = duration<rep>;
209 using fs_nanoseconds = duration<rep, nano>;
210 using fs_microseconds = duration<rep, micro>;
211
212 static constexpr rep max_seconds =
213 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
214
215 static constexpr rep max_nsec =
216 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
217 fs_seconds(max_seconds))
218 .count();
219
220 static constexpr rep min_seconds =
221 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
222
223 static constexpr rep min_nsec_timespec =
224 duration_cast<fs_nanoseconds>(
225 (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
226 fs_seconds(1))
227 .count();
228
229private:
230#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
231 static constexpr fs_duration get_min_nsecs() {
232 return duration_cast<fs_duration>(
233 fs_nanoseconds(min_nsec_timespec) -
234 duration_cast<fs_nanoseconds>(fs_seconds(1)));
235 }
236 // Static assert that these values properly round trip.
237 static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
238 FileTimeT::duration::min(),
239 "value doesn't roundtrip");
240
241 static constexpr bool check_range() {
242 // This kinda sucks, but it's what happens when we don't have __int128_t.
243 if (sizeof(TimeT) == sizeof(rep)) {
244 typedef duration<long long, ratio<3600 * 24 * 365> > Years;
245 return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
246 duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
247 }
248 return max_seconds >= numeric_limits<TimeT>::max() &&
249 min_seconds <= numeric_limits<TimeT>::min();
250 }
251 static_assert(check_range(), "the representable range is unacceptable small");
252#endif
253};
254
255template <class FileTimeT, class TimeT>
256struct time_util_base<FileTimeT, TimeT, true> {
257 using rep = typename FileTimeT::rep;
258 using fs_duration = typename FileTimeT::duration;
259 using fs_seconds = duration<rep>;
260 using fs_nanoseconds = duration<rep, nano>;
261 using fs_microseconds = duration<rep, micro>;
262
263 static const rep max_seconds;
264 static const rep max_nsec;
265 static const rep min_seconds;
266 static const rep min_nsec_timespec;
267};
268
269template <class FileTimeT, class TimeT>
270const typename FileTimeT::rep
271 time_util_base<FileTimeT, TimeT, true>::max_seconds =
272 duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
273
274template <class FileTimeT, class TimeT>
275const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
276 duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
277 fs_seconds(max_seconds))
278 .count();
279
280template <class FileTimeT, class TimeT>
281const typename FileTimeT::rep
282 time_util_base<FileTimeT, TimeT, true>::min_seconds =
283 duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
284
285template <class FileTimeT, class TimeT>
286const typename FileTimeT::rep
287 time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
288 duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
289 fs_seconds(min_seconds)) +
290 fs_seconds(1))
291 .count();
292
293template <class FileTimeT, class TimeT, class TimeSpecT>
294struct time_util : time_util_base<FileTimeT, TimeT> {
295 using Base = time_util_base<FileTimeT, TimeT>;
296 using Base::max_nsec;
297 using Base::max_seconds;
298 using Base::min_nsec_timespec;
299 using Base::min_seconds;
300
301 using typename Base::fs_duration;
302 using typename Base::fs_microseconds;
303 using typename Base::fs_nanoseconds;
304 using typename Base::fs_seconds;
305
306public:
307 template <class CType, class ChronoType>
308 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
309 ChronoType time) {
310 using Lim = numeric_limits<CType>;
311 if (time > Lim::max() || time < Lim::min())
312 return false;
313 *out = static_cast<CType>(time);
314 return true;
315 }
316
317 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
318 if (tm.tv_sec >= 0) {
319 return tm.tv_sec < max_seconds ||
320 (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
321 } else if (tm.tv_sec == (min_seconds - 1)) {
322 return tm.tv_nsec >= min_nsec_timespec;
323 } else {
324 return tm.tv_sec >= min_seconds;
325 }
326 }
327
328 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
329 auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
330 auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
331 if (nsecs.count() < 0) {
332 secs = secs + fs_seconds(1);
333 nsecs = nsecs + fs_seconds(1);
334 }
335 using TLim = numeric_limits<TimeT>;
336 if (secs.count() >= 0)
337 return secs.count() <= TLim::max();
338 return secs.count() >= TLim::min();
339 }
340
341 static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
342 convert_from_timespec(TimeSpecT tm) {
343 if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
344 return FileTimeT(fs_seconds(tm.tv_sec) +
345 duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
346 } else { // tm.tv_sec < 0
347 auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
348 fs_nanoseconds(tm.tv_nsec));
349 auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
350 return FileTimeT(Dur);
351 }
352 }
353
354 template <class SubSecT>
355 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
356 set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
357 auto dur = tp.time_since_epoch();
358 auto sec_dur = duration_cast<fs_seconds>(dur);
359 auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
360 // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
361 if (subsec_dur.count() < 0) {
362 if (sec_dur.count() > min_seconds) {
363 sec_dur = sec_dur - fs_seconds(1);
364 subsec_dur = subsec_dur + fs_seconds(1);
365 } else {
366 subsec_dur = fs_nanoseconds::zero();
367 }
368 }
369 return checked_set(sec_out, sec_dur.count()) &&
370 checked_set(subsec_out, subsec_dur.count());
371 }
372 static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
373 FileTimeT tp) {
374 if (!is_representable(tp))
375 return false;
376 return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
377 }
378};
379
380using fs_time = time_util<file_time_type, time_t, TimeSpec>;
381
382#if defined(__APPLE__)
383TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
384TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
385#else
386TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
387TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
388#endif
389
390// allow the utimes implementation to compile even it we're not going
391// to use it.
392
393bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
394 error_code& ec) {
395 using namespace chrono;
396 auto Convert = [](long nsec) {
397 using int_type = decltype(std::declval< ::timeval>().tv_usec);
398 auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
399 return static_cast<int_type>(dur);
400 };
401 struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
402 {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
403 if (::utimes(p.c_str(), ConvertedTS) == -1) {
404 ec = capture_errno();
405 return true;
406 }
407 return false;
408}
409
410#if defined(_LIBCPP_USE_UTIMENSAT)
411bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
412 error_code& ec) {
413 if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
414 ec = capture_errno();
415 return true;
416 }
417 return false;
418}
419#endif
420
421bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
422 error_code& ec) {
423#if !defined(_LIBCPP_USE_UTIMENSAT)
424 return posix_utimes(p, TS, ec);
425#else
426 return posix_utimensat(p, TS, ec);
427#endif
428}
429
430} // namespace
431} // end namespace detail
432
433_LIBCPP_END_NAMESPACE_FILESYSTEM
434
435#endif // FILESYSTEM_COMMON_H
lib/libcxx/src/filesystem/operations.cpp created+1782
...@@ -0,0 +1,1782 @@
1//===--------------------- filesystem/ops.cpp -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "filesystem"
10#include "array"
11#include "iterator"
12#include "fstream"
13#include "random" /* for unique_path */
14#include "string_view"
15#include "type_traits"
16#include "vector"
17#include "cstdlib"
18#include "climits"
19
20#include "filesystem_common.h"
21
22#include <unistd.h>
23#include <sys/stat.h>
24#include <sys/statvfs.h>
25#include <time.h>
26#include <fcntl.h> /* values for fchmodat */
27
28#if defined(__linux__)
29#include <linux/version.h>
30#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
31#include <sys/sendfile.h>
32#define _LIBCPP_USE_SENDFILE
33#endif
34#elif defined(__APPLE__) || __has_include(<copyfile.h>)
35#include <copyfile.h>
36#define _LIBCPP_USE_COPYFILE
37#endif
38
39#if !defined(__APPLE__)
40#define _LIBCPP_USE_CLOCK_GETTIME
41#endif
42
43#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
44#include <sys/time.h> // for gettimeofday and timeval
45#endif // !defined(CLOCK_REALTIME)
46
47#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
48#pragma comment(lib, "rt")
49#endif
50
51#if defined(_LIBCPP_COMPILER_GCC)
52#if _GNUC_VER < 500
53#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
54#endif
55#endif
56
57_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
58
59namespace {
60namespace parser {
61
62using string_view_t = path::__string_view;
63using string_view_pair = pair<string_view_t, string_view_t>;
64using PosPtr = path::value_type const*;
65
66struct PathParser {
67 enum ParserState : unsigned char {
68 // Zero is a special sentinel value used by default constructed iterators.
69 PS_BeforeBegin = path::iterator::_BeforeBegin,
70 PS_InRootName = path::iterator::_InRootName,
71 PS_InRootDir = path::iterator::_InRootDir,
72 PS_InFilenames = path::iterator::_InFilenames,
73 PS_InTrailingSep = path::iterator::_InTrailingSep,
74 PS_AtEnd = path::iterator::_AtEnd
75 };
76
77 const string_view_t Path;
78 string_view_t RawEntry;
79 ParserState State;
80
81private:
82 PathParser(string_view_t P, ParserState State) noexcept : Path(P),
83 State(State) {}
84
85public:
86 PathParser(string_view_t P, string_view_t E, unsigned char S)
87 : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
88 // S cannot be '0' or PS_BeforeBegin.
89 }
90
91 static PathParser CreateBegin(string_view_t P) noexcept {
92 PathParser PP(P, PS_BeforeBegin);
93 PP.increment();
94 return PP;
95 }
96
97 static PathParser CreateEnd(string_view_t P) noexcept {
98 PathParser PP(P, PS_AtEnd);
99 return PP;
100 }
101
102 PosPtr peek() const noexcept {
103 auto TkEnd = getNextTokenStartPos();
104 auto End = getAfterBack();
105 return TkEnd == End ? nullptr : TkEnd;
106 }
107
108 void increment() noexcept {
109 const PosPtr End = getAfterBack();
110 const PosPtr Start = getNextTokenStartPos();
111 if (Start == End)
112 return makeState(PS_AtEnd);
113
114 switch (State) {
115 case PS_BeforeBegin: {
116 PosPtr TkEnd = consumeSeparator(Start, End);
117 if (TkEnd)
118 return makeState(PS_InRootDir, Start, TkEnd);
119 else
120 return makeState(PS_InFilenames, Start, consumeName(Start, End));
121 }
122 case PS_InRootDir:
123 return makeState(PS_InFilenames, Start, consumeName(Start, End));
124
125 case PS_InFilenames: {
126 PosPtr SepEnd = consumeSeparator(Start, End);
127 if (SepEnd != End) {
128 PosPtr TkEnd = consumeName(SepEnd, End);
129 if (TkEnd)
130 return makeState(PS_InFilenames, SepEnd, TkEnd);
131 }
132 return makeState(PS_InTrailingSep, Start, SepEnd);
133 }
134
135 case PS_InTrailingSep:
136 return makeState(PS_AtEnd);
137
138 case PS_InRootName:
139 case PS_AtEnd:
140 _LIBCPP_UNREACHABLE();
141 }
142 }
143
144 void decrement() noexcept {
145 const PosPtr REnd = getBeforeFront();
146 const PosPtr RStart = getCurrentTokenStartPos() - 1;
147 if (RStart == REnd) // we're decrementing the begin
148 return makeState(PS_BeforeBegin);
149
150 switch (State) {
151 case PS_AtEnd: {
152 // Try to consume a trailing separator or root directory first.
153 if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
154 if (SepEnd == REnd)
155 return makeState(PS_InRootDir, Path.data(), RStart + 1);
156 return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
157 } else {
158 PosPtr TkStart = consumeName(RStart, REnd);
159 return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
160 }
161 }
162 case PS_InTrailingSep:
163 return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
164 RStart + 1);
165 case PS_InFilenames: {
166 PosPtr SepEnd = consumeSeparator(RStart, REnd);
167 if (SepEnd == REnd)
168 return makeState(PS_InRootDir, Path.data(), RStart + 1);
169 PosPtr TkEnd = consumeName(SepEnd, REnd);
170 return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
171 }
172 case PS_InRootDir:
173 // return makeState(PS_InRootName, Path.data(), RStart + 1);
174 case PS_InRootName:
175 case PS_BeforeBegin:
176 _LIBCPP_UNREACHABLE();
177 }
178 }
179
180 /// \brief Return a view with the "preferred representation" of the current
181 /// element. For example trailing separators are represented as a '.'
182 string_view_t operator*() const noexcept {
183 switch (State) {
184 case PS_BeforeBegin:
185 case PS_AtEnd:
186 return "";
187 case PS_InRootDir:
188 return "/";
189 case PS_InTrailingSep:
190 return "";
191 case PS_InRootName:
192 case PS_InFilenames:
193 return RawEntry;
194 }
195 _LIBCPP_UNREACHABLE();
196 }
197
198 explicit operator bool() const noexcept {
199 return State != PS_BeforeBegin && State != PS_AtEnd;
200 }
201
202 PathParser& operator++() noexcept {
203 increment();
204 return *this;
205 }
206
207 PathParser& operator--() noexcept {
208 decrement();
209 return *this;
210 }
211
212 bool atEnd() const noexcept {
213 return State == PS_AtEnd;
214 }
215
216 bool inRootDir() const noexcept {
217 return State == PS_InRootDir;
218 }
219
220 bool inRootName() const noexcept {
221 return State == PS_InRootName;
222 }
223
224 bool inRootPath() const noexcept {
225 return inRootName() || inRootDir();
226 }
227
228private:
229 void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
230 State = NewState;
231 RawEntry = string_view_t(Start, End - Start);
232 }
233 void makeState(ParserState NewState) noexcept {
234 State = NewState;
235 RawEntry = {};
236 }
237
238 PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
239
240 PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
241
242 /// \brief Return a pointer to the first character after the currently
243 /// lexed element.
244 PosPtr getNextTokenStartPos() const noexcept {
245 switch (State) {
246 case PS_BeforeBegin:
247 return Path.data();
248 case PS_InRootName:
249 case PS_InRootDir:
250 case PS_InFilenames:
251 return &RawEntry.back() + 1;
252 case PS_InTrailingSep:
253 case PS_AtEnd:
254 return getAfterBack();
255 }
256 _LIBCPP_UNREACHABLE();
257 }
258
259 /// \brief Return a pointer to the first character in the currently lexed
260 /// element.
261 PosPtr getCurrentTokenStartPos() const noexcept {
262 switch (State) {
263 case PS_BeforeBegin:
264 case PS_InRootName:
265 return &Path.front();
266 case PS_InRootDir:
267 case PS_InFilenames:
268 case PS_InTrailingSep:
269 return &RawEntry.front();
270 case PS_AtEnd:
271 return &Path.back() + 1;
272 }
273 _LIBCPP_UNREACHABLE();
274 }
275
276 PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
277 if (P == End || *P != '/')
278 return nullptr;
279 const int Inc = P < End ? 1 : -1;
280 P += Inc;
281 while (P != End && *P == '/')
282 P += Inc;
283 return P;
284 }
285
286 PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
287 if (P == End || *P == '/')
288 return nullptr;
289 const int Inc = P < End ? 1 : -1;
290 P += Inc;
291 while (P != End && *P != '/')
292 P += Inc;
293 return P;
294 }
295};
296
297string_view_pair separate_filename(string_view_t const& s) {
298 if (s == "." || s == ".." || s.empty())
299 return string_view_pair{s, ""};
300 auto pos = s.find_last_of('.');
301 if (pos == string_view_t::npos || pos == 0)
302 return string_view_pair{s, string_view_t{}};
303 return string_view_pair{s.substr(0, pos), s.substr(pos)};
304}
305
306string_view_t createView(PosPtr S, PosPtr E) noexcept {
307 return {S, static_cast<size_t>(E - S) + 1};
308}
309
310} // namespace parser
311} // namespace
312
313// POSIX HELPERS
314
315namespace detail {
316namespace {
317
318using value_type = path::value_type;
319using string_type = path::string_type;
320
321struct FileDescriptor {
322 const path& name;
323 int fd = -1;
324 StatT m_stat;
325 file_status m_status;
326
327 template <class... Args>
328 static FileDescriptor create(const path* p, error_code& ec, Args... args) {
329 ec.clear();
330 int fd;
331 if ((fd = ::open(p->c_str(), args...)) == -1) {
332 ec = capture_errno();
333 return FileDescriptor{p};
334 }
335 return FileDescriptor(p, fd);
336 }
337
338 template <class... Args>
339 static FileDescriptor create_with_status(const path* p, error_code& ec,
340 Args... args) {
341 FileDescriptor fd = create(p, ec, args...);
342 if (!ec)
343 fd.refresh_status(ec);
344
345 return fd;
346 }
347
348 file_status get_status() const { return m_status; }
349 StatT const& get_stat() const { return m_stat; }
350
351 bool status_known() const { return _VSTD_FS::status_known(m_status); }
352
353 file_status refresh_status(error_code& ec);
354
355 void close() noexcept {
356 if (fd != -1)
357 ::close(fd);
358 fd = -1;
359 }
360
361 FileDescriptor(FileDescriptor&& other)
362 : name(other.name), fd(other.fd), m_stat(other.m_stat),
363 m_status(other.m_status) {
364 other.fd = -1;
365 other.m_status = file_status{};
366 }
367
368 ~FileDescriptor() { close(); }
369
370 FileDescriptor(FileDescriptor const&) = delete;
371 FileDescriptor& operator=(FileDescriptor const&) = delete;
372
373private:
374 explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {}
375};
376
377perms posix_get_perms(const StatT& st) noexcept {
378 return static_cast<perms>(st.st_mode) & perms::mask;
379}
380
381::mode_t posix_convert_perms(perms prms) {
382 return static_cast< ::mode_t>(prms & perms::mask);
383}
384
385file_status create_file_status(error_code& m_ec, path const& p,
386 const StatT& path_stat, error_code* ec) {
387 if (ec)
388 *ec = m_ec;
389 if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
390 return file_status(file_type::not_found);
391 } else if (m_ec) {
392 ErrorHandler<void> err("posix_stat", ec, &p);
393 err.report(m_ec, "failed to determine attributes for the specified path");
394 return file_status(file_type::none);
395 }
396 // else
397
398 file_status fs_tmp;
399 auto const mode = path_stat.st_mode;
400 if (S_ISLNK(mode))
401 fs_tmp.type(file_type::symlink);
402 else if (S_ISREG(mode))
403 fs_tmp.type(file_type::regular);
404 else if (S_ISDIR(mode))
405 fs_tmp.type(file_type::directory);
406 else if (S_ISBLK(mode))
407 fs_tmp.type(file_type::block);
408 else if (S_ISCHR(mode))
409 fs_tmp.type(file_type::character);
410 else if (S_ISFIFO(mode))
411 fs_tmp.type(file_type::fifo);
412 else if (S_ISSOCK(mode))
413 fs_tmp.type(file_type::socket);
414 else
415 fs_tmp.type(file_type::unknown);
416
417 fs_tmp.permissions(detail::posix_get_perms(path_stat));
418 return fs_tmp;
419}
420
421file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
422 error_code m_ec;
423 if (::stat(p.c_str(), &path_stat) == -1)
424 m_ec = detail::capture_errno();
425 return create_file_status(m_ec, p, path_stat, ec);
426}
427
428file_status posix_stat(path const& p, error_code* ec) {
429 StatT path_stat;
430 return posix_stat(p, path_stat, ec);
431}
432
433file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
434 error_code m_ec;
435 if (::lstat(p.c_str(), &path_stat) == -1)
436 m_ec = detail::capture_errno();
437 return create_file_status(m_ec, p, path_stat, ec);
438}
439
440file_status posix_lstat(path const& p, error_code* ec) {
441 StatT path_stat;
442 return posix_lstat(p, path_stat, ec);
443}
444
445// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
446bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
447 if (::ftruncate(fd.fd, to_size) == -1) {
448 ec = capture_errno();
449 return true;
450 }
451 ec.clear();
452 return false;
453}
454
455bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
456 if (::fchmod(fd.fd, st.st_mode) == -1) {
457 ec = capture_errno();
458 return true;
459 }
460 ec.clear();
461 return false;
462}
463
464bool stat_equivalent(const StatT& st1, const StatT& st2) {
465 return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
466}
467
468file_status FileDescriptor::refresh_status(error_code& ec) {
469 // FD must be open and good.
470 m_status = file_status{};
471 m_stat = {};
472 error_code m_ec;
473 if (::fstat(fd, &m_stat) == -1)
474 m_ec = capture_errno();
475 m_status = create_file_status(m_ec, name, m_stat, &ec);
476 return m_status;
477}
478} // namespace
479} // end namespace detail
480
481using detail::capture_errno;
482using detail::ErrorHandler;
483using detail::StatT;
484using detail::TimeSpec;
485using parser::createView;
486using parser::PathParser;
487using parser::string_view_t;
488
489const bool _FilesystemClock::is_steady;
490
491_FilesystemClock::time_point _FilesystemClock::now() noexcept {
492 typedef chrono::duration<rep> __secs;
493#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
494 typedef chrono::duration<rep, nano> __nsecs;
495 struct timespec tp;
496 if (0 != clock_gettime(CLOCK_REALTIME, &tp))
497 __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
498 return time_point(__secs(tp.tv_sec) +
499 chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
500#else
501 typedef chrono::duration<rep, micro> __microsecs;
502 timeval tv;
503 gettimeofday(&tv, 0);
504 return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
505#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
506}
507
508filesystem_error::~filesystem_error() {}
509
510void filesystem_error::__create_what(int __num_paths) {
511 const char* derived_what = system_error::what();
512 __storage_->__what_ = [&]() -> string {
513 const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str();
514 const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str();
515 switch (__num_paths) {
516 default:
517 return detail::format_string("filesystem error: %s", derived_what);
518 case 1:
519 return detail::format_string("filesystem error: %s [%s]", derived_what,
520 p1);
521 case 2:
522 return detail::format_string("filesystem error: %s [%s] [%s]",
523 derived_what, p1, p2);
524 }
525 }();
526}
527
528static path __do_absolute(const path& p, path* cwd, error_code* ec) {
529 if (ec)
530 ec->clear();
531 if (p.is_absolute())
532 return p;
533 *cwd = __current_path(ec);
534 if (ec && *ec)
535 return {};
536 return (*cwd) / p;
537}
538
539path __absolute(const path& p, error_code* ec) {
540 path cwd;
541 return __do_absolute(p, &cwd, ec);
542}
543
544path __canonical(path const& orig_p, error_code* ec) {
545 path cwd;
546 ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
547
548 path p = __do_absolute(orig_p, &cwd, ec);
549#if _POSIX_VERSION >= 200112
550 std::unique_ptr<char, decltype(&::free)>
551 hold(::realpath(p.c_str(), nullptr), &::free);
552 if (hold.get() == nullptr)
553 return err.report(capture_errno());
554 return {hold.get()};
555#else
556 char buff[PATH_MAX + 1];
557 char* ret;
558 if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
559 return err.report(capture_errno());
560 return {ret};
561#endif
562}
563
564void __copy(const path& from, const path& to, copy_options options,
565 error_code* ec) {
566 ErrorHandler<void> err("copy", ec, &from, &to);
567
568 const bool sym_status = bool(
569 options & (copy_options::create_symlinks | copy_options::skip_symlinks));
570
571 const bool sym_status2 = bool(options & copy_options::copy_symlinks);
572
573 error_code m_ec1;
574 StatT f_st = {};
575 const file_status f = sym_status || sym_status2
576 ? detail::posix_lstat(from, f_st, &m_ec1)
577 : detail::posix_stat(from, f_st, &m_ec1);
578 if (m_ec1)
579 return err.report(m_ec1);
580
581 StatT t_st = {};
582 const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
583 : detail::posix_stat(to, t_st, &m_ec1);
584
585 if (not status_known(t))
586 return err.report(m_ec1);
587
588 if (!exists(f) || is_other(f) || is_other(t) ||
589 (is_directory(f) && is_regular_file(t)) ||
590 detail::stat_equivalent(f_st, t_st)) {
591 return err.report(errc::function_not_supported);
592 }
593
594 if (ec)
595 ec->clear();
596
597 if (is_symlink(f)) {
598 if (bool(copy_options::skip_symlinks & options)) {
599 // do nothing
600 } else if (not exists(t)) {
601 __copy_symlink(from, to, ec);
602 } else {
603 return err.report(errc::file_exists);
604 }
605 return;
606 } else if (is_regular_file(f)) {
607 if (bool(copy_options::directories_only & options)) {
608 // do nothing
609 } else if (bool(copy_options::create_symlinks & options)) {
610 __create_symlink(from, to, ec);
611 } else if (bool(copy_options::create_hard_links & options)) {
612 __create_hard_link(from, to, ec);
613 } else if (is_directory(t)) {
614 __copy_file(from, to / from.filename(), options, ec);
615 } else {
616 __copy_file(from, to, options, ec);
617 }
618 return;
619 } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
620 return err.report(errc::is_a_directory);
621 } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
622 copy_options::none == options)) {
623
624 if (!exists(t)) {
625 // create directory to with attributes from 'from'.
626 __create_directory(to, from, ec);
627 if (ec && *ec) {
628 return;
629 }
630 }
631 directory_iterator it =
632 ec ? directory_iterator(from, *ec) : directory_iterator(from);
633 if (ec && *ec) {
634 return;
635 }
636 error_code m_ec2;
637 for (; it != directory_iterator(); it.increment(m_ec2)) {
638 if (m_ec2) {
639 return err.report(m_ec2);
640 }
641 __copy(it->path(), to / it->path().filename(),
642 options | copy_options::__in_recursive_copy, ec);
643 if (ec && *ec) {
644 return;
645 }
646 }
647 }
648}
649
650namespace detail {
651namespace {
652
653#ifdef _LIBCPP_USE_SENDFILE
654bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
655 error_code& ec) {
656
657 size_t count = read_fd.get_stat().st_size;
658 do {
659 ssize_t res;
660 if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
661 ec = capture_errno();
662 return false;
663 }
664 count -= res;
665 } while (count > 0);
666
667 ec.clear();
668
669 return true;
670}
671#elif defined(_LIBCPP_USE_COPYFILE)
672bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
673 error_code& ec) {
674 struct CopyFileState {
675 copyfile_state_t state;
676 CopyFileState() { state = copyfile_state_alloc(); }
677 ~CopyFileState() { copyfile_state_free(state); }
678
679 private:
680 CopyFileState(CopyFileState const&) = delete;
681 CopyFileState& operator=(CopyFileState const&) = delete;
682 };
683
684 CopyFileState cfs;
685 if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
686 ec = capture_errno();
687 return false;
688 }
689
690 ec.clear();
691 return true;
692}
693#endif
694
695// Note: This function isn't guarded by ifdef's even though it may be unused
696// in order to assure it still compiles.
697__attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd,
698 FileDescriptor& write_fd,
699 error_code& ec) {
700 ifstream in;
701 in.__open(read_fd.fd, ios::binary);
702 if (!in.is_open()) {
703 // This assumes that __open didn't reset the error code.
704 ec = capture_errno();
705 return false;
706 }
707 ofstream out;
708 out.__open(write_fd.fd, ios::binary);
709 if (!out.is_open()) {
710 ec = capture_errno();
711 return false;
712 }
713
714 if (in.good() && out.good()) {
715 using InIt = istreambuf_iterator<char>;
716 using OutIt = ostreambuf_iterator<char>;
717 InIt bin(in);
718 InIt ein;
719 OutIt bout(out);
720 copy(bin, ein, bout);
721 }
722 if (out.fail() || in.fail()) {
723 ec = make_error_code(errc::io_error);
724 return false;
725 }
726
727 ec.clear();
728 return true;
729}
730
731bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) {
732#if defined(_LIBCPP_USE_SENDFILE)
733 return copy_file_impl_sendfile(from, to, ec);
734#elif defined(_LIBCPP_USE_COPYFILE)
735 return copy_file_impl_copyfile(from, to, ec);
736#else
737 return copy_file_impl_default(from, to, ec);
738#endif
739}
740
741} // namespace
742} // namespace detail
743
744bool __copy_file(const path& from, const path& to, copy_options options,
745 error_code* ec) {
746 using detail::FileDescriptor;
747 ErrorHandler<bool> err("copy_file", ec, &to, &from);
748
749 error_code m_ec;
750 FileDescriptor from_fd =
751 FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
752 if (m_ec)
753 return err.report(m_ec);
754
755 auto from_st = from_fd.get_status();
756 StatT const& from_stat = from_fd.get_stat();
757 if (!is_regular_file(from_st)) {
758 if (not m_ec)
759 m_ec = make_error_code(errc::not_supported);
760 return err.report(m_ec);
761 }
762
763 const bool skip_existing = bool(copy_options::skip_existing & options);
764 const bool update_existing = bool(copy_options::update_existing & options);
765 const bool overwrite_existing =
766 bool(copy_options::overwrite_existing & options);
767
768 StatT to_stat_path;
769 file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
770 if (!status_known(to_st))
771 return err.report(m_ec);
772
773 const bool to_exists = exists(to_st);
774 if (to_exists && !is_regular_file(to_st))
775 return err.report(errc::not_supported);
776
777 if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
778 return err.report(errc::file_exists);
779
780 if (to_exists && skip_existing)
781 return false;
782
783 bool ShouldCopy = [&]() {
784 if (to_exists && update_existing) {
785 auto from_time = detail::extract_mtime(from_stat);
786 auto to_time = detail::extract_mtime(to_stat_path);
787 if (from_time.tv_sec < to_time.tv_sec)
788 return false;
789 if (from_time.tv_sec == to_time.tv_sec &&
790 from_time.tv_nsec <= to_time.tv_nsec)
791 return false;
792 return true;
793 }
794 if (!to_exists || overwrite_existing)
795 return true;
796 return err.report(errc::file_exists);
797 }();
798 if (!ShouldCopy)
799 return false;
800
801 // Don't truncate right away. We may not be opening the file we originally
802 // looked at; we'll check this later.
803 int to_open_flags = O_WRONLY;
804 if (!to_exists)
805 to_open_flags |= O_CREAT;
806 FileDescriptor to_fd = FileDescriptor::create_with_status(
807 &to, m_ec, to_open_flags, from_stat.st_mode);
808 if (m_ec)
809 return err.report(m_ec);
810
811 if (to_exists) {
812 // Check that the file we initially stat'ed is equivalent to the one
813 // we opened.
814 // FIXME: report this better.
815 if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
816 return err.report(errc::bad_file_descriptor);
817
818 // Set the permissions and truncate the file we opened.
819 if (detail::posix_fchmod(to_fd, from_stat, m_ec))
820 return err.report(m_ec);
821 if (detail::posix_ftruncate(to_fd, 0, m_ec))
822 return err.report(m_ec);
823 }
824
825 if (!copy_file_impl(from_fd, to_fd, m_ec)) {
826 // FIXME: Remove the dest file if we failed, and it didn't exist previously.
827 return err.report(m_ec);
828 }
829
830 return true;
831}
832
833void __copy_symlink(const path& existing_symlink, const path& new_symlink,
834 error_code* ec) {
835 const path real_path(__read_symlink(existing_symlink, ec));
836 if (ec && *ec) {
837 return;
838 }
839 // NOTE: proposal says you should detect if you should call
840 // create_symlink or create_directory_symlink. I don't think this
841 // is needed with POSIX
842 __create_symlink(real_path, new_symlink, ec);
843}
844
845bool __create_directories(const path& p, error_code* ec) {
846 ErrorHandler<bool> err("create_directories", ec, &p);
847
848 error_code m_ec;
849 auto const st = detail::posix_stat(p, &m_ec);
850 if (!status_known(st))
851 return err.report(m_ec);
852 else if (is_directory(st))
853 return false;
854 else if (exists(st))
855 return err.report(errc::file_exists);
856
857 const path parent = p.parent_path();
858 if (!parent.empty()) {
859 const file_status parent_st = status(parent, m_ec);
860 if (not status_known(parent_st))
861 return err.report(m_ec);
862 if (not exists(parent_st)) {
863 __create_directories(parent, ec);
864 if (ec && *ec) {
865 return false;
866 }
867 }
868 }
869 return __create_directory(p, ec);
870}
871
872bool __create_directory(const path& p, error_code* ec) {
873 ErrorHandler<bool> err("create_directory", ec, &p);
874
875 if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
876 return true;
877 if (errno != EEXIST)
878 err.report(capture_errno());
879 return false;
880}
881
882bool __create_directory(path const& p, path const& attributes, error_code* ec) {
883 ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
884
885 StatT attr_stat;
886 error_code mec;
887 auto st = detail::posix_stat(attributes, attr_stat, &mec);
888 if (!status_known(st))
889 return err.report(mec);
890 if (!is_directory(st))
891 return err.report(errc::not_a_directory,
892 "the specified attribute path is invalid");
893
894 if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
895 return true;
896 if (errno != EEXIST)
897 err.report(capture_errno());
898 return false;
899}
900
901void __create_directory_symlink(path const& from, path const& to,
902 error_code* ec) {
903 ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
904 if (::symlink(from.c_str(), to.c_str()) != 0)
905 return err.report(capture_errno());
906}
907
908void __create_hard_link(const path& from, const path& to, error_code* ec) {
909 ErrorHandler<void> err("create_hard_link", ec, &from, &to);
910 if (::link(from.c_str(), to.c_str()) == -1)
911 return err.report(capture_errno());
912}
913
914void __create_symlink(path const& from, path const& to, error_code* ec) {
915 ErrorHandler<void> err("create_symlink", ec, &from, &to);
916 if (::symlink(from.c_str(), to.c_str()) == -1)
917 return err.report(capture_errno());
918}
919
920path __current_path(error_code* ec) {
921 ErrorHandler<path> err("current_path", ec);
922
923 auto size = ::pathconf(".", _PC_PATH_MAX);
924 _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
925
926 auto buff = unique_ptr<char[]>(new char[size + 1]);
927 char* ret;
928 if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
929 return err.report(capture_errno(), "call to getcwd failed");
930
931 return {buff.get()};
932}
933
934void __current_path(const path& p, error_code* ec) {
935 ErrorHandler<void> err("current_path", ec, &p);
936 if (::chdir(p.c_str()) == -1)
937 err.report(capture_errno());
938}
939
940bool __equivalent(const path& p1, const path& p2, error_code* ec) {
941 ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
942
943 error_code ec1, ec2;
944 StatT st1 = {}, st2 = {};
945 auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
946 if (!exists(s1))
947 return err.report(errc::not_supported);
948 auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
949 if (!exists(s2))
950 return err.report(errc::not_supported);
951
952 return detail::stat_equivalent(st1, st2);
953}
954
955uintmax_t __file_size(const path& p, error_code* ec) {
956 ErrorHandler<uintmax_t> err("file_size", ec, &p);
957
958 error_code m_ec;
959 StatT st;
960 file_status fst = detail::posix_stat(p, st, &m_ec);
961 if (!exists(fst) || !is_regular_file(fst)) {
962 errc error_kind =
963 is_directory(fst) ? errc::is_a_directory : errc::not_supported;
964 if (!m_ec)
965 m_ec = make_error_code(error_kind);
966 return err.report(m_ec);
967 }
968 // is_regular_file(p) == true
969 return static_cast<uintmax_t>(st.st_size);
970}
971
972uintmax_t __hard_link_count(const path& p, error_code* ec) {
973 ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
974
975 error_code m_ec;
976 StatT st;
977 detail::posix_stat(p, st, &m_ec);
978 if (m_ec)
979 return err.report(m_ec);
980 return static_cast<uintmax_t>(st.st_nlink);
981}
982
983bool __fs_is_empty(const path& p, error_code* ec) {
984 ErrorHandler<bool> err("is_empty", ec, &p);
985
986 error_code m_ec;
987 StatT pst;
988 auto st = detail::posix_stat(p, pst, &m_ec);
989 if (m_ec)
990 return err.report(m_ec);
991 else if (!is_directory(st) && !is_regular_file(st))
992 return err.report(errc::not_supported);
993 else if (is_directory(st)) {
994 auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
995 if (ec && *ec)
996 return false;
997 return it == directory_iterator{};
998 } else if (is_regular_file(st))
999 return static_cast<uintmax_t>(pst.st_size) == 0;
1000
1001 _LIBCPP_UNREACHABLE();
1002}
1003
1004static file_time_type __extract_last_write_time(const path& p, const StatT& st,
1005 error_code* ec) {
1006 using detail::fs_time;
1007 ErrorHandler<file_time_type> err("last_write_time", ec, &p);
1008
1009 auto ts = detail::extract_mtime(st);
1010 if (!fs_time::is_representable(ts))
1011 return err.report(errc::value_too_large);
1012
1013 return fs_time::convert_from_timespec(ts);
1014}
1015
1016file_time_type __last_write_time(const path& p, error_code* ec) {
1017 using namespace chrono;
1018 ErrorHandler<file_time_type> err("last_write_time", ec, &p);
1019
1020 error_code m_ec;
1021 StatT st;
1022 detail::posix_stat(p, st, &m_ec);
1023 if (m_ec)
1024 return err.report(m_ec);
1025 return __extract_last_write_time(p, st, ec);
1026}
1027
1028void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
1029 using detail::fs_time;
1030 ErrorHandler<void> err("last_write_time", ec, &p);
1031
1032 error_code m_ec;
1033 array<TimeSpec, 2> tbuf;
1034#if !defined(_LIBCPP_USE_UTIMENSAT)
1035 // This implementation has a race condition between determining the
1036 // last access time and attempting to set it to the same value using
1037 // ::utimes
1038 StatT st;
1039 file_status fst = detail::posix_stat(p, st, &m_ec);
1040 if (m_ec)
1041 return err.report(m_ec);
1042 tbuf[0] = detail::extract_atime(st);
1043#else
1044 tbuf[0].tv_sec = 0;
1045 tbuf[0].tv_nsec = UTIME_OMIT;
1046#endif
1047 if (!fs_time::convert_to_timespec(tbuf[1], new_time))
1048 return err.report(errc::value_too_large);
1049
1050 detail::set_file_times(p, tbuf, m_ec);
1051 if (m_ec)
1052 return err.report(m_ec);
1053}
1054
1055void __permissions(const path& p, perms prms, perm_options opts,
1056 error_code* ec) {
1057 ErrorHandler<void> err("permissions", ec, &p);
1058
1059 auto has_opt = [&](perm_options o) { return bool(o & opts); };
1060 const bool resolve_symlinks = !has_opt(perm_options::nofollow);
1061 const bool add_perms = has_opt(perm_options::add);
1062 const bool remove_perms = has_opt(perm_options::remove);
1063 _LIBCPP_ASSERT(
1064 (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
1065 "One and only one of the perm_options constants replace, add, or remove "
1066 "is present in opts");
1067
1068 bool set_sym_perms = false;
1069 prms &= perms::mask;
1070 if (!resolve_symlinks || (add_perms || remove_perms)) {
1071 error_code m_ec;
1072 file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
1073 : detail::posix_lstat(p, &m_ec);
1074 set_sym_perms = is_symlink(st);
1075 if (m_ec)
1076 return err.report(m_ec);
1077 _LIBCPP_ASSERT(st.permissions() != perms::unknown,
1078 "Permissions unexpectedly unknown");
1079 if (add_perms)
1080 prms |= st.permissions();
1081 else if (remove_perms)
1082 prms = st.permissions() & ~prms;
1083 }
1084 const auto real_perms = detail::posix_convert_perms(prms);
1085
1086#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
1087 const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
1088 if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
1089 return err.report(capture_errno());
1090 }
1091#else
1092 if (set_sym_perms)
1093 return err.report(errc::operation_not_supported);
1094 if (::chmod(p.c_str(), real_perms) == -1) {
1095 return err.report(capture_errno());
1096 }
1097#endif
1098}
1099
1100path __read_symlink(const path& p, error_code* ec) {
1101 ErrorHandler<path> err("read_symlink", ec, &p);
1102
1103#ifdef PATH_MAX
1104 struct NullDeleter { void operator()(void*) const {} };
1105 const size_t size = PATH_MAX + 1;
1106 char stack_buff[size];
1107 auto buff = std::unique_ptr<char[], NullDeleter>(stack_buff);
1108#else
1109 StatT sb;
1110 if (::lstat(p.c_str(), &sb) == -1) {
1111 return err.report(capture_errno());
1112 }
1113 const size_t size = sb.st_size + 1;
1114 auto buff = unique_ptr<char[]>(new char[size]);
1115#endif
1116 ::ssize_t ret;
1117 if ((ret = ::readlink(p.c_str(), buff.get(), size)) == -1)
1118 return err.report(capture_errno());
1119 _LIBCPP_ASSERT(ret > 0, "TODO");
1120 if (static_cast<size_t>(ret) >= size)
1121 return err.report(errc::value_too_large);
1122 buff[ret] = 0;
1123 return {buff.get()};
1124}
1125
1126bool __remove(const path& p, error_code* ec) {
1127 ErrorHandler<bool> err("remove", ec, &p);
1128 if (::remove(p.c_str()) == -1) {
1129 if (errno != ENOENT)
1130 err.report(capture_errno());
1131 return false;
1132 }
1133 return true;
1134}
1135
1136namespace {
1137
1138uintmax_t remove_all_impl(path const& p, error_code& ec) {
1139 const auto npos = static_cast<uintmax_t>(-1);
1140 const file_status st = __symlink_status(p, &ec);
1141 if (ec)
1142 return npos;
1143 uintmax_t count = 1;
1144 if (is_directory(st)) {
1145 for (directory_iterator it(p, ec); !ec && it != directory_iterator();
1146 it.increment(ec)) {
1147 auto other_count = remove_all_impl(it->path(), ec);
1148 if (ec)
1149 return npos;
1150 count += other_count;
1151 }
1152 if (ec)
1153 return npos;
1154 }
1155 if (!__remove(p, &ec))
1156 return npos;
1157 return count;
1158}
1159
1160} // end namespace
1161
1162uintmax_t __remove_all(const path& p, error_code* ec) {
1163 ErrorHandler<uintmax_t> err("remove_all", ec, &p);
1164
1165 error_code mec;
1166 auto count = remove_all_impl(p, mec);
1167 if (mec) {
1168 if (mec == errc::no_such_file_or_directory)
1169 return 0;
1170 return err.report(mec);
1171 }
1172 return count;
1173}
1174
1175void __rename(const path& from, const path& to, error_code* ec) {
1176 ErrorHandler<void> err("rename", ec, &from, &to);
1177 if (::rename(from.c_str(), to.c_str()) == -1)
1178 err.report(capture_errno());
1179}
1180
1181void __resize_file(const path& p, uintmax_t size, error_code* ec) {
1182 ErrorHandler<void> err("resize_file", ec, &p);
1183 if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
1184 return err.report(capture_errno());
1185}
1186
1187space_info __space(const path& p, error_code* ec) {
1188 ErrorHandler<void> err("space", ec, &p);
1189 space_info si;
1190 struct statvfs m_svfs = {};
1191 if (::statvfs(p.c_str(), &m_svfs) == -1) {
1192 err.report(capture_errno());
1193 si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
1194 return si;
1195 }
1196 // Multiply with overflow checking.
1197 auto do_mult = [&](uintmax_t& out, uintmax_t other) {
1198 out = other * m_svfs.f_frsize;
1199 if (other == 0 || out / other != m_svfs.f_frsize)
1200 out = static_cast<uintmax_t>(-1);
1201 };
1202 do_mult(si.capacity, m_svfs.f_blocks);
1203 do_mult(si.free, m_svfs.f_bfree);
1204 do_mult(si.available, m_svfs.f_bavail);
1205 return si;
1206}
1207
1208file_status __status(const path& p, error_code* ec) {
1209 return detail::posix_stat(p, ec);
1210}
1211
1212file_status __symlink_status(const path& p, error_code* ec) {
1213 return detail::posix_lstat(p, ec);
1214}
1215
1216path __temp_directory_path(error_code* ec) {
1217 ErrorHandler<path> err("temp_directory_path", ec);
1218
1219 const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
1220 const char* ret = nullptr;
1221
1222 for (auto& ep : env_paths)
1223 if ((ret = getenv(ep)))
1224 break;
1225 if (ret == nullptr)
1226 ret = "/tmp";
1227
1228 path p(ret);
1229 error_code m_ec;
1230 file_status st = detail::posix_stat(p, &m_ec);
1231 if (!status_known(st))
1232 return err.report(m_ec, "cannot access path \"%s\"", p);
1233
1234 if (!exists(st) || !is_directory(st))
1235 return err.report(errc::not_a_directory, "path \"%s\" is not a directory",
1236 p);
1237
1238 return p;
1239}
1240
1241path __weakly_canonical(const path& p, error_code* ec) {
1242 ErrorHandler<path> err("weakly_canonical", ec, &p);
1243
1244 if (p.empty())
1245 return __canonical("", ec);
1246
1247 path result;
1248 path tmp;
1249 tmp.__reserve(p.native().size());
1250 auto PP = PathParser::CreateEnd(p.native());
1251 --PP;
1252 vector<string_view_t> DNEParts;
1253
1254 while (PP.State != PathParser::PS_BeforeBegin) {
1255 tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
1256 error_code m_ec;
1257 file_status st = __status(tmp, &m_ec);
1258 if (!status_known(st)) {
1259 return err.report(m_ec);
1260 } else if (exists(st)) {
1261 result = __canonical(tmp, ec);
1262 break;
1263 }
1264 DNEParts.push_back(*PP);
1265 --PP;
1266 }
1267 if (PP.State == PathParser::PS_BeforeBegin)
1268 result = __canonical("", ec);
1269 if (ec)
1270 ec->clear();
1271 if (DNEParts.empty())
1272 return result;
1273 for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
1274 result /= *It;
1275 return result.lexically_normal();
1276}
1277
1278///////////////////////////////////////////////////////////////////////////////
1279// path definitions
1280///////////////////////////////////////////////////////////////////////////////
1281
1282constexpr path::value_type path::preferred_separator;
1283
1284path& path::replace_extension(path const& replacement) {
1285 path p = extension();
1286 if (not p.empty()) {
1287 __pn_.erase(__pn_.size() - p.native().size());
1288 }
1289 if (!replacement.empty()) {
1290 if (replacement.native()[0] != '.') {
1291 __pn_ += ".";
1292 }
1293 __pn_.append(replacement.__pn_);
1294 }
1295 return *this;
1296}
1297
1298///////////////////////////////////////////////////////////////////////////////
1299// path.decompose
1300
1301string_view_t path::__root_name() const {
1302 auto PP = PathParser::CreateBegin(__pn_);
1303 if (PP.State == PathParser::PS_InRootName)
1304 return *PP;
1305 return {};
1306}
1307
1308string_view_t path::__root_directory() const {
1309 auto PP = PathParser::CreateBegin(__pn_);
1310 if (PP.State == PathParser::PS_InRootName)
1311 ++PP;
1312 if (PP.State == PathParser::PS_InRootDir)
1313 return *PP;
1314 return {};
1315}
1316
1317string_view_t path::__root_path_raw() const {
1318 auto PP = PathParser::CreateBegin(__pn_);
1319 if (PP.State == PathParser::PS_InRootName) {
1320 auto NextCh = PP.peek();
1321 if (NextCh && *NextCh == '/') {
1322 ++PP;
1323 return createView(__pn_.data(), &PP.RawEntry.back());
1324 }
1325 return PP.RawEntry;
1326 }
1327 if (PP.State == PathParser::PS_InRootDir)
1328 return *PP;
1329 return {};
1330}
1331
1332static bool ConsumeRootName(PathParser *PP) {
1333 static_assert(PathParser::PS_BeforeBegin == 1 &&
1334 PathParser::PS_InRootName == 2,
1335 "Values for enums are incorrect");
1336 while (PP->State <= PathParser::PS_InRootName)
1337 ++(*PP);
1338 return PP->State == PathParser::PS_AtEnd;
1339}
1340
1341static bool ConsumeRootDir(PathParser* PP) {
1342 static_assert(PathParser::PS_BeforeBegin == 1 &&
1343 PathParser::PS_InRootName == 2 &&
1344 PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
1345 while (PP->State <= PathParser::PS_InRootDir)
1346 ++(*PP);
1347 return PP->State == PathParser::PS_AtEnd;
1348}
1349
1350string_view_t path::__relative_path() const {
1351 auto PP = PathParser::CreateBegin(__pn_);
1352 if (ConsumeRootDir(&PP))
1353 return {};
1354 return createView(PP.RawEntry.data(), &__pn_.back());
1355}
1356
1357string_view_t path::__parent_path() const {
1358 if (empty())
1359 return {};
1360 // Determine if we have a root path but not a relative path. In that case
1361 // return *this.
1362 {
1363 auto PP = PathParser::CreateBegin(__pn_);
1364 if (ConsumeRootDir(&PP))
1365 return __pn_;
1366 }
1367 // Otherwise remove a single element from the end of the path, and return
1368 // a string representing that path
1369 {
1370 auto PP = PathParser::CreateEnd(__pn_);
1371 --PP;
1372 if (PP.RawEntry.data() == __pn_.data())
1373 return {};
1374 --PP;
1375 return createView(__pn_.data(), &PP.RawEntry.back());
1376 }
1377}
1378
1379string_view_t path::__filename() const {
1380 if (empty())
1381 return {};
1382 {
1383 PathParser PP = PathParser::CreateBegin(__pn_);
1384 if (ConsumeRootDir(&PP))
1385 return {};
1386 }
1387 return *(--PathParser::CreateEnd(__pn_));
1388}
1389
1390string_view_t path::__stem() const {
1391 return parser::separate_filename(__filename()).first;
1392}
1393
1394string_view_t path::__extension() const {
1395 return parser::separate_filename(__filename()).second;
1396}
1397
1398////////////////////////////////////////////////////////////////////////////
1399// path.gen
1400
1401enum PathPartKind : unsigned char {
1402 PK_None,
1403 PK_RootSep,
1404 PK_Filename,
1405 PK_Dot,
1406 PK_DotDot,
1407 PK_TrailingSep
1408};
1409
1410static PathPartKind ClassifyPathPart(string_view_t Part) {
1411 if (Part.empty())
1412 return PK_TrailingSep;
1413 if (Part == ".")
1414 return PK_Dot;
1415 if (Part == "..")
1416 return PK_DotDot;
1417 if (Part == "/")
1418 return PK_RootSep;
1419 return PK_Filename;
1420}
1421
1422path path::lexically_normal() const {
1423 if (__pn_.empty())
1424 return *this;
1425
1426 using PartKindPair = pair<string_view_t, PathPartKind>;
1427 vector<PartKindPair> Parts;
1428 // Guess as to how many elements the path has to avoid reallocating.
1429 Parts.reserve(32);
1430
1431 // Track the total size of the parts as we collect them. This allows the
1432 // resulting path to reserve the correct amount of memory.
1433 size_t NewPathSize = 0;
1434 auto AddPart = [&](PathPartKind K, string_view_t P) {
1435 NewPathSize += P.size();
1436 Parts.emplace_back(P, K);
1437 };
1438 auto LastPartKind = [&]() {
1439 if (Parts.empty())
1440 return PK_None;
1441 return Parts.back().second;
1442 };
1443
1444 bool MaybeNeedTrailingSep = false;
1445 // Build a stack containing the remaining elements of the path, popping off
1446 // elements which occur before a '..' entry.
1447 for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
1448 auto Part = *PP;
1449 PathPartKind Kind = ClassifyPathPart(Part);
1450 switch (Kind) {
1451 case PK_Filename:
1452 case PK_RootSep: {
1453 // Add all non-dot and non-dot-dot elements to the stack of elements.
1454 AddPart(Kind, Part);
1455 MaybeNeedTrailingSep = false;
1456 break;
1457 }
1458 case PK_DotDot: {
1459 // Only push a ".." element if there are no elements preceding the "..",
1460 // or if the preceding element is itself "..".
1461 auto LastKind = LastPartKind();
1462 if (LastKind == PK_Filename) {
1463 NewPathSize -= Parts.back().first.size();
1464 Parts.pop_back();
1465 } else if (LastKind != PK_RootSep)
1466 AddPart(PK_DotDot, "..");
1467 MaybeNeedTrailingSep = LastKind == PK_Filename;
1468 break;
1469 }
1470 case PK_Dot:
1471 case PK_TrailingSep: {
1472 MaybeNeedTrailingSep = true;
1473 break;
1474 }
1475 case PK_None:
1476 _LIBCPP_UNREACHABLE();
1477 }
1478 }
1479 // [fs.path.generic]p6.8: If the path is empty, add a dot.
1480 if (Parts.empty())
1481 return ".";
1482
1483 // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
1484 // trailing directory-separator.
1485 bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
1486
1487 path Result;
1488 Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
1489 for (auto& PK : Parts)
1490 Result /= PK.first;
1491
1492 if (NeedTrailingSep)
1493 Result /= "";
1494
1495 return Result;
1496}
1497
1498static int DetermineLexicalElementCount(PathParser PP) {
1499 int Count = 0;
1500 for (; PP; ++PP) {
1501 auto Elem = *PP;
1502 if (Elem == "..")
1503 --Count;
1504 else if (Elem != "." && Elem != "")
1505 ++Count;
1506 }
1507 return Count;
1508}
1509
1510path path::lexically_relative(const path& base) const {
1511 { // perform root-name/root-directory mismatch checks
1512 auto PP = PathParser::CreateBegin(__pn_);
1513 auto PPBase = PathParser::CreateBegin(base.__pn_);
1514 auto CheckIterMismatchAtBase = [&]() {
1515 return PP.State != PPBase.State &&
1516 (PP.inRootPath() || PPBase.inRootPath());
1517 };
1518 if (PP.inRootName() && PPBase.inRootName()) {
1519 if (*PP != *PPBase)
1520 return {};
1521 } else if (CheckIterMismatchAtBase())
1522 return {};
1523
1524 if (PP.inRootPath())
1525 ++PP;
1526 if (PPBase.inRootPath())
1527 ++PPBase;
1528 if (CheckIterMismatchAtBase())
1529 return {};
1530 }
1531
1532 // Find the first mismatching element
1533 auto PP = PathParser::CreateBegin(__pn_);
1534 auto PPBase = PathParser::CreateBegin(base.__pn_);
1535 while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
1536 ++PP;
1537 ++PPBase;
1538 }
1539
1540 // If there is no mismatch, return ".".
1541 if (!PP && !PPBase)
1542 return ".";
1543
1544 // Otherwise, determine the number of elements, 'n', which are not dot or
1545 // dot-dot minus the number of dot-dot elements.
1546 int ElemCount = DetermineLexicalElementCount(PPBase);
1547 if (ElemCount < 0)
1548 return {};
1549
1550 // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
1551 if (ElemCount == 0 && (PP.atEnd() || *PP == ""))
1552 return ".";
1553
1554 // return a path constructed with 'n' dot-dot elements, followed by the the
1555 // elements of '*this' after the mismatch.
1556 path Result;
1557 // FIXME: Reserve enough room in Result that it won't have to re-allocate.
1558 while (ElemCount--)
1559 Result /= "..";
1560 for (; PP; ++PP)
1561 Result /= *PP;
1562 return Result;
1563}
1564
1565////////////////////////////////////////////////////////////////////////////
1566// path.comparisons
1567static int CompareRootName(PathParser *LHS, PathParser *RHS) {
1568 if (!LHS->inRootName() && !RHS->inRootName())
1569 return 0;
1570
1571 auto GetRootName = [](PathParser *Parser) -> string_view_t {
1572 return Parser->inRootName() ? **Parser : "";
1573 };
1574 int res = GetRootName(LHS).compare(GetRootName(RHS));
1575 ConsumeRootName(LHS);
1576 ConsumeRootName(RHS);
1577 return res;
1578}
1579
1580static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
1581 if (!LHS->inRootDir() && RHS->inRootDir())
1582 return -1;
1583 else if (LHS->inRootDir() && !RHS->inRootDir())
1584 return 1;
1585 else {
1586 ConsumeRootDir(LHS);
1587 ConsumeRootDir(RHS);
1588 return 0;
1589 }
1590}
1591
1592static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
1593 auto &LHS = *LHSPtr;
1594 auto &RHS = *RHSPtr;
1595
1596 int res;
1597 while (LHS && RHS) {
1598 if ((res = (*LHS).compare(*RHS)) != 0)
1599 return res;
1600 ++LHS;
1601 ++RHS;
1602 }
1603 return 0;
1604}
1605
1606static int CompareEndState(PathParser *LHS, PathParser *RHS) {
1607 if (LHS->atEnd() && !RHS->atEnd())
1608 return -1;
1609 else if (!LHS->atEnd() && RHS->atEnd())
1610 return 1;
1611 return 0;
1612}
1613
1614int path::__compare(string_view_t __s) const {
1615 auto LHS = PathParser::CreateBegin(__pn_);
1616 auto RHS = PathParser::CreateBegin(__s);
1617 int res;
1618
1619 if ((res = CompareRootName(&LHS, &RHS)) != 0)
1620 return res;
1621
1622 if ((res = CompareRootDir(&LHS, &RHS)) != 0)
1623 return res;
1624
1625 if ((res = CompareRelative(&LHS, &RHS)) != 0)
1626 return res;
1627
1628 return CompareEndState(&LHS, &RHS);
1629}
1630
1631////////////////////////////////////////////////////////////////////////////
1632// path.nonmembers
1633size_t hash_value(const path& __p) noexcept {
1634 auto PP = PathParser::CreateBegin(__p.native());
1635 size_t hash_value = 0;
1636 hash<string_view_t> hasher;
1637 while (PP) {
1638 hash_value = __hash_combine(hash_value, hasher(*PP));
1639 ++PP;
1640 }
1641 return hash_value;
1642}
1643
1644////////////////////////////////////////////////////////////////////////////
1645// path.itr
1646path::iterator path::begin() const {
1647 auto PP = PathParser::CreateBegin(__pn_);
1648 iterator it;
1649 it.__path_ptr_ = this;
1650 it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
1651 it.__entry_ = PP.RawEntry;
1652 it.__stashed_elem_.__assign_view(*PP);
1653 return it;
1654}
1655
1656path::iterator path::end() const {
1657 iterator it{};
1658 it.__state_ = path::iterator::_AtEnd;
1659 it.__path_ptr_ = this;
1660 return it;
1661}
1662
1663path::iterator& path::iterator::__increment() {
1664 PathParser PP(__path_ptr_->native(), __entry_, __state_);
1665 ++PP;
1666 __state_ = static_cast<_ParserState>(PP.State);
1667 __entry_ = PP.RawEntry;
1668 __stashed_elem_.__assign_view(*PP);
1669 return *this;
1670}
1671
1672path::iterator& path::iterator::__decrement() {
1673 PathParser PP(__path_ptr_->native(), __entry_, __state_);
1674 --PP;
1675 __state_ = static_cast<_ParserState>(PP.State);
1676 __entry_ = PP.RawEntry;
1677 __stashed_elem_.__assign_view(*PP);
1678 return *this;
1679}
1680
1681///////////////////////////////////////////////////////////////////////////////
1682// directory entry definitions
1683///////////////////////////////////////////////////////////////////////////////
1684
1685#ifndef _LIBCPP_WIN32API
1686error_code directory_entry::__do_refresh() noexcept {
1687 __data_.__reset();
1688 error_code failure_ec;
1689
1690 StatT full_st;
1691 file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
1692 if (!status_known(st)) {
1693 __data_.__reset();
1694 return failure_ec;
1695 }
1696
1697 if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1698 __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1699 __data_.__type_ = st.type();
1700 __data_.__non_sym_perms_ = st.permissions();
1701 } else { // we have a symlink
1702 __data_.__sym_perms_ = st.permissions();
1703 // Get the information about the linked entity.
1704 // Ignore errors from stat, since we don't want errors regarding symlink
1705 // resolution to be reported to the user.
1706 error_code ignored_ec;
1707 st = detail::posix_stat(__p_, full_st, &ignored_ec);
1708
1709 __data_.__type_ = st.type();
1710 __data_.__non_sym_perms_ = st.permissions();
1711
1712 // If we failed to resolve the link, then only partially populate the
1713 // cache.
1714 if (!status_known(st)) {
1715 __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1716 return error_code{};
1717 }
1718 // Otherwise, we resolved the link, potentially as not existing.
1719 // That's OK.
1720 __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1721 }
1722
1723 if (_VSTD_FS::is_regular_file(st))
1724 __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
1725
1726 if (_VSTD_FS::exists(st)) {
1727 __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
1728
1729 // Attempt to extract the mtime, and fail if it's not representable using
1730 // file_time_type. For now we ignore the error, as we'll report it when
1731 // the value is actually used.
1732 error_code ignored_ec;
1733 __data_.__write_time_ =
1734 __extract_last_write_time(__p_, full_st, &ignored_ec);
1735 }
1736
1737 return failure_ec;
1738}
1739#else
1740error_code directory_entry::__do_refresh() noexcept {
1741 __data_.__reset();
1742 error_code failure_ec;
1743
1744 file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
1745 if (!status_known(st)) {
1746 __data_.__reset();
1747 return failure_ec;
1748 }
1749
1750 if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
1751 __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
1752 __data_.__type_ = st.type();
1753 __data_.__non_sym_perms_ = st.permissions();
1754 } else { // we have a symlink
1755 __data_.__sym_perms_ = st.permissions();
1756 // Get the information about the linked entity.
1757 // Ignore errors from stat, since we don't want errors regarding symlink
1758 // resolution to be reported to the user.
1759 error_code ignored_ec;
1760 st = _VSTD_FS::status(__p_, ignored_ec);
1761
1762 __data_.__type_ = st.type();
1763 __data_.__non_sym_perms_ = st.permissions();
1764
1765 // If we failed to resolve the link, then only partially populate the
1766 // cache.
1767 if (!status_known(st)) {
1768 __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
1769 return error_code{};
1770 }
1771 __data_.__cache_type_ = directory_entry::_RefreshSymlink;
1772 }
1773
1774 // FIXME: This is currently broken, and the implementation only a placeholder.
1775 // We need to cache last_write_time, file_size, and hard_link_count here before
1776 // the implementation actually works.
1777
1778 return failure_ec;
1779}
1780#endif
1781
1782_LIBCPP_END_NAMESPACE_FILESYSTEM
lib/libcxx/src/functional.cpp created+25
...@@ -0,0 +1,25 @@
1//===----------------------- functional.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "functional"
10
11_LIBCPP_BEGIN_NAMESPACE_STD
12
13#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
14bad_function_call::~bad_function_call() _NOEXCEPT
15{
16}
17
18const char*
19bad_function_call::what() const _NOEXCEPT
20{
21 return "std::bad_function_call";
22}
23#endif
24
25_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/future.cpp created+277
...@@ -0,0 +1,277 @@
1//===------------------------- future.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10
11#ifndef _LIBCPP_HAS_NO_THREADS
12
13#include "future"
14#include "string"
15
16_LIBCPP_BEGIN_NAMESPACE_STD
17
18class _LIBCPP_HIDDEN __future_error_category
19 : public __do_message
20{
21public:
22 virtual const char* name() const _NOEXCEPT;
23 virtual string message(int ev) const;
24};
25
26const char*
27__future_error_category::name() const _NOEXCEPT
28{
29 return "future";
30}
31
32#if defined(__clang__)
33#pragma clang diagnostic push
34#pragma clang diagnostic ignored "-Wswitch"
35#elif defined(__GNUC__) || defined(__GNUG__)
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wswitch"
38#endif
39
40string
41__future_error_category::message(int ev) const
42{
43 switch (static_cast<future_errc>(ev))
44 {
45 case future_errc(0): // For backwards compatibility with C++11 (LWG 2056)
46 case future_errc::broken_promise:
47 return string("The associated promise has been destructed prior "
48 "to the associated state becoming ready.");
49 case future_errc::future_already_retrieved:
50 return string("The future has already been retrieved from "
51 "the promise or packaged_task.");
52 case future_errc::promise_already_satisfied:
53 return string("The state of the promise has already been set.");
54 case future_errc::no_state:
55 return string("Operation not permitted on an object without "
56 "an associated state.");
57 }
58 return string("unspecified future_errc value\n");
59}
60
61#if defined(__clang__)
62#pragma clang diagnostic pop
63#elif defined(__GNUC__) || defined(__GNUG__)
64#pragma GCC diagnostic pop
65#endif
66
67const error_category&
68future_category() _NOEXCEPT
69{
70 static __future_error_category __f;
71 return __f;
72}
73
74future_error::future_error(error_code __ec)
75 : logic_error(__ec.message()),
76 __ec_(__ec)
77{
78}
79
80future_error::~future_error() _NOEXCEPT
81{
82}
83
84void
85__assoc_sub_state::__on_zero_shared() _NOEXCEPT
86{
87 delete this;
88}
89
90void
91__assoc_sub_state::set_value()
92{
93 unique_lock<mutex> __lk(__mut_);
94 if (__has_value())
95 __throw_future_error(future_errc::promise_already_satisfied);
96 __state_ |= __constructed | ready;
97 __cv_.notify_all();
98}
99
100void
101__assoc_sub_state::set_value_at_thread_exit()
102{
103 unique_lock<mutex> __lk(__mut_);
104 if (__has_value())
105 __throw_future_error(future_errc::promise_already_satisfied);
106 __state_ |= __constructed;
107 __thread_local_data()->__make_ready_at_thread_exit(this);
108}
109
110void
111__assoc_sub_state::set_exception(exception_ptr __p)
112{
113 unique_lock<mutex> __lk(__mut_);
114 if (__has_value())
115 __throw_future_error(future_errc::promise_already_satisfied);
116 __exception_ = __p;
117 __state_ |= ready;
118 __cv_.notify_all();
119}
120
121void
122__assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p)
123{
124 unique_lock<mutex> __lk(__mut_);
125 if (__has_value())
126 __throw_future_error(future_errc::promise_already_satisfied);
127 __exception_ = __p;
128 __thread_local_data()->__make_ready_at_thread_exit(this);
129}
130
131void
132__assoc_sub_state::__make_ready()
133{
134 unique_lock<mutex> __lk(__mut_);
135 __state_ |= ready;
136 __cv_.notify_all();
137}
138
139void
140__assoc_sub_state::copy()
141{
142 unique_lock<mutex> __lk(__mut_);
143 __sub_wait(__lk);
144 if (__exception_ != nullptr)
145 rethrow_exception(__exception_);
146}
147
148void
149__assoc_sub_state::wait()
150{
151 unique_lock<mutex> __lk(__mut_);
152 __sub_wait(__lk);
153}
154
155void
156__assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk)
157{
158 if (!__is_ready())
159 {
160 if (__state_ & static_cast<unsigned>(deferred))
161 {
162 __state_ &= ~static_cast<unsigned>(deferred);
163 __lk.unlock();
164 __execute();
165 }
166 else
167 while (!__is_ready())
168 __cv_.wait(__lk);
169 }
170}
171
172void
173__assoc_sub_state::__execute()
174{
175 __throw_future_error(future_errc::no_state);
176}
177
178future<void>::future(__assoc_sub_state* __state)
179 : __state_(__state)
180{
181 __state_->__attach_future();
182}
183
184future<void>::~future()
185{
186 if (__state_)
187 __state_->__release_shared();
188}
189
190void
191future<void>::get()
192{
193 unique_ptr<__shared_count, __release_shared_count> __(__state_);
194 __assoc_sub_state* __s = __state_;
195 __state_ = nullptr;
196 __s->copy();
197}
198
199promise<void>::promise()
200 : __state_(new __assoc_sub_state)
201{
202}
203
204promise<void>::~promise()
205{
206 if (__state_)
207 {
208#ifndef _LIBCPP_NO_EXCEPTIONS
209 if (!__state_->__has_value() && __state_->use_count() > 1)
210 __state_->set_exception(make_exception_ptr(
211 future_error(make_error_code(future_errc::broken_promise))
212 ));
213#endif // _LIBCPP_NO_EXCEPTIONS
214 __state_->__release_shared();
215 }
216}
217
218future<void>
219promise<void>::get_future()
220{
221 if (__state_ == nullptr)
222 __throw_future_error(future_errc::no_state);
223 return future<void>(__state_);
224}
225
226void
227promise<void>::set_value()
228{
229 if (__state_ == nullptr)
230 __throw_future_error(future_errc::no_state);
231 __state_->set_value();
232}
233
234void
235promise<void>::set_exception(exception_ptr __p)
236{
237 if (__state_ == nullptr)
238 __throw_future_error(future_errc::no_state);
239 __state_->set_exception(__p);
240}
241
242void
243promise<void>::set_value_at_thread_exit()
244{
245 if (__state_ == nullptr)
246 __throw_future_error(future_errc::no_state);
247 __state_->set_value_at_thread_exit();
248}
249
250void
251promise<void>::set_exception_at_thread_exit(exception_ptr __p)
252{
253 if (__state_ == nullptr)
254 __throw_future_error(future_errc::no_state);
255 __state_->set_exception_at_thread_exit(__p);
256}
257
258shared_future<void>::~shared_future()
259{
260 if (__state_)
261 __state_->__release_shared();
262}
263
264shared_future<void>&
265shared_future<void>::operator=(const shared_future& __rhs)
266{
267 if (__rhs.__state_)
268 __rhs.__state_->__add_shared();
269 if (__state_)
270 __state_->__release_shared();
271 __state_ = __rhs.__state_;
272 return *this;
273}
274
275_LIBCPP_END_NAMESPACE_STD
276
277#endif // !_LIBCPP_HAS_NO_THREADS
lib/libcxx/src/hash.cpp created+561
...@@ -0,0 +1,561 @@
1//===-------------------------- hash.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__hash_table"
10#include "algorithm"
11#include "stdexcept"
12#include "type_traits"
13
14#ifdef __clang__
15#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
16#endif
17
18_LIBCPP_BEGIN_NAMESPACE_STD
19
20namespace {
21
22// handle all next_prime(i) for i in [1, 210), special case 0
23const unsigned small_primes[] =
24{
25 0,
26 2,
27 3,
28 5,
29 7,
30 11,
31 13,
32 17,
33 19,
34 23,
35 29,
36 31,
37 37,
38 41,
39 43,
40 47,
41 53,
42 59,
43 61,
44 67,
45 71,
46 73,
47 79,
48 83,
49 89,
50 97,
51 101,
52 103,
53 107,
54 109,
55 113,
56 127,
57 131,
58 137,
59 139,
60 149,
61 151,
62 157,
63 163,
64 167,
65 173,
66 179,
67 181,
68 191,
69 193,
70 197,
71 199,
72 211
73};
74
75// potential primes = 210*k + indices[i], k >= 1
76// these numbers are not divisible by 2, 3, 5 or 7
77// (or any integer 2 <= j <= 10 for that matter).
78const unsigned indices[] =
79{
80 1,
81 11,
82 13,
83 17,
84 19,
85 23,
86 29,
87 31,
88 37,
89 41,
90 43,
91 47,
92 53,
93 59,
94 61,
95 67,
96 71,
97 73,
98 79,
99 83,
100 89,
101 97,
102 101,
103 103,
104 107,
105 109,
106 113,
107 121,
108 127,
109 131,
110 137,
111 139,
112 143,
113 149,
114 151,
115 157,
116 163,
117 167,
118 169,
119 173,
120 179,
121 181,
122 187,
123 191,
124 193,
125 197,
126 199,
127 209
128};
129
130}
131
132// Returns: If n == 0, returns 0. Else returns the lowest prime number that
133// is greater than or equal to n.
134//
135// The algorithm creates a list of small primes, plus an open-ended list of
136// potential primes. All prime numbers are potential prime numbers. However
137// some potential prime numbers are not prime. In an ideal world, all potential
138// prime numbers would be prime. Candidate prime numbers are chosen as the next
139// highest potential prime. Then this number is tested for prime by dividing it
140// by all potential prime numbers less than the sqrt of the candidate.
141//
142// This implementation defines potential primes as those numbers not divisible
143// by 2, 3, 5, and 7. Other (common) implementations define potential primes
144// as those not divisible by 2. A few other implementations define potential
145// primes as those not divisible by 2 or 3. By raising the number of small
146// primes which the potential prime is not divisible by, the set of potential
147// primes more closely approximates the set of prime numbers. And thus there
148// are fewer potential primes to search, and fewer potential primes to divide
149// against.
150
151template <size_t _Sz = sizeof(size_t)>
152inline _LIBCPP_INLINE_VISIBILITY
153typename enable_if<_Sz == 4, void>::type
154__check_for_overflow(size_t N)
155{
156 if (N > 0xFFFFFFFB)
157 __throw_overflow_error("__next_prime overflow");
158}
159
160template <size_t _Sz = sizeof(size_t)>
161inline _LIBCPP_INLINE_VISIBILITY
162typename enable_if<_Sz == 8, void>::type
163__check_for_overflow(size_t N)
164{
165 if (N > 0xFFFFFFFFFFFFFFC5ull)
166 __throw_overflow_error("__next_prime overflow");
167}
168
169size_t
170__next_prime(size_t n)
171{
172 const size_t L = 210;
173 const size_t N = sizeof(small_primes) / sizeof(small_primes[0]);
174 // If n is small enough, search in small_primes
175 if (n <= small_primes[N-1])
176 return *std::lower_bound(small_primes, small_primes + N, n);
177 // Else n > largest small_primes
178 // Check for overflow
179 __check_for_overflow(n);
180 // Start searching list of potential primes: L * k0 + indices[in]
181 const size_t M = sizeof(indices) / sizeof(indices[0]);
182 // Select first potential prime >= n
183 // Known a-priori n >= L
184 size_t k0 = n / L;
185 size_t in = static_cast<size_t>(std::lower_bound(indices, indices + M, n - k0 * L)
186 - indices);
187 n = L * k0 + indices[in];
188 while (true)
189 {
190 // Divide n by all primes or potential primes (i) until:
191 // 1. The division is even, so try next potential prime.
192 // 2. The i > sqrt(n), in which case n is prime.
193 // It is known a-priori that n is not divisible by 2, 3, 5 or 7,
194 // so don't test those (j == 5 -> divide by 11 first). And the
195 // potential primes start with 211, so don't test against the last
196 // small prime.
197 for (size_t j = 5; j < N - 1; ++j)
198 {
199 const std::size_t p = small_primes[j];
200 const std::size_t q = n / p;
201 if (q < p)
202 return n;
203 if (n == q * p)
204 goto next;
205 }
206 // n wasn't divisible by small primes, try potential primes
207 {
208 size_t i = 211;
209 while (true)
210 {
211 std::size_t q = n / i;
212 if (q < i)
213 return n;
214 if (n == q * i)
215 break;
216
217 i += 10;
218 q = n / i;
219 if (q < i)
220 return n;
221 if (n == q * i)
222 break;
223
224 i += 2;
225 q = n / i;
226 if (q < i)
227 return n;
228 if (n == q * i)
229 break;
230
231 i += 4;
232 q = n / i;
233 if (q < i)
234 return n;
235 if (n == q * i)
236 break;
237
238 i += 2;
239 q = n / i;
240 if (q < i)
241 return n;
242 if (n == q * i)
243 break;
244
245 i += 4;
246 q = n / i;
247 if (q < i)
248 return n;
249 if (n == q * i)
250 break;
251
252 i += 6;
253 q = n / i;
254 if (q < i)
255 return n;
256 if (n == q * i)
257 break;
258
259 i += 2;
260 q = n / i;
261 if (q < i)
262 return n;
263 if (n == q * i)
264 break;
265
266 i += 6;
267 q = n / i;
268 if (q < i)
269 return n;
270 if (n == q * i)
271 break;
272
273 i += 4;
274 q = n / i;
275 if (q < i)
276 return n;
277 if (n == q * i)
278 break;
279
280 i += 2;
281 q = n / i;
282 if (q < i)
283 return n;
284 if (n == q * i)
285 break;
286
287 i += 4;
288 q = n / i;
289 if (q < i)
290 return n;
291 if (n == q * i)
292 break;
293
294 i += 6;
295 q = n / i;
296 if (q < i)
297 return n;
298 if (n == q * i)
299 break;
300
301 i += 6;
302 q = n / i;
303 if (q < i)
304 return n;
305 if (n == q * i)
306 break;
307
308 i += 2;
309 q = n / i;
310 if (q < i)
311 return n;
312 if (n == q * i)
313 break;
314
315 i += 6;
316 q = n / i;
317 if (q < i)
318 return n;
319 if (n == q * i)
320 break;
321
322 i += 4;
323 q = n / i;
324 if (q < i)
325 return n;
326 if (n == q * i)
327 break;
328
329 i += 2;
330 q = n / i;
331 if (q < i)
332 return n;
333 if (n == q * i)
334 break;
335
336 i += 6;
337 q = n / i;
338 if (q < i)
339 return n;
340 if (n == q * i)
341 break;
342
343 i += 4;
344 q = n / i;
345 if (q < i)
346 return n;
347 if (n == q * i)
348 break;
349
350 i += 6;
351 q = n / i;
352 if (q < i)
353 return n;
354 if (n == q * i)
355 break;
356
357 i += 8;
358 q = n / i;
359 if (q < i)
360 return n;
361 if (n == q * i)
362 break;
363
364 i += 4;
365 q = n / i;
366 if (q < i)
367 return n;
368 if (n == q * i)
369 break;
370
371 i += 2;
372 q = n / i;
373 if (q < i)
374 return n;
375 if (n == q * i)
376 break;
377
378 i += 4;
379 q = n / i;
380 if (q < i)
381 return n;
382 if (n == q * i)
383 break;
384
385 i += 2;
386 q = n / i;
387 if (q < i)
388 return n;
389 if (n == q * i)
390 break;
391
392 i += 4;
393 q = n / i;
394 if (q < i)
395 return n;
396 if (n == q * i)
397 break;
398
399 i += 8;
400 q = n / i;
401 if (q < i)
402 return n;
403 if (n == q * i)
404 break;
405
406 i += 6;
407 q = n / i;
408 if (q < i)
409 return n;
410 if (n == q * i)
411 break;
412
413 i += 4;
414 q = n / i;
415 if (q < i)
416 return n;
417 if (n == q * i)
418 break;
419
420 i += 6;
421 q = n / i;
422 if (q < i)
423 return n;
424 if (n == q * i)
425 break;
426
427 i += 2;
428 q = n / i;
429 if (q < i)
430 return n;
431 if (n == q * i)
432 break;
433
434 i += 4;
435 q = n / i;
436 if (q < i)
437 return n;
438 if (n == q * i)
439 break;
440
441 i += 6;
442 q = n / i;
443 if (q < i)
444 return n;
445 if (n == q * i)
446 break;
447
448 i += 2;
449 q = n / i;
450 if (q < i)
451 return n;
452 if (n == q * i)
453 break;
454
455 i += 6;
456 q = n / i;
457 if (q < i)
458 return n;
459 if (n == q * i)
460 break;
461
462 i += 6;
463 q = n / i;
464 if (q < i)
465 return n;
466 if (n == q * i)
467 break;
468
469 i += 4;
470 q = n / i;
471 if (q < i)
472 return n;
473 if (n == q * i)
474 break;
475
476 i += 2;
477 q = n / i;
478 if (q < i)
479 return n;
480 if (n == q * i)
481 break;
482
483 i += 4;
484 q = n / i;
485 if (q < i)
486 return n;
487 if (n == q * i)
488 break;
489
490 i += 6;
491 q = n / i;
492 if (q < i)
493 return n;
494 if (n == q * i)
495 break;
496
497 i += 2;
498 q = n / i;
499 if (q < i)
500 return n;
501 if (n == q * i)
502 break;
503
504 i += 6;
505 q = n / i;
506 if (q < i)
507 return n;
508 if (n == q * i)
509 break;
510
511 i += 4;
512 q = n / i;
513 if (q < i)
514 return n;
515 if (n == q * i)
516 break;
517
518 i += 2;
519 q = n / i;
520 if (q < i)
521 return n;
522 if (n == q * i)
523 break;
524
525 i += 4;
526 q = n / i;
527 if (q < i)
528 return n;
529 if (n == q * i)
530 break;
531
532 i += 2;
533 q = n / i;
534 if (q < i)
535 return n;
536 if (n == q * i)
537 break;
538
539 i += 10;
540 q = n / i;
541 if (q < i)
542 return n;
543 if (n == q * i)
544 break;
545
546 // This will loop i to the next "plane" of potential primes
547 i += 2;
548 }
549 }
550next:
551 // n is not prime. Increment n to next potential prime.
552 if (++in == M)
553 {
554 ++k0;
555 in = 0;
556 }
557 n = L * k0 + indices[in];
558 }
559}
560
561_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/include/apple_availability.h created+51
...@@ -0,0 +1,51 @@
1//===------------------------ apple_availability.h ------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#ifndef _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
9#define _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
10
11#if defined(__APPLE__)
12
13#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
14#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101300
15#define _LIBCPP_USE_UTIMENSAT
16#endif
17#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
18#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 110000
19#define _LIBCPP_USE_UTIMENSAT
20#endif
21#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
22#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 110000
23#define _LIBCPP_USE_UTIMENSAT
24#endif
25#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
26#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 40000
27#define _LIBCPP_USE_UTIMENSAT
28#endif
29#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
30
31#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
32#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101200
33#define _LIBCPP_USE_CLOCK_GETTIME
34#endif
35#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
36#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 100000
37#define _LIBCPP_USE_CLOCK_GETTIME
38#endif
39#elif defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__)
40#if __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 100000
41#define _LIBCPP_USE_CLOCK_GETTIME
42#endif
43#elif defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
44#if __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 30000
45#define _LIBCPP_USE_CLOCK_GETTIME
46#endif
47#endif // __ENVIRONMENT_.*_VERSION_MIN_REQUIRED__
48
49#endif // __APPLE__
50
51#endif // _LIBCPP_SRC_INCLUDE_APPLE_AVAILABILITY_H
lib/libcxx/src/include/atomic_support.h created+176
...@@ -0,0 +1,176 @@
1//===----------------------------------------------------------------------===////
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===////
8
9#ifndef ATOMIC_SUPPORT_H
10#define ATOMIC_SUPPORT_H
11
12#include "__config"
13#include "memory" // for __libcpp_relaxed_load
14
15#if defined(__clang__) && __has_builtin(__atomic_load_n) \
16 && __has_builtin(__atomic_store_n) \
17 && __has_builtin(__atomic_add_fetch) \
18 && __has_builtin(__atomic_exchange_n) \
19 && __has_builtin(__atomic_compare_exchange_n) \
20 && defined(__ATOMIC_RELAXED) \
21 && defined(__ATOMIC_CONSUME) \
22 && defined(__ATOMIC_ACQUIRE) \
23 && defined(__ATOMIC_RELEASE) \
24 && defined(__ATOMIC_ACQ_REL) \
25 && defined(__ATOMIC_SEQ_CST)
26# define _LIBCPP_HAS_ATOMIC_BUILTINS
27#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
28# define _LIBCPP_HAS_ATOMIC_BUILTINS
29#endif
30
31#if !defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
32# if defined(_LIBCPP_WARNING)
33 _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
34# else
35# warning Building libc++ without __atomic builtins is unsupported
36# endif
37#endif
38
39_LIBCPP_BEGIN_NAMESPACE_STD
40
41namespace {
42
43#if defined(_LIBCPP_HAS_ATOMIC_BUILTINS) && !defined(_LIBCPP_HAS_NO_THREADS)
44
45enum __libcpp_atomic_order {
46 _AO_Relaxed = __ATOMIC_RELAXED,
47 _AO_Consume = __ATOMIC_CONSUME,
48 _AO_Acquire = __ATOMIC_ACQUIRE,
49 _AO_Release = __ATOMIC_RELEASE,
50 _AO_Acq_Rel = __ATOMIC_ACQ_REL,
51 _AO_Seq = __ATOMIC_SEQ_CST
52};
53
54template <class _ValueType, class _FromType>
55inline _LIBCPP_INLINE_VISIBILITY
56void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
57 int __order = _AO_Seq)
58{
59 __atomic_store_n(__dest, __val, __order);
60}
61
62template <class _ValueType, class _FromType>
63inline _LIBCPP_INLINE_VISIBILITY
64void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
65{
66 __atomic_store_n(__dest, __val, _AO_Relaxed);
67}
68
69template <class _ValueType>
70inline _LIBCPP_INLINE_VISIBILITY
71_ValueType __libcpp_atomic_load(_ValueType const* __val,
72 int __order = _AO_Seq)
73{
74 return __atomic_load_n(__val, __order);
75}
76
77template <class _ValueType, class _AddType>
78inline _LIBCPP_INLINE_VISIBILITY
79_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
80 int __order = _AO_Seq)
81{
82 return __atomic_add_fetch(__val, __a, __order);
83}
84
85template <class _ValueType>
86inline _LIBCPP_INLINE_VISIBILITY
87_ValueType __libcpp_atomic_exchange(_ValueType* __target,
88 _ValueType __value, int __order = _AO_Seq)
89{
90 return __atomic_exchange_n(__target, __value, __order);
91}
92
93template <class _ValueType>
94inline _LIBCPP_INLINE_VISIBILITY
95bool __libcpp_atomic_compare_exchange(_ValueType* __val,
96 _ValueType* __expected, _ValueType __after,
97 int __success_order = _AO_Seq,
98 int __fail_order = _AO_Seq)
99{
100 return __atomic_compare_exchange_n(__val, __expected, __after, true,
101 __success_order, __fail_order);
102}
103
104#else // _LIBCPP_HAS_NO_THREADS
105
106enum __libcpp_atomic_order {
107 _AO_Relaxed,
108 _AO_Consume,
109 _AO_Acquire,
110 _AO_Release,
111 _AO_Acq_Rel,
112 _AO_Seq
113};
114
115template <class _ValueType, class _FromType>
116inline _LIBCPP_INLINE_VISIBILITY
117void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
118 int = 0)
119{
120 *__dest = __val;
121}
122
123template <class _ValueType, class _FromType>
124inline _LIBCPP_INLINE_VISIBILITY
125void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
126{
127 *__dest = __val;
128}
129
130template <class _ValueType>
131inline _LIBCPP_INLINE_VISIBILITY
132_ValueType __libcpp_atomic_load(_ValueType const* __val,
133 int = 0)
134{
135 return *__val;
136}
137
138template <class _ValueType, class _AddType>
139inline _LIBCPP_INLINE_VISIBILITY
140_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
141 int = 0)
142{
143 return *__val += __a;
144}
145
146template <class _ValueType>
147inline _LIBCPP_INLINE_VISIBILITY
148_ValueType __libcpp_atomic_exchange(_ValueType* __target,
149 _ValueType __value, int __order = _AO_Seq)
150{
151 _ValueType old = *__target;
152 *__target = __value;
153 return old;
154}
155
156template <class _ValueType>
157inline _LIBCPP_INLINE_VISIBILITY
158bool __libcpp_atomic_compare_exchange(_ValueType* __val,
159 _ValueType* __expected, _ValueType __after,
160 int = 0, int = 0)
161{
162 if (*__val == *__expected) {
163 *__val = __after;
164 return true;
165 }
166 *__expected = *__val;
167 return false;
168}
169
170#endif // _LIBCPP_HAS_NO_THREADS
171
172} // end namespace
173
174_LIBCPP_END_NAMESPACE_STD
175
176#endif // ATOMIC_SUPPORT_H
lib/libcxx/src/include/config_elast.h created+41
...@@ -0,0 +1,41 @@
1//===----------------------- config_elast.h -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP_CONFIG_ELAST
10#define _LIBCPP_CONFIG_ELAST
11
12#include <__config>
13
14#if defined(_LIBCPP_MSVCRT_LIKE)
15#include <stdlib.h>
16#else
17#include <errno.h>
18#endif
19
20#if defined(ELAST)
21#define _LIBCPP_ELAST ELAST
22#elif defined(_NEWLIB_VERSION)
23#define _LIBCPP_ELAST __ELASTERROR
24#elif defined(__Fuchsia__)
25// No _LIBCPP_ELAST needed on Fuchsia
26#elif defined(__wasi__)
27// No _LIBCPP_ELAST needed on WASI
28#elif defined(__linux__) || defined(_LIBCPP_HAS_MUSL_LIBC)
29#define _LIBCPP_ELAST 4095
30#elif defined(__APPLE__)
31// No _LIBCPP_ELAST needed on Apple
32#elif defined(__sun__)
33#define _LIBCPP_ELAST ESTALE
34#elif defined(_LIBCPP_MSVCRT_LIKE)
35#define _LIBCPP_ELAST (_sys_nerr - 1)
36#else
37// Warn here so that the person doing the libcxx port has an easier time:
38#warning ELAST for this platform not yet implemented
39#endif
40
41#endif // _LIBCPP_CONFIG_ELAST
lib/libcxx/src/include/refstring.h created+127
...@@ -0,0 +1,127 @@
1//===------------------------ __refstring ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP_REFSTRING_H
10#define _LIBCPP_REFSTRING_H
11
12#include <__config>
13#include <stdexcept>
14#include <cstddef>
15#include <cstring>
16#ifdef __APPLE__
17#include <dlfcn.h>
18#include <mach-o/dyld.h>
19#endif
20#include "atomic_support.h"
21
22_LIBCPP_BEGIN_NAMESPACE_STD
23
24namespace __refstring_imp { namespace {
25typedef int count_t;
26
27struct _Rep_base {
28 std::size_t len;
29 std::size_t cap;
30 count_t count;
31};
32
33inline _Rep_base* rep_from_data(const char *data_) noexcept {
34 char *data = const_cast<char *>(data_);
35 return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
36}
37
38inline char * data_from_rep(_Rep_base *rep) noexcept {
39 char *data = reinterpret_cast<char *>(rep);
40 return data + sizeof(*rep);
41}
42
43#if defined(__APPLE__)
44inline
45const char* compute_gcc_empty_string_storage() _NOEXCEPT
46{
47 void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
48 if (handle == nullptr)
49 return nullptr;
50 void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
51 if (sym == nullptr)
52 return nullptr;
53 return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
54}
55
56inline
57const char*
58get_gcc_empty_string_storage() _NOEXCEPT
59{
60 static const char* p = compute_gcc_empty_string_storage();
61 return p;
62}
63#endif
64
65}} // namespace __refstring_imp
66
67using namespace __refstring_imp;
68
69inline
70__libcpp_refstring::__libcpp_refstring(const char* msg) {
71 std::size_t len = strlen(msg);
72 _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
73 rep->len = len;
74 rep->cap = len;
75 rep->count = 0;
76 char *data = data_from_rep(rep);
77 std::memcpy(data, msg, len + 1);
78 __imp_ = data;
79}
80
81inline
82__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
83 : __imp_(s.__imp_)
84{
85 if (__uses_refcount())
86 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
87}
88
89inline
90__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
91 bool adjust_old_count = __uses_refcount();
92 struct _Rep_base *old_rep = rep_from_data(__imp_);
93 __imp_ = s.__imp_;
94 if (__uses_refcount())
95 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
96 if (adjust_old_count)
97 {
98 if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
99 {
100 ::operator delete(old_rep);
101 }
102 }
103 return *this;
104}
105
106inline
107__libcpp_refstring::~__libcpp_refstring() {
108 if (__uses_refcount()) {
109 _Rep_base* rep = rep_from_data(__imp_);
110 if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
111 ::operator delete(rep);
112 }
113 }
114}
115
116inline
117bool __libcpp_refstring::__uses_refcount() const {
118#ifdef __APPLE__
119 return __imp_ != get_gcc_empty_string_storage();
120#else
121 return true;
122#endif
123}
124
125_LIBCPP_END_NAMESPACE_STD
126
127#endif //_LIBCPP_REFSTRING_H
lib/libcxx/src/ios.cpp created+457
...@@ -0,0 +1,457 @@
1//===-------------------------- ios.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10
11#include "ios"
12
13#include <stdlib.h>
14
15#include "__locale"
16#include "algorithm"
17#include "include/config_elast.h"
18#include "istream"
19#include "limits"
20#include "memory"
21#include "new"
22#include "streambuf"
23#include "string"
24#include "__undef_macros"
25
26_LIBCPP_BEGIN_NAMESPACE_STD
27
28template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<char>;
29template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ios<wchar_t>;
30
31template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<char>;
32template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_streambuf<wchar_t>;
33
34template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<char>;
35template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_istream<wchar_t>;
36
37template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<char>;
38template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_ostream<wchar_t>;
39
40template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_iostream<char>;
41
42class _LIBCPP_HIDDEN __iostream_category
43 : public __do_message
44{
45public:
46 virtual const char* name() const _NOEXCEPT;
47 virtual string message(int ev) const;
48};
49
50const char*
51__iostream_category::name() const _NOEXCEPT
52{
53 return "iostream";
54}
55
56string
57__iostream_category::message(int ev) const
58{
59 if (ev != static_cast<int>(io_errc::stream)
60#ifdef _LIBCPP_ELAST
61 && ev <= _LIBCPP_ELAST
62#endif // _LIBCPP_ELAST
63 )
64 return __do_message::message(ev);
65 return string("unspecified iostream_category error");
66}
67
68const error_category&
69iostream_category() _NOEXCEPT
70{
71 static __iostream_category s;
72 return s;
73}
74
75// ios_base::failure
76
77ios_base::failure::failure(const string& msg, const error_code& ec)
78 : system_error(ec, msg)
79{
80}
81
82ios_base::failure::failure(const char* msg, const error_code& ec)
83 : system_error(ec, msg)
84{
85}
86
87ios_base::failure::~failure() throw()
88{
89}
90
91// ios_base locale
92
93const ios_base::fmtflags ios_base::boolalpha;
94const ios_base::fmtflags ios_base::dec;
95const ios_base::fmtflags ios_base::fixed;
96const ios_base::fmtflags ios_base::hex;
97const ios_base::fmtflags ios_base::internal;
98const ios_base::fmtflags ios_base::left;
99const ios_base::fmtflags ios_base::oct;
100const ios_base::fmtflags ios_base::right;
101const ios_base::fmtflags ios_base::scientific;
102const ios_base::fmtflags ios_base::showbase;
103const ios_base::fmtflags ios_base::showpoint;
104const ios_base::fmtflags ios_base::showpos;
105const ios_base::fmtflags ios_base::skipws;
106const ios_base::fmtflags ios_base::unitbuf;
107const ios_base::fmtflags ios_base::uppercase;
108const ios_base::fmtflags ios_base::adjustfield;
109const ios_base::fmtflags ios_base::basefield;
110const ios_base::fmtflags ios_base::floatfield;
111
112const ios_base::iostate ios_base::badbit;
113const ios_base::iostate ios_base::eofbit;
114const ios_base::iostate ios_base::failbit;
115const ios_base::iostate ios_base::goodbit;
116
117const ios_base::openmode ios_base::app;
118const ios_base::openmode ios_base::ate;
119const ios_base::openmode ios_base::binary;
120const ios_base::openmode ios_base::in;
121const ios_base::openmode ios_base::out;
122const ios_base::openmode ios_base::trunc;
123
124void
125ios_base::__call_callbacks(event ev)
126{
127 for (size_t i = __event_size_; i;)
128 {
129 --i;
130 __fn_[i](ev, *this, __index_[i]);
131 }
132}
133
134// locale
135
136locale
137ios_base::imbue(const locale& newloc)
138{
139 static_assert(sizeof(locale) == sizeof(__loc_), "");
140 locale& loc_storage = *reinterpret_cast<locale*>(&__loc_);
141 locale oldloc = loc_storage;
142 loc_storage = newloc;
143 __call_callbacks(imbue_event);
144 return oldloc;
145}
146
147locale
148ios_base::getloc() const
149{
150 const locale& loc_storage = *reinterpret_cast<const locale*>(&__loc_);
151 return loc_storage;
152}
153
154// xalloc
155#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)
156atomic<int> ios_base::__xindex_ = ATOMIC_VAR_INIT(0);
157#else
158int ios_base::__xindex_ = 0;
159#endif
160
161template <typename _Tp>
162static size_t __ios_new_cap(size_t __req_size, size_t __current_cap)
163{ // Precondition: __req_size > __current_cap
164 const size_t mx = std::numeric_limits<size_t>::max() / sizeof(_Tp);
165 if (__req_size < mx/2)
166 return _VSTD::max(2 * __current_cap, __req_size);
167 else
168 return mx;
169}
170
171int
172ios_base::xalloc()
173{
174 return __xindex_++;
175}
176
177long&
178ios_base::iword(int index)
179{
180 size_t req_size = static_cast<size_t>(index)+1;
181 if (req_size > __iarray_cap_)
182 {
183 size_t newcap = __ios_new_cap<long>(req_size, __iarray_cap_);
184 long* iarray = static_cast<long*>(realloc(__iarray_, newcap * sizeof(long)));
185 if (iarray == 0)
186 {
187 setstate(badbit);
188 static long error;
189 error = 0;
190 return error;
191 }
192 __iarray_ = iarray;
193 for (long* p = __iarray_ + __iarray_size_; p < __iarray_ + newcap; ++p)
194 *p = 0;
195 __iarray_cap_ = newcap;
196 }
197 __iarray_size_ = max<size_t>(__iarray_size_, req_size);
198 return __iarray_[index];
199}
200
201void*&
202ios_base::pword(int index)
203{
204 size_t req_size = static_cast<size_t>(index)+1;
205 if (req_size > __parray_cap_)
206 {
207 size_t newcap = __ios_new_cap<void *>(req_size, __iarray_cap_);
208 void** parray = static_cast<void**>(realloc(__parray_, newcap * sizeof(void *)));
209 if (parray == 0)
210 {
211 setstate(badbit);
212 static void* error;
213 error = 0;
214 return error;
215 }
216 __parray_ = parray;
217 for (void** p = __parray_ + __parray_size_; p < __parray_ + newcap; ++p)
218 *p = 0;
219 __parray_cap_ = newcap;
220 }
221 __parray_size_ = max<size_t>(__parray_size_, req_size);
222 return __parray_[index];
223}
224
225// register_callback
226
227void
228ios_base::register_callback(event_callback fn, int index)
229{
230 size_t req_size = __event_size_ + 1;
231 if (req_size > __event_cap_)
232 {
233 size_t newcap = __ios_new_cap<event_callback>(req_size, __event_cap_);
234 event_callback* fns = static_cast<event_callback*>(realloc(__fn_, newcap * sizeof(event_callback)));
235 if (fns == 0)
236 setstate(badbit);
237 __fn_ = fns;
238 int* indxs = static_cast<int *>(realloc(__index_, newcap * sizeof(int)));
239 if (indxs == 0)
240 setstate(badbit);
241 __index_ = indxs;
242 __event_cap_ = newcap;
243 }
244 __fn_[__event_size_] = fn;
245 __index_[__event_size_] = index;
246 ++__event_size_;
247}
248
249ios_base::~ios_base()
250{
251 __call_callbacks(erase_event);
252 locale& loc_storage = *reinterpret_cast<locale*>(&__loc_);
253 loc_storage.~locale();
254 free(__fn_);
255 free(__index_);
256 free(__iarray_);
257 free(__parray_);
258}
259
260// iostate
261
262void
263ios_base::clear(iostate state)
264{
265 if (__rdbuf_)
266 __rdstate_ = state;
267 else
268 __rdstate_ = state | badbit;
269
270 if (((state | (__rdbuf_ ? goodbit : badbit)) & __exceptions_) != 0)
271 __throw_failure("ios_base::clear");
272}
273
274// init
275
276void
277ios_base::init(void* sb)
278{
279 __rdbuf_ = sb;
280 __rdstate_ = __rdbuf_ ? goodbit : badbit;
281 __exceptions_ = goodbit;
282 __fmtflags_ = skipws | dec;
283 __width_ = 0;
284 __precision_ = 6;
285 __fn_ = 0;
286 __index_ = 0;
287 __event_size_ = 0;
288 __event_cap_ = 0;
289 __iarray_ = 0;
290 __iarray_size_ = 0;
291 __iarray_cap_ = 0;
292 __parray_ = 0;
293 __parray_size_ = 0;
294 __parray_cap_ = 0;
295 ::new(&__loc_) locale;
296}
297
298void
299ios_base::copyfmt(const ios_base& rhs)
300{
301 // If we can't acquire the needed resources, throw bad_alloc (can't set badbit)
302 // Don't alter *this until all needed resources are acquired
303 unique_ptr<event_callback, void (*)(void*)> new_callbacks(0, free);
304 unique_ptr<int, void (*)(void*)> new_ints(0, free);
305 unique_ptr<long, void (*)(void*)> new_longs(0, free);
306 unique_ptr<void*, void (*)(void*)> new_pointers(0, free);
307 if (__event_cap_ < rhs.__event_size_)
308 {
309 size_t newesize = sizeof(event_callback) * rhs.__event_size_;
310 new_callbacks.reset(static_cast<event_callback*>(malloc(newesize)));
311 if (!new_callbacks)
312 __throw_bad_alloc();
313
314 size_t newisize = sizeof(int) * rhs.__event_size_;
315 new_ints.reset(static_cast<int *>(malloc(newisize)));
316 if (!new_ints)
317 __throw_bad_alloc();
318 }
319 if (__iarray_cap_ < rhs.__iarray_size_)
320 {
321 size_t newsize = sizeof(long) * rhs.__iarray_size_;
322 new_longs.reset(static_cast<long*>(malloc(newsize)));
323 if (!new_longs)
324 __throw_bad_alloc();
325 }
326 if (__parray_cap_ < rhs.__parray_size_)
327 {
328 size_t newsize = sizeof(void*) * rhs.__parray_size_;
329 new_pointers.reset(static_cast<void**>(malloc(newsize)));
330 if (!new_pointers)
331 __throw_bad_alloc();
332 }
333 // Got everything we need. Copy everything but __rdstate_, __rdbuf_ and __exceptions_
334 __fmtflags_ = rhs.__fmtflags_;
335 __precision_ = rhs.__precision_;
336 __width_ = rhs.__width_;
337 locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_);
338 const locale& rhs_loc = *reinterpret_cast<const locale*>(&rhs.__loc_);
339 lhs_loc = rhs_loc;
340 if (__event_cap_ < rhs.__event_size_)
341 {
342 free(__fn_);
343 __fn_ = new_callbacks.release();
344 free(__index_);
345 __index_ = new_ints.release();
346 __event_cap_ = rhs.__event_size_;
347 }
348 for (__event_size_ = 0; __event_size_ < rhs.__event_size_; ++__event_size_)
349 {
350 __fn_[__event_size_] = rhs.__fn_[__event_size_];
351 __index_[__event_size_] = rhs.__index_[__event_size_];
352 }
353 if (__iarray_cap_ < rhs.__iarray_size_)
354 {
355 free(__iarray_);
356 __iarray_ = new_longs.release();
357 __iarray_cap_ = rhs.__iarray_size_;
358 }
359 for (__iarray_size_ = 0; __iarray_size_ < rhs.__iarray_size_; ++__iarray_size_)
360 __iarray_[__iarray_size_] = rhs.__iarray_[__iarray_size_];
361 if (__parray_cap_ < rhs.__parray_size_)
362 {
363 free(__parray_);
364 __parray_ = new_pointers.release();
365 __parray_cap_ = rhs.__parray_size_;
366 }
367 for (__parray_size_ = 0; __parray_size_ < rhs.__parray_size_; ++__parray_size_)
368 __parray_[__parray_size_] = rhs.__parray_[__parray_size_];
369}
370
371void
372ios_base::move(ios_base& rhs)
373{
374 // *this is uninitialized
375 __fmtflags_ = rhs.__fmtflags_;
376 __precision_ = rhs.__precision_;
377 __width_ = rhs.__width_;
378 __rdstate_ = rhs.__rdstate_;
379 __exceptions_ = rhs.__exceptions_;
380 __rdbuf_ = 0;
381 locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_);
382 ::new(&__loc_) locale(rhs_loc);
383 __fn_ = rhs.__fn_;
384 rhs.__fn_ = 0;
385 __index_ = rhs.__index_;
386 rhs.__index_ = 0;
387 __event_size_ = rhs.__event_size_;
388 rhs.__event_size_ = 0;
389 __event_cap_ = rhs.__event_cap_;
390 rhs.__event_cap_ = 0;
391 __iarray_ = rhs.__iarray_;
392 rhs.__iarray_ = 0;
393 __iarray_size_ = rhs.__iarray_size_;
394 rhs.__iarray_size_ = 0;
395 __iarray_cap_ = rhs.__iarray_cap_;
396 rhs.__iarray_cap_ = 0;
397 __parray_ = rhs.__parray_;
398 rhs.__parray_ = 0;
399 __parray_size_ = rhs.__parray_size_;
400 rhs.__parray_size_ = 0;
401 __parray_cap_ = rhs.__parray_cap_;
402 rhs.__parray_cap_ = 0;
403}
404
405void
406ios_base::swap(ios_base& rhs) _NOEXCEPT
407{
408 _VSTD::swap(__fmtflags_, rhs.__fmtflags_);
409 _VSTD::swap(__precision_, rhs.__precision_);
410 _VSTD::swap(__width_, rhs.__width_);
411 _VSTD::swap(__rdstate_, rhs.__rdstate_);
412 _VSTD::swap(__exceptions_, rhs.__exceptions_);
413 locale& lhs_loc = *reinterpret_cast<locale*>(&__loc_);
414 locale& rhs_loc = *reinterpret_cast<locale*>(&rhs.__loc_);
415 _VSTD::swap(lhs_loc, rhs_loc);
416 _VSTD::swap(__fn_, rhs.__fn_);
417 _VSTD::swap(__index_, rhs.__index_);
418 _VSTD::swap(__event_size_, rhs.__event_size_);
419 _VSTD::swap(__event_cap_, rhs.__event_cap_);
420 _VSTD::swap(__iarray_, rhs.__iarray_);
421 _VSTD::swap(__iarray_size_, rhs.__iarray_size_);
422 _VSTD::swap(__iarray_cap_, rhs.__iarray_cap_);
423 _VSTD::swap(__parray_, rhs.__parray_);
424 _VSTD::swap(__parray_size_, rhs.__parray_size_);
425 _VSTD::swap(__parray_cap_, rhs.__parray_cap_);
426}
427
428void
429ios_base::__set_badbit_and_consider_rethrow()
430{
431 __rdstate_ |= badbit;
432#ifndef _LIBCPP_NO_EXCEPTIONS
433 if (__exceptions_ & badbit)
434 throw;
435#endif // _LIBCPP_NO_EXCEPTIONS
436}
437
438void
439ios_base::__set_failbit_and_consider_rethrow()
440{
441 __rdstate_ |= failbit;
442#ifndef _LIBCPP_NO_EXCEPTIONS
443 if (__exceptions_ & failbit)
444 throw;
445#endif // _LIBCPP_NO_EXCEPTIONS
446}
447
448bool
449ios_base::sync_with_stdio(bool sync)
450{
451 static bool previous_state = true;
452 bool r = previous_state;
453 previous_state = sync;
454 return r;
455}
456
457_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/iostream.cpp created+159
...@@ -0,0 +1,159 @@
1//===------------------------ iostream.cpp --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__std_stream"
10#include "__locale"
11#include "string"
12#include "new"
13
14#define _str(s) #s
15#define str(s) _str(s)
16#define _LIBCPP_ABI_NAMESPACE_STR str(_LIBCPP_ABI_NAMESPACE)
17
18_LIBCPP_BEGIN_NAMESPACE_STD
19
20#ifndef _LIBCPP_HAS_NO_STDIN
21_ALIGNAS_TYPE (istream) _LIBCPP_FUNC_VIS char cin[sizeof(istream)]
22#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
23__asm__("?cin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
24#endif
25;
26_ALIGNAS_TYPE (__stdinbuf<char> ) static char __cin[sizeof(__stdinbuf <char>)];
27static mbstate_t mb_cin;
28_ALIGNAS_TYPE (wistream) _LIBCPP_FUNC_VIS char wcin[sizeof(wistream)]
29#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
30__asm__("?wcin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
31#endif
32;
33_ALIGNAS_TYPE (__stdinbuf<wchar_t> ) static char __wcin[sizeof(__stdinbuf <wchar_t>)];
34static mbstate_t mb_wcin;
35#endif
36
37#ifndef _LIBCPP_HAS_NO_STDOUT
38_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cout[sizeof(ostream)]
39#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
40__asm__("?cout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
41#endif
42;
43_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)];
44static mbstate_t mb_cout;
45_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcout[sizeof(wostream)]
46#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
47__asm__("?wcout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
48#endif
49;
50_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)];
51static mbstate_t mb_wcout;
52#endif
53
54_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char cerr[sizeof(ostream)]
55#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
56__asm__("?cerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
57#endif
58;
59_ALIGNAS_TYPE (__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)];
60static mbstate_t mb_cerr;
61_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wcerr[sizeof(wostream)]
62#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
63__asm__("?wcerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
64#endif
65;
66_ALIGNAS_TYPE (__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)];
67static mbstate_t mb_wcerr;
68
69_ALIGNAS_TYPE (ostream) _LIBCPP_FUNC_VIS char clog[sizeof(ostream)]
70#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
71__asm__("?clog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
72#endif
73;
74_ALIGNAS_TYPE (wostream) _LIBCPP_FUNC_VIS char wclog[sizeof(wostream)]
75#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__)
76__asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A")
77#endif
78;
79
80_LIBCPP_HIDDEN ios_base::Init __start_std_streams;
81
82// On Windows the TLS storage for locales needs to be initialized before we create
83// the standard streams, otherwise it may not be alive during program termination
84// when we flush the streams.
85static void force_locale_initialization() {
86#if defined(_LIBCPP_MSVCRT_LIKE)
87 static bool once = []() {
88 auto loc = newlocale(LC_ALL_MASK, "C", 0);
89 {
90 __libcpp_locale_guard g(loc); // forces initialization of locale TLS
91 ((void)g);
92 }
93 freelocale(loc);
94 return true;
95 }();
96 ((void)once);
97#endif
98}
99
100class DoIOSInit {
101public:
102 DoIOSInit();
103 ~DoIOSInit();
104};
105
106DoIOSInit::DoIOSInit()
107{
108 force_locale_initialization();
109
110#ifndef _LIBCPP_HAS_NO_STDIN
111 istream* cin_ptr = ::new(cin) istream(::new(__cin) __stdinbuf <char>(stdin, &mb_cin));
112 wistream* wcin_ptr = ::new(wcin) wistream(::new(__wcin) __stdinbuf <wchar_t>(stdin, &mb_wcin));
113#endif
114#ifndef _LIBCPP_HAS_NO_STDOUT
115 ostream* cout_ptr = ::new(cout) ostream(::new(__cout) __stdoutbuf<char>(stdout, &mb_cout));
116 wostream* wcout_ptr = ::new(wcout) wostream(::new(__wcout) __stdoutbuf<wchar_t>(stdout, &mb_wcout));
117#endif
118 ostream* cerr_ptr = ::new(cerr) ostream(::new(__cerr) __stdoutbuf<char>(stderr, &mb_cerr));
119 ::new(clog) ostream(cerr_ptr->rdbuf());
120 wostream* wcerr_ptr = ::new(wcerr) wostream(::new(__wcerr) __stdoutbuf<wchar_t>(stderr, &mb_wcerr));
121 ::new(wclog) wostream(wcerr_ptr->rdbuf());
122
123#if !defined(_LIBCPP_HAS_NO_STDIN) && !defined(_LIBCPP_HAS_NO_STDOUT)
124 cin_ptr->tie(cout_ptr);
125 wcin_ptr->tie(wcout_ptr);
126#endif
127 _VSTD::unitbuf(*cerr_ptr);
128 _VSTD::unitbuf(*wcerr_ptr);
129#ifndef _LIBCPP_HAS_NO_STDOUT
130 cerr_ptr->tie(cout_ptr);
131 wcerr_ptr->tie(wcout_ptr);
132#endif
133}
134
135DoIOSInit::~DoIOSInit()
136{
137#ifndef _LIBCPP_HAS_NO_STDOUT
138 ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
139 wostream* wcout_ptr = reinterpret_cast<wostream*>(wcout);
140 cout_ptr->flush();
141 wcout_ptr->flush();
142#endif
143
144 ostream* clog_ptr = reinterpret_cast<ostream*>(clog);
145 wostream* wclog_ptr = reinterpret_cast<wostream*>(wclog);
146 clog_ptr->flush();
147 wclog_ptr->flush();
148}
149
150ios_base::Init::Init()
151{
152 static DoIOSInit init_the_streams; // gets initialized once
153}
154
155ios_base::Init::~Init()
156{
157}
158
159_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/locale.cpp created+6154
...@@ -0,0 +1,6154 @@
1//===------------------------- locale.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// On Solaris, we need to define something to make the C99 parts of localeconv
10// visible.
11#ifdef __sun__
12#define _LCONV_C99
13#endif
14
15#include "string"
16#include "locale"
17#include "codecvt"
18#include "vector"
19#include "algorithm"
20#include "typeinfo"
21#ifndef _LIBCPP_NO_EXCEPTIONS
22# include "type_traits"
23#endif
24#include "clocale"
25#include "cstring"
26#if defined(_LIBCPP_MSVCRT)
27#define _CTYPE_DISABLE_MACROS
28#endif
29#include "cwctype"
30#include "__sso_allocator"
31#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
32#include "support/win32/locale_win32.h"
33#elif !defined(__BIONIC__)
34#include <langinfo.h>
35#endif
36#include <stdlib.h>
37#include <stdio.h>
38#include "include/atomic_support.h"
39#include "__undef_macros"
40
41// On Linux, wint_t and wchar_t have different signed-ness, and this causes
42// lots of noise in the build log, but no bugs that I know of.
43#if defined(__clang__)
44#pragma clang diagnostic ignored "-Wsign-conversion"
45#endif
46
47_LIBCPP_BEGIN_NAMESPACE_STD
48
49struct __libcpp_unique_locale {
50 __libcpp_unique_locale(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {}
51
52 ~__libcpp_unique_locale() {
53 if (__loc_)
54 freelocale(__loc_);
55 }
56
57 explicit operator bool() const { return __loc_; }
58
59 locale_t& get() { return __loc_; }
60
61 locale_t __loc_;
62private:
63 __libcpp_unique_locale(__libcpp_unique_locale const&);
64 __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
65};
66
67#ifdef __cloc_defined
68locale_t __cloc() {
69 // In theory this could create a race condition. In practice
70 // the race condition is non-fatal since it will just create
71 // a little resource leak. Better approach would be appreciated.
72 static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
73 return result;
74}
75#endif // __cloc_defined
76
77namespace {
78
79struct release
80{
81 void operator()(locale::facet* p) {p->__release_shared();}
82};
83
84template <class T, class A0>
85inline
86T&
87make(A0 a0)
88{
89 static typename aligned_storage<sizeof(T)>::type buf;
90 auto *obj = ::new (&buf) T(a0);
91 return *obj;
92}
93
94template <class T, class A0, class A1>
95inline
96T&
97make(A0 a0, A1 a1)
98{
99 static typename aligned_storage<sizeof(T)>::type buf;
100 ::new (&buf) T(a0, a1);
101 return *reinterpret_cast<T*>(&buf);
102}
103
104template <class T, class A0, class A1, class A2>
105inline
106T&
107make(A0 a0, A1 a1, A2 a2)
108{
109 static typename aligned_storage<sizeof(T)>::type buf;
110 auto *obj = ::new (&buf) T(a0, a1, a2);
111 return *obj;
112}
113
114template <typename T, size_t N>
115inline
116_LIBCPP_CONSTEXPR
117size_t
118countof(const T (&)[N])
119{
120 return N;
121}
122
123template <typename T>
124inline
125_LIBCPP_CONSTEXPR
126size_t
127countof(const T * const begin, const T * const end)
128{
129 return static_cast<size_t>(end - begin);
130}
131
132_LIBCPP_NORETURN static void __throw_runtime_error(const string &msg)
133{
134#ifndef _LIBCPP_NO_EXCEPTIONS
135 throw runtime_error(msg);
136#else
137 (void)msg;
138 _VSTD::abort();
139#endif
140}
141
142}
143
144#if defined(_AIX)
145// Set priority to INT_MIN + 256 + 150
146# pragma priority ( -2147483242 )
147#endif
148
149const locale::category locale::none;
150const locale::category locale::collate;
151const locale::category locale::ctype;
152const locale::category locale::monetary;
153const locale::category locale::numeric;
154const locale::category locale::time;
155const locale::category locale::messages;
156const locale::category locale::all;
157
158class _LIBCPP_HIDDEN locale::__imp
159 : public facet
160{
161 enum {N = 28};
162#if defined(_LIBCPP_COMPILER_MSVC)
163// FIXME: MSVC doesn't support aligned parameters by value.
164// I can't get the __sso_allocator to work here
165// for MSVC I think for this reason.
166 vector<facet*> facets_;
167#else
168 vector<facet*, __sso_allocator<facet*, N> > facets_;
169#endif
170 string name_;
171public:
172 explicit __imp(size_t refs = 0);
173 explicit __imp(const string& name, size_t refs = 0);
174 __imp(const __imp&);
175 __imp(const __imp&, const string&, locale::category c);
176 __imp(const __imp& other, const __imp& one, locale::category c);
177 __imp(const __imp&, facet* f, long id);
178 ~__imp();
179
180 const string& name() const {return name_;}
181 bool has_facet(long id) const
182 {return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
183 const locale::facet* use_facet(long id) const;
184
185 static const locale& make_classic();
186 static locale& make_global();
187private:
188 void install(facet* f, long id);
189 template <class F> void install(F* f) {install(f, f->id.__get());}
190 template <class F> void install_from(const __imp& other);
191};
192
193locale::__imp::__imp(size_t refs)
194 : facet(refs),
195 facets_(N),
196 name_("C")
197{
198 facets_.clear();
199 install(&make<_VSTD::collate<char> >(1u));
200 install(&make<_VSTD::collate<wchar_t> >(1u));
201 install(&make<_VSTD::ctype<char> >(nullptr, false, 1u));
202 install(&make<_VSTD::ctype<wchar_t> >(1u));
203 install(&make<codecvt<char, char, mbstate_t> >(1u));
204 install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
205 install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
206 install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
207 install(&make<numpunct<char> >(1u));
208 install(&make<numpunct<wchar_t> >(1u));
209 install(&make<num_get<char> >(1u));
210 install(&make<num_get<wchar_t> >(1u));
211 install(&make<num_put<char> >(1u));
212 install(&make<num_put<wchar_t> >(1u));
213 install(&make<moneypunct<char, false> >(1u));
214 install(&make<moneypunct<char, true> >(1u));
215 install(&make<moneypunct<wchar_t, false> >(1u));
216 install(&make<moneypunct<wchar_t, true> >(1u));
217 install(&make<money_get<char> >(1u));
218 install(&make<money_get<wchar_t> >(1u));
219 install(&make<money_put<char> >(1u));
220 install(&make<money_put<wchar_t> >(1u));
221 install(&make<time_get<char> >(1u));
222 install(&make<time_get<wchar_t> >(1u));
223 install(&make<time_put<char> >(1u));
224 install(&make<time_put<wchar_t> >(1u));
225 install(&make<_VSTD::messages<char> >(1u));
226 install(&make<_VSTD::messages<wchar_t> >(1u));
227}
228
229locale::__imp::__imp(const string& name, size_t refs)
230 : facet(refs),
231 facets_(N),
232 name_(name)
233{
234#ifndef _LIBCPP_NO_EXCEPTIONS
235 try
236 {
237#endif // _LIBCPP_NO_EXCEPTIONS
238 facets_ = locale::classic().__locale_->facets_;
239 for (unsigned i = 0; i < facets_.size(); ++i)
240 if (facets_[i])
241 facets_[i]->__add_shared();
242 install(new collate_byname<char>(name_));
243 install(new collate_byname<wchar_t>(name_));
244 install(new ctype_byname<char>(name_));
245 install(new ctype_byname<wchar_t>(name_));
246 install(new codecvt_byname<char, char, mbstate_t>(name_));
247 install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
248 install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
249 install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
250 install(new numpunct_byname<char>(name_));
251 install(new numpunct_byname<wchar_t>(name_));
252 install(new moneypunct_byname<char, false>(name_));
253 install(new moneypunct_byname<char, true>(name_));
254 install(new moneypunct_byname<wchar_t, false>(name_));
255 install(new moneypunct_byname<wchar_t, true>(name_));
256 install(new time_get_byname<char>(name_));
257 install(new time_get_byname<wchar_t>(name_));
258 install(new time_put_byname<char>(name_));
259 install(new time_put_byname<wchar_t>(name_));
260 install(new messages_byname<char>(name_));
261 install(new messages_byname<wchar_t>(name_));
262#ifndef _LIBCPP_NO_EXCEPTIONS
263 }
264 catch (...)
265 {
266 for (unsigned i = 0; i < facets_.size(); ++i)
267 if (facets_[i])
268 facets_[i]->__release_shared();
269 throw;
270 }
271#endif // _LIBCPP_NO_EXCEPTIONS
272}
273
274// NOTE avoid the `base class should be explicitly initialized in the
275// copy constructor` warning emitted by GCC
276#if defined(__clang__) || _GNUC_VER >= 406
277#pragma GCC diagnostic push
278#pragma GCC diagnostic ignored "-Wextra"
279#endif
280
281locale::__imp::__imp(const __imp& other)
282 : facets_(max<size_t>(N, other.facets_.size())),
283 name_(other.name_)
284{
285 facets_ = other.facets_;
286 for (unsigned i = 0; i < facets_.size(); ++i)
287 if (facets_[i])
288 facets_[i]->__add_shared();
289}
290
291#if defined(__clang__) || _GNUC_VER >= 406
292#pragma GCC diagnostic pop
293#endif
294
295locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
296 : facets_(N),
297 name_("*")
298{
299 facets_ = other.facets_;
300 for (unsigned i = 0; i < facets_.size(); ++i)
301 if (facets_[i])
302 facets_[i]->__add_shared();
303#ifndef _LIBCPP_NO_EXCEPTIONS
304 try
305 {
306#endif // _LIBCPP_NO_EXCEPTIONS
307 if (c & locale::collate)
308 {
309 install(new collate_byname<char>(name));
310 install(new collate_byname<wchar_t>(name));
311 }
312 if (c & locale::ctype)
313 {
314 install(new ctype_byname<char>(name));
315 install(new ctype_byname<wchar_t>(name));
316 install(new codecvt_byname<char, char, mbstate_t>(name));
317 install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
318 install(new codecvt_byname<char16_t, char, mbstate_t>(name));
319 install(new codecvt_byname<char32_t, char, mbstate_t>(name));
320 }
321 if (c & locale::monetary)
322 {
323 install(new moneypunct_byname<char, false>(name));
324 install(new moneypunct_byname<char, true>(name));
325 install(new moneypunct_byname<wchar_t, false>(name));
326 install(new moneypunct_byname<wchar_t, true>(name));
327 }
328 if (c & locale::numeric)
329 {
330 install(new numpunct_byname<char>(name));
331 install(new numpunct_byname<wchar_t>(name));
332 }
333 if (c & locale::time)
334 {
335 install(new time_get_byname<char>(name));
336 install(new time_get_byname<wchar_t>(name));
337 install(new time_put_byname<char>(name));
338 install(new time_put_byname<wchar_t>(name));
339 }
340 if (c & locale::messages)
341 {
342 install(new messages_byname<char>(name));
343 install(new messages_byname<wchar_t>(name));
344 }
345#ifndef _LIBCPP_NO_EXCEPTIONS
346 }
347 catch (...)
348 {
349 for (unsigned i = 0; i < facets_.size(); ++i)
350 if (facets_[i])
351 facets_[i]->__release_shared();
352 throw;
353 }
354#endif // _LIBCPP_NO_EXCEPTIONS
355}
356
357template<class F>
358inline
359void
360locale::__imp::install_from(const locale::__imp& one)
361{
362 long id = F::id.__get();
363 install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
364}
365
366locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
367 : facets_(N),
368 name_("*")
369{
370 facets_ = other.facets_;
371 for (unsigned i = 0; i < facets_.size(); ++i)
372 if (facets_[i])
373 facets_[i]->__add_shared();
374#ifndef _LIBCPP_NO_EXCEPTIONS
375 try
376 {
377#endif // _LIBCPP_NO_EXCEPTIONS
378 if (c & locale::collate)
379 {
380 install_from<_VSTD::collate<char> >(one);
381 install_from<_VSTD::collate<wchar_t> >(one);
382 }
383 if (c & locale::ctype)
384 {
385 install_from<_VSTD::ctype<char> >(one);
386 install_from<_VSTD::ctype<wchar_t> >(one);
387 install_from<_VSTD::codecvt<char, char, mbstate_t> >(one);
388 install_from<_VSTD::codecvt<char16_t, char, mbstate_t> >(one);
389 install_from<_VSTD::codecvt<char32_t, char, mbstate_t> >(one);
390 install_from<_VSTD::codecvt<wchar_t, char, mbstate_t> >(one);
391 }
392 if (c & locale::monetary)
393 {
394 install_from<moneypunct<char, false> >(one);
395 install_from<moneypunct<char, true> >(one);
396 install_from<moneypunct<wchar_t, false> >(one);
397 install_from<moneypunct<wchar_t, true> >(one);
398 install_from<money_get<char> >(one);
399 install_from<money_get<wchar_t> >(one);
400 install_from<money_put<char> >(one);
401 install_from<money_put<wchar_t> >(one);
402 }
403 if (c & locale::numeric)
404 {
405 install_from<numpunct<char> >(one);
406 install_from<numpunct<wchar_t> >(one);
407 install_from<num_get<char> >(one);
408 install_from<num_get<wchar_t> >(one);
409 install_from<num_put<char> >(one);
410 install_from<num_put<wchar_t> >(one);
411 }
412 if (c & locale::time)
413 {
414 install_from<time_get<char> >(one);
415 install_from<time_get<wchar_t> >(one);
416 install_from<time_put<char> >(one);
417 install_from<time_put<wchar_t> >(one);
418 }
419 if (c & locale::messages)
420 {
421 install_from<_VSTD::messages<char> >(one);
422 install_from<_VSTD::messages<wchar_t> >(one);
423 }
424#ifndef _LIBCPP_NO_EXCEPTIONS
425 }
426 catch (...)
427 {
428 for (unsigned i = 0; i < facets_.size(); ++i)
429 if (facets_[i])
430 facets_[i]->__release_shared();
431 throw;
432 }
433#endif // _LIBCPP_NO_EXCEPTIONS
434}
435
436locale::__imp::__imp(const __imp& other, facet* f, long id)
437 : facets_(max<size_t>(N, other.facets_.size()+1)),
438 name_("*")
439{
440 f->__add_shared();
441 unique_ptr<facet, release> hold(f);
442 facets_ = other.facets_;
443 for (unsigned i = 0; i < other.facets_.size(); ++i)
444 if (facets_[i])
445 facets_[i]->__add_shared();
446 install(hold.get(), id);
447}
448
449locale::__imp::~__imp()
450{
451 for (unsigned i = 0; i < facets_.size(); ++i)
452 if (facets_[i])
453 facets_[i]->__release_shared();
454}
455
456void
457locale::__imp::install(facet* f, long id)
458{
459 f->__add_shared();
460 unique_ptr<facet, release> hold(f);
461 if (static_cast<size_t>(id) >= facets_.size())
462 facets_.resize(static_cast<size_t>(id+1));
463 if (facets_[static_cast<size_t>(id)])
464 facets_[static_cast<size_t>(id)]->__release_shared();
465 facets_[static_cast<size_t>(id)] = hold.release();
466}
467
468const locale::facet*
469locale::__imp::use_facet(long id) const
470{
471 if (!has_facet(id))
472 __throw_bad_cast();
473 return facets_[static_cast<size_t>(id)];
474}
475
476// locale
477
478const locale&
479locale::__imp::make_classic()
480{
481 // only one thread can get in here and it only gets in once
482 static aligned_storage<sizeof(locale)>::type buf;
483 locale* c = reinterpret_cast<locale*>(&buf);
484 c->__locale_ = &make<__imp>(1u);
485 return *c;
486}
487
488const locale&
489locale::classic()
490{
491 static const locale& c = __imp::make_classic();
492 return c;
493}
494
495locale&
496locale::__imp::make_global()
497{
498 // only one thread can get in here and it only gets in once
499 static aligned_storage<sizeof(locale)>::type buf;
500 auto *obj = ::new (&buf) locale(locale::classic());
501 return *obj;
502}
503
504locale&
505locale::__global()
506{
507 static locale& g = __imp::make_global();
508 return g;
509}
510
511locale::locale() _NOEXCEPT
512 : __locale_(__global().__locale_)
513{
514 __locale_->__add_shared();
515}
516
517locale::locale(const locale& l) _NOEXCEPT
518 : __locale_(l.__locale_)
519{
520 __locale_->__add_shared();
521}
522
523locale::~locale()
524{
525 __locale_->__release_shared();
526}
527
528const locale&
529locale::operator=(const locale& other) _NOEXCEPT
530{
531 other.__locale_->__add_shared();
532 __locale_->__release_shared();
533 __locale_ = other.__locale_;
534 return *this;
535}
536
537locale::locale(const char* name)
538 : __locale_(name ? new __imp(name)
539 : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
540{
541 __locale_->__add_shared();
542}
543
544locale::locale(const string& name)
545 : __locale_(new __imp(name))
546{
547 __locale_->__add_shared();
548}
549
550locale::locale(const locale& other, const char* name, category c)
551 : __locale_(name ? new __imp(*other.__locale_, name, c)
552 : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
553{
554 __locale_->__add_shared();
555}
556
557locale::locale(const locale& other, const string& name, category c)
558 : __locale_(new __imp(*other.__locale_, name, c))
559{
560 __locale_->__add_shared();
561}
562
563locale::locale(const locale& other, const locale& one, category c)
564 : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
565{
566 __locale_->__add_shared();
567}
568
569string
570locale::name() const
571{
572 return __locale_->name();
573}
574
575void
576locale::__install_ctor(const locale& other, facet* f, long id)
577{
578 if (f)
579 __locale_ = new __imp(*other.__locale_, f, id);
580 else
581 __locale_ = other.__locale_;
582 __locale_->__add_shared();
583}
584
585locale
586locale::global(const locale& loc)
587{
588 locale& g = __global();
589 locale r = g;
590 g = loc;
591 if (g.name() != "*")
592 setlocale(LC_ALL, g.name().c_str());
593 return r;
594}
595
596bool
597locale::has_facet(id& x) const
598{
599 return __locale_->has_facet(x.__get());
600}
601
602const locale::facet*
603locale::use_facet(id& x) const
604{
605 return __locale_->use_facet(x.__get());
606}
607
608bool
609locale::operator==(const locale& y) const
610{
611 return (__locale_ == y.__locale_)
612 || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
613}
614
615// locale::facet
616
617locale::facet::~facet()
618{
619}
620
621void
622locale::facet::__on_zero_shared() _NOEXCEPT
623{
624 delete this;
625}
626
627// locale::id
628
629int32_t locale::id::__next_id = 0;
630
631namespace
632{
633
634class __fake_bind
635{
636 locale::id* id_;
637 void (locale::id::* pmf_)();
638public:
639 __fake_bind(void (locale::id::* pmf)(), locale::id* id)
640 : id_(id), pmf_(pmf) {}
641
642 void operator()() const
643 {
644 (id_->*pmf_)();
645 }
646};
647
648}
649
650long
651locale::id::__get()
652{
653 call_once(__flag_, __fake_bind(&locale::id::__init, this));
654 return __id_ - 1;
655}
656
657void
658locale::id::__init()
659{
660 __id_ = __libcpp_atomic_add(&__next_id, 1);
661}
662
663// template <> class collate_byname<char>
664
665collate_byname<char>::collate_byname(const char* n, size_t refs)
666 : collate<char>(refs),
667 __l(newlocale(LC_ALL_MASK, n, 0))
668{
669 if (__l == 0)
670 __throw_runtime_error("collate_byname<char>::collate_byname"
671 " failed to construct for " + string(n));
672}
673
674collate_byname<char>::collate_byname(const string& name, size_t refs)
675 : collate<char>(refs),
676 __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
677{
678 if (__l == 0)
679 __throw_runtime_error("collate_byname<char>::collate_byname"
680 " failed to construct for " + name);
681}
682
683collate_byname<char>::~collate_byname()
684{
685 freelocale(__l);
686}
687
688int
689collate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
690 const char_type* __lo2, const char_type* __hi2) const
691{
692 string_type lhs(__lo1, __hi1);
693 string_type rhs(__lo2, __hi2);
694 int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l);
695 if (r < 0)
696 return -1;
697 if (r > 0)
698 return 1;
699 return r;
700}
701
702collate_byname<char>::string_type
703collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
704{
705 const string_type in(lo, hi);
706 string_type out(strxfrm_l(0, in.c_str(), 0, __l), char());
707 strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l);
708 return out;
709}
710
711// template <> class collate_byname<wchar_t>
712
713collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
714 : collate<wchar_t>(refs),
715 __l(newlocale(LC_ALL_MASK, n, 0))
716{
717 if (__l == 0)
718 __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
719 " failed to construct for " + string(n));
720}
721
722collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
723 : collate<wchar_t>(refs),
724 __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
725{
726 if (__l == 0)
727 __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
728 " failed to construct for " + name);
729}
730
731collate_byname<wchar_t>::~collate_byname()
732{
733 freelocale(__l);
734}
735
736int
737collate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
738 const char_type* __lo2, const char_type* __hi2) const
739{
740 string_type lhs(__lo1, __hi1);
741 string_type rhs(__lo2, __hi2);
742 int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l);
743 if (r < 0)
744 return -1;
745 if (r > 0)
746 return 1;
747 return r;
748}
749
750collate_byname<wchar_t>::string_type
751collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
752{
753 const string_type in(lo, hi);
754 string_type out(wcsxfrm_l(0, in.c_str(), 0, __l), wchar_t());
755 wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l);
756 return out;
757}
758
759// template <> class ctype<wchar_t>;
760
761const ctype_base::mask ctype_base::space;
762const ctype_base::mask ctype_base::print;
763const ctype_base::mask ctype_base::cntrl;
764const ctype_base::mask ctype_base::upper;
765const ctype_base::mask ctype_base::lower;
766const ctype_base::mask ctype_base::alpha;
767const ctype_base::mask ctype_base::digit;
768const ctype_base::mask ctype_base::punct;
769const ctype_base::mask ctype_base::xdigit;
770const ctype_base::mask ctype_base::blank;
771const ctype_base::mask ctype_base::alnum;
772const ctype_base::mask ctype_base::graph;
773
774locale::id ctype<wchar_t>::id;
775
776ctype<wchar_t>::~ctype()
777{
778}
779
780bool
781ctype<wchar_t>::do_is(mask m, char_type c) const
782{
783 return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
784}
785
786const wchar_t*
787ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
788{
789 for (; low != high; ++low, ++vec)
790 *vec = static_cast<mask>(isascii(*low) ?
791 ctype<char>::classic_table()[*low] : 0);
792 return low;
793}
794
795const wchar_t*
796ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
797{
798 for (; low != high; ++low)
799 if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
800 break;
801 return low;
802}
803
804const wchar_t*
805ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
806{
807 for (; low != high; ++low)
808 if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
809 break;
810 return low;
811}
812
813wchar_t
814ctype<wchar_t>::do_toupper(char_type c) const
815{
816#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
817 return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
818#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
819 defined(__NetBSD__)
820 return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
821#else
822 return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c;
823#endif
824}
825
826const wchar_t*
827ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
828{
829 for (; low != high; ++low)
830#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
831 *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
832#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
833 defined(__NetBSD__)
834 *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
835 : *low;
836#else
837 *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low;
838#endif
839 return low;
840}
841
842wchar_t
843ctype<wchar_t>::do_tolower(char_type c) const
844{
845#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
846 return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
847#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
848 defined(__NetBSD__)
849 return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
850#else
851 return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c;
852#endif
853}
854
855const wchar_t*
856ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
857{
858 for (; low != high; ++low)
859#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
860 *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
861#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
862 defined(__NetBSD__)
863 *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
864 : *low;
865#else
866 *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low;
867#endif
868 return low;
869}
870
871wchar_t
872ctype<wchar_t>::do_widen(char c) const
873{
874 return c;
875}
876
877const char*
878ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
879{
880 for (; low != high; ++low, ++dest)
881 *dest = *low;
882 return low;
883}
884
885char
886ctype<wchar_t>::do_narrow(char_type c, char dfault) const
887{
888 if (isascii(c))
889 return static_cast<char>(c);
890 return dfault;
891}
892
893const wchar_t*
894ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
895{
896 for (; low != high; ++low, ++dest)
897 if (isascii(*low))
898 *dest = static_cast<char>(*low);
899 else
900 *dest = dfault;
901 return low;
902}
903
904// template <> class ctype<char>;
905
906locale::id ctype<char>::id;
907
908ctype<char>::ctype(const mask* tab, bool del, size_t refs)
909 : locale::facet(refs),
910 __tab_(tab),
911 __del_(del)
912{
913 if (__tab_ == 0)
914 __tab_ = classic_table();
915}
916
917ctype<char>::~ctype()
918{
919 if (__tab_ && __del_)
920 delete [] __tab_;
921}
922
923char
924ctype<char>::do_toupper(char_type c) const
925{
926#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
927 return isascii(c) ?
928 static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
929#elif defined(__NetBSD__)
930 return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
931#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
932 return isascii(c) ?
933 static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
934#else
935 return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c;
936#endif
937}
938
939const char*
940ctype<char>::do_toupper(char_type* low, const char_type* high) const
941{
942 for (; low != high; ++low)
943#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
944 *low = isascii(*low) ?
945 static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
946#elif defined(__NetBSD__)
947 *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
948#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
949 *low = isascii(*low) ?
950 static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
951#else
952 *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low;
953#endif
954 return low;
955}
956
957char
958ctype<char>::do_tolower(char_type c) const
959{
960#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
961 return isascii(c) ?
962 static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
963#elif defined(__NetBSD__)
964 return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
965#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
966 return isascii(c) ?
967 static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
968#else
969 return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c;
970#endif
971}
972
973const char*
974ctype<char>::do_tolower(char_type* low, const char_type* high) const
975{
976 for (; low != high; ++low)
977#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
978 *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
979#elif defined(__NetBSD__)
980 *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
981#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
982 *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
983#else
984 *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low;
985#endif
986 return low;
987}
988
989char
990ctype<char>::do_widen(char c) const
991{
992 return c;
993}
994
995const char*
996ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
997{
998 for (; low != high; ++low, ++dest)
999 *dest = *low;
1000 return low;
1001}
1002
1003char
1004ctype<char>::do_narrow(char_type c, char dfault) const
1005{
1006 if (isascii(c))
1007 return static_cast<char>(c);
1008 return dfault;
1009}
1010
1011const char*
1012ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
1013{
1014 for (; low != high; ++low, ++dest)
1015 if (isascii(*low))
1016 *dest = *low;
1017 else
1018 *dest = dfault;
1019 return low;
1020}
1021
1022#if defined(__EMSCRIPTEN__)
1023extern "C" const unsigned short ** __ctype_b_loc();
1024extern "C" const int ** __ctype_tolower_loc();
1025extern "C" const int ** __ctype_toupper_loc();
1026#endif
1027
1028#ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
1029const ctype<char>::mask*
1030ctype<char>::classic_table() _NOEXCEPT
1031{
1032 static _LIBCPP_CONSTEXPR const ctype<char>::mask builtin_table[table_size] = {
1033 cntrl, cntrl,
1034 cntrl, cntrl,
1035 cntrl, cntrl,
1036 cntrl, cntrl,
1037 cntrl, cntrl | space | blank,
1038 cntrl | space, cntrl | space,
1039 cntrl | space, cntrl | space,
1040 cntrl, cntrl,
1041 cntrl, cntrl,
1042 cntrl, cntrl,
1043 cntrl, cntrl,
1044 cntrl, cntrl,
1045 cntrl, cntrl,
1046 cntrl, cntrl,
1047 cntrl, cntrl,
1048 cntrl, cntrl,
1049 space | blank | print, punct | print,
1050 punct | print, punct | print,
1051 punct | print, punct | print,
1052 punct | print, punct | print,
1053 punct | print, punct | print,
1054 punct | print, punct | print,
1055 punct | print, punct | print,
1056 punct | print, punct | print,
1057 digit | print | xdigit, digit | print | xdigit,
1058 digit | print | xdigit, digit | print | xdigit,
1059 digit | print | xdigit, digit | print | xdigit,
1060 digit | print | xdigit, digit | print | xdigit,
1061 digit | print | xdigit, digit | print | xdigit,
1062 punct | print, punct | print,
1063 punct | print, punct | print,
1064 punct | print, punct | print,
1065 punct | print, upper | xdigit | print | alpha,
1066 upper | xdigit | print | alpha, upper | xdigit | print | alpha,
1067 upper | xdigit | print | alpha, upper | xdigit | print | alpha,
1068 upper | xdigit | print | alpha, upper | print | alpha,
1069 upper | print | alpha, upper | print | alpha,
1070 upper | print | alpha, upper | print | alpha,
1071 upper | print | alpha, upper | print | alpha,
1072 upper | print | alpha, upper | print | alpha,
1073 upper | print | alpha, upper | print | alpha,
1074 upper | print | alpha, upper | print | alpha,
1075 upper | print | alpha, upper | print | alpha,
1076 upper | print | alpha, upper | print | alpha,
1077 upper | print | alpha, upper | print | alpha,
1078 upper | print | alpha, punct | print,
1079 punct | print, punct | print,
1080 punct | print, punct | print,
1081 punct | print, lower | xdigit | print | alpha,
1082 lower | xdigit | print | alpha, lower | xdigit | print | alpha,
1083 lower | xdigit | print | alpha, lower | xdigit | print | alpha,
1084 lower | xdigit | print | alpha, lower | print | alpha,
1085 lower | print | alpha, lower | print | alpha,
1086 lower | print | alpha, lower | print | alpha,
1087 lower | print | alpha, lower | print | alpha,
1088 lower | print | alpha, lower | print | alpha,
1089 lower | print | alpha, lower | print | alpha,
1090 lower | print | alpha, lower | print | alpha,
1091 lower | print | alpha, lower | print | alpha,
1092 lower | print | alpha, lower | print | alpha,
1093 lower | print | alpha, lower | print | alpha,
1094 lower | print | alpha, punct | print,
1095 punct | print, punct | print,
1096 punct | print, cntrl,
1097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1105 };
1106 return builtin_table;
1107}
1108#else
1109const ctype<char>::mask*
1110ctype<char>::classic_table() _NOEXCEPT
1111{
1112#if defined(__APPLE__) || defined(__FreeBSD__)
1113 return _DefaultRuneLocale.__runetype;
1114#elif defined(__NetBSD__)
1115 return _C_ctype_tab_ + 1;
1116#elif defined(__GLIBC__)
1117 return _LIBCPP_GET_C_LOCALE->__ctype_b;
1118#elif __sun__
1119 return __ctype_mask;
1120#elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
1121 return __pctype_func();
1122#elif defined(__EMSCRIPTEN__)
1123 return *__ctype_b_loc();
1124#elif defined(_NEWLIB_VERSION)
1125 // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
1126 return _ctype_ + 1;
1127#elif defined(_AIX)
1128 return (const unsigned int *)__lc_ctype_ptr->obj->mask;
1129#else
1130 // Platform not supported: abort so the person doing the port knows what to
1131 // fix
1132# warning ctype<char>::classic_table() is not implemented
1133 printf("ctype<char>::classic_table() is not implemented\n");
1134 abort();
1135 return NULL;
1136#endif
1137}
1138#endif
1139
1140#if defined(__GLIBC__)
1141const int*
1142ctype<char>::__classic_lower_table() _NOEXCEPT
1143{
1144 return _LIBCPP_GET_C_LOCALE->__ctype_tolower;
1145}
1146
1147const int*
1148ctype<char>::__classic_upper_table() _NOEXCEPT
1149{
1150 return _LIBCPP_GET_C_LOCALE->__ctype_toupper;
1151}
1152#elif __NetBSD__
1153const short*
1154ctype<char>::__classic_lower_table() _NOEXCEPT
1155{
1156 return _C_tolower_tab_ + 1;
1157}
1158
1159const short*
1160ctype<char>::__classic_upper_table() _NOEXCEPT
1161{
1162 return _C_toupper_tab_ + 1;
1163}
1164
1165#elif defined(__EMSCRIPTEN__)
1166const int*
1167ctype<char>::__classic_lower_table() _NOEXCEPT
1168{
1169 return *__ctype_tolower_loc();
1170}
1171
1172const int*
1173ctype<char>::__classic_upper_table() _NOEXCEPT
1174{
1175 return *__ctype_toupper_loc();
1176}
1177#endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__
1178
1179// template <> class ctype_byname<char>
1180
1181ctype_byname<char>::ctype_byname(const char* name, size_t refs)
1182 : ctype<char>(0, false, refs),
1183 __l(newlocale(LC_ALL_MASK, name, 0))
1184{
1185 if (__l == 0)
1186 __throw_runtime_error("ctype_byname<char>::ctype_byname"
1187 " failed to construct for " + string(name));
1188}
1189
1190ctype_byname<char>::ctype_byname(const string& name, size_t refs)
1191 : ctype<char>(0, false, refs),
1192 __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
1193{
1194 if (__l == 0)
1195 __throw_runtime_error("ctype_byname<char>::ctype_byname"
1196 " failed to construct for " + name);
1197}
1198
1199ctype_byname<char>::~ctype_byname()
1200{
1201 freelocale(__l);
1202}
1203
1204char
1205ctype_byname<char>::do_toupper(char_type c) const
1206{
1207 return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l));
1208}
1209
1210const char*
1211ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
1212{
1213 for (; low != high; ++low)
1214 *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l));
1215 return low;
1216}
1217
1218char
1219ctype_byname<char>::do_tolower(char_type c) const
1220{
1221 return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l));
1222}
1223
1224const char*
1225ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
1226{
1227 for (; low != high; ++low)
1228 *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l));
1229 return low;
1230}
1231
1232// template <> class ctype_byname<wchar_t>
1233
1234ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
1235 : ctype<wchar_t>(refs),
1236 __l(newlocale(LC_ALL_MASK, name, 0))
1237{
1238 if (__l == 0)
1239 __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
1240 " failed to construct for " + string(name));
1241}
1242
1243ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
1244 : ctype<wchar_t>(refs),
1245 __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
1246{
1247 if (__l == 0)
1248 __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
1249 " failed to construct for " + name);
1250}
1251
1252ctype_byname<wchar_t>::~ctype_byname()
1253{
1254 freelocale(__l);
1255}
1256
1257bool
1258ctype_byname<wchar_t>::do_is(mask m, char_type c) const
1259{
1260#ifdef _LIBCPP_WCTYPE_IS_MASK
1261 return static_cast<bool>(iswctype_l(c, m, __l));
1262#else
1263 bool result = false;
1264 wint_t ch = static_cast<wint_t>(c);
1265 if ((m & space) == space) result |= (iswspace_l(ch, __l) != 0);
1266 if ((m & print) == print) result |= (iswprint_l(ch, __l) != 0);
1267 if ((m & cntrl) == cntrl) result |= (iswcntrl_l(ch, __l) != 0);
1268 if ((m & upper) == upper) result |= (iswupper_l(ch, __l) != 0);
1269 if ((m & lower) == lower) result |= (iswlower_l(ch, __l) != 0);
1270 if ((m & alpha) == alpha) result |= (iswalpha_l(ch, __l) != 0);
1271 if ((m & digit) == digit) result |= (iswdigit_l(ch, __l) != 0);
1272 if ((m & punct) == punct) result |= (iswpunct_l(ch, __l) != 0);
1273 if ((m & xdigit) == xdigit) result |= (iswxdigit_l(ch, __l) != 0);
1274 if ((m & blank) == blank) result |= (iswblank_l(ch, __l) != 0);
1275 return result;
1276#endif
1277}
1278
1279const wchar_t*
1280ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
1281{
1282 for (; low != high; ++low, ++vec)
1283 {
1284 if (isascii(*low))
1285 *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
1286 else
1287 {
1288 *vec = 0;
1289 wint_t ch = static_cast<wint_t>(*low);
1290 if (iswspace_l(ch, __l))
1291 *vec |= space;
1292#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
1293 if (iswprint_l(ch, __l))
1294 *vec |= print;
1295#endif
1296 if (iswcntrl_l(ch, __l))
1297 *vec |= cntrl;
1298 if (iswupper_l(ch, __l))
1299 *vec |= upper;
1300 if (iswlower_l(ch, __l))
1301 *vec |= lower;
1302#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
1303 if (iswalpha_l(ch, __l))
1304 *vec |= alpha;
1305#endif
1306 if (iswdigit_l(ch, __l))
1307 *vec |= digit;
1308 if (iswpunct_l(ch, __l))
1309 *vec |= punct;
1310#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
1311 if (iswxdigit_l(ch, __l))
1312 *vec |= xdigit;
1313#endif
1314#if !defined(__sun__)
1315 if (iswblank_l(ch, __l))
1316 *vec |= blank;
1317#endif
1318 }
1319 }
1320 return low;
1321}
1322
1323const wchar_t*
1324ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
1325{
1326 for (; low != high; ++low)
1327 {
1328#ifdef _LIBCPP_WCTYPE_IS_MASK
1329 if (iswctype_l(*low, m, __l))
1330 break;
1331#else
1332 wint_t ch = static_cast<wint_t>(*low);
1333 if ((m & space) == space && iswspace_l(ch, __l)) break;
1334 if ((m & print) == print && iswprint_l(ch, __l)) break;
1335 if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) break;
1336 if ((m & upper) == upper && iswupper_l(ch, __l)) break;
1337 if ((m & lower) == lower && iswlower_l(ch, __l)) break;
1338 if ((m & alpha) == alpha && iswalpha_l(ch, __l)) break;
1339 if ((m & digit) == digit && iswdigit_l(ch, __l)) break;
1340 if ((m & punct) == punct && iswpunct_l(ch, __l)) break;
1341 if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) break;
1342 if ((m & blank) == blank && iswblank_l(ch, __l)) break;
1343#endif
1344 }
1345 return low;
1346}
1347
1348const wchar_t*
1349ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
1350{
1351 for (; low != high; ++low)
1352 {
1353#ifdef _LIBCPP_WCTYPE_IS_MASK
1354 if (!iswctype_l(*low, m, __l))
1355 break;
1356#else
1357 wint_t ch = static_cast<wint_t>(*low);
1358 if ((m & space) == space && iswspace_l(ch, __l)) continue;
1359 if ((m & print) == print && iswprint_l(ch, __l)) continue;
1360 if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) continue;
1361 if ((m & upper) == upper && iswupper_l(ch, __l)) continue;
1362 if ((m & lower) == lower && iswlower_l(ch, __l)) continue;
1363 if ((m & alpha) == alpha && iswalpha_l(ch, __l)) continue;
1364 if ((m & digit) == digit && iswdigit_l(ch, __l)) continue;
1365 if ((m & punct) == punct && iswpunct_l(ch, __l)) continue;
1366 if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) continue;
1367 if ((m & blank) == blank && iswblank_l(ch, __l)) continue;
1368 break;
1369#endif
1370 }
1371 return low;
1372}
1373
1374wchar_t
1375ctype_byname<wchar_t>::do_toupper(char_type c) const
1376{
1377 return towupper_l(c, __l);
1378}
1379
1380const wchar_t*
1381ctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const
1382{
1383 for (; low != high; ++low)
1384 *low = towupper_l(*low, __l);
1385 return low;
1386}
1387
1388wchar_t
1389ctype_byname<wchar_t>::do_tolower(char_type c) const
1390{
1391 return towlower_l(c, __l);
1392}
1393
1394const wchar_t*
1395ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const
1396{
1397 for (; low != high; ++low)
1398 *low = towlower_l(*low, __l);
1399 return low;
1400}
1401
1402wchar_t
1403ctype_byname<wchar_t>::do_widen(char c) const
1404{
1405 return __libcpp_btowc_l(c, __l);
1406}
1407
1408const char*
1409ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
1410{
1411 for (; low != high; ++low, ++dest)
1412 *dest = __libcpp_btowc_l(*low, __l);
1413 return low;
1414}
1415
1416char
1417ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const
1418{
1419 int r = __libcpp_wctob_l(c, __l);
1420 return r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
1421}
1422
1423const wchar_t*
1424ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
1425{
1426 for (; low != high; ++low, ++dest)
1427 {
1428 int r = __libcpp_wctob_l(*low, __l);
1429 *dest = r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
1430 }
1431 return low;
1432}
1433
1434// template <> class codecvt<char, char, mbstate_t>
1435
1436locale::id codecvt<char, char, mbstate_t>::id;
1437
1438codecvt<char, char, mbstate_t>::~codecvt()
1439{
1440}
1441
1442codecvt<char, char, mbstate_t>::result
1443codecvt<char, char, mbstate_t>::do_out(state_type&,
1444 const intern_type* frm, const intern_type*, const intern_type*& frm_nxt,
1445 extern_type* to, extern_type*, extern_type*& to_nxt) const
1446{
1447 frm_nxt = frm;
1448 to_nxt = to;
1449 return noconv;
1450}
1451
1452codecvt<char, char, mbstate_t>::result
1453codecvt<char, char, mbstate_t>::do_in(state_type&,
1454 const extern_type* frm, const extern_type*, const extern_type*& frm_nxt,
1455 intern_type* to, intern_type*, intern_type*& to_nxt) const
1456{
1457 frm_nxt = frm;
1458 to_nxt = to;
1459 return noconv;
1460}
1461
1462codecvt<char, char, mbstate_t>::result
1463codecvt<char, char, mbstate_t>::do_unshift(state_type&,
1464 extern_type* to, extern_type*, extern_type*& to_nxt) const
1465{
1466 to_nxt = to;
1467 return noconv;
1468}
1469
1470int
1471codecvt<char, char, mbstate_t>::do_encoding() const _NOEXCEPT
1472{
1473 return 1;
1474}
1475
1476bool
1477codecvt<char, char, mbstate_t>::do_always_noconv() const _NOEXCEPT
1478{
1479 return true;
1480}
1481
1482int
1483codecvt<char, char, mbstate_t>::do_length(state_type&,
1484 const extern_type* frm, const extern_type* end, size_t mx) const
1485{
1486 return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end-frm)));
1487}
1488
1489int
1490codecvt<char, char, mbstate_t>::do_max_length() const _NOEXCEPT
1491{
1492 return 1;
1493}
1494
1495// template <> class codecvt<wchar_t, char, mbstate_t>
1496
1497locale::id codecvt<wchar_t, char, mbstate_t>::id;
1498
1499codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
1500 : locale::facet(refs),
1501 __l(_LIBCPP_GET_C_LOCALE)
1502{
1503}
1504
1505codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
1506 : locale::facet(refs),
1507 __l(newlocale(LC_ALL_MASK, nm, 0))
1508{
1509 if (__l == 0)
1510 __throw_runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
1511 " failed to construct for " + string(nm));
1512}
1513
1514codecvt<wchar_t, char, mbstate_t>::~codecvt()
1515{
1516 if (__l != _LIBCPP_GET_C_LOCALE)
1517 freelocale(__l);
1518}
1519
1520codecvt<wchar_t, char, mbstate_t>::result
1521codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
1522 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
1523 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
1524{
1525 // look for first internal null in frm
1526 const intern_type* fend = frm;
1527 for (; fend != frm_end; ++fend)
1528 if (*fend == 0)
1529 break;
1530 // loop over all null-terminated sequences in frm
1531 to_nxt = to;
1532 for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
1533 {
1534 // save state in case it is needed to recover to_nxt on error
1535 mbstate_t save_state = st;
1536 size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1537 static_cast<size_t>(to_end-to), &st, __l);
1538 if (n == size_t(-1))
1539 {
1540 // need to recover to_nxt
1541 for (to_nxt = to; frm != frm_nxt; ++frm)
1542 {
1543 n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l);
1544 if (n == size_t(-1))
1545 break;
1546 to_nxt += n;
1547 }
1548 frm_nxt = frm;
1549 return error;
1550 }
1551 if (n == 0)
1552 return partial;
1553 to_nxt += n;
1554 if (to_nxt == to_end)
1555 break;
1556 if (fend != frm_end) // set up next null terminated sequence
1557 {
1558 // Try to write the terminating null
1559 extern_type tmp[MB_LEN_MAX];
1560 n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
1561 if (n == size_t(-1)) // on error
1562 return error;
1563 if (n > static_cast<size_t>(to_end-to_nxt)) // is there room?
1564 return partial;
1565 for (extern_type* p = tmp; n; --n) // write it
1566 *to_nxt++ = *p++;
1567 ++frm_nxt;
1568 // look for next null in frm
1569 for (fend = frm_nxt; fend != frm_end; ++fend)
1570 if (*fend == 0)
1571 break;
1572 }
1573 }
1574 return frm_nxt == frm_end ? ok : partial;
1575}
1576
1577codecvt<wchar_t, char, mbstate_t>::result
1578codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
1579 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
1580 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
1581{
1582 // look for first internal null in frm
1583 const extern_type* fend = frm;
1584 for (; fend != frm_end; ++fend)
1585 if (*fend == 0)
1586 break;
1587 // loop over all null-terminated sequences in frm
1588 to_nxt = to;
1589 for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
1590 {
1591 // save state in case it is needed to recover to_nxt on error
1592 mbstate_t save_state = st;
1593 size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1594 static_cast<size_t>(to_end-to), &st, __l);
1595 if (n == size_t(-1))
1596 {
1597 // need to recover to_nxt
1598 for (to_nxt = to; frm != frm_nxt; ++to_nxt)
1599 {
1600 n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm),
1601 &save_state, __l);
1602 switch (n)
1603 {
1604 case 0:
1605 ++frm;
1606 break;
1607 case size_t(-1):
1608 frm_nxt = frm;
1609 return error;
1610 case size_t(-2):
1611 frm_nxt = frm;
1612 return partial;
1613 default:
1614 frm += n;
1615 break;
1616 }
1617 }
1618 frm_nxt = frm;
1619 return frm_nxt == frm_end ? ok : partial;
1620 }
1621 if (n == size_t(-1))
1622 return error;
1623 to_nxt += n;
1624 if (to_nxt == to_end)
1625 break;
1626 if (fend != frm_end) // set up next null terminated sequence
1627 {
1628 // Try to write the terminating null
1629 n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l);
1630 if (n != 0) // on error
1631 return error;
1632 ++to_nxt;
1633 ++frm_nxt;
1634 // look for next null in frm
1635 for (fend = frm_nxt; fend != frm_end; ++fend)
1636 if (*fend == 0)
1637 break;
1638 }
1639 }
1640 return frm_nxt == frm_end ? ok : partial;
1641}
1642
1643codecvt<wchar_t, char, mbstate_t>::result
1644codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st,
1645 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
1646{
1647 to_nxt = to;
1648 extern_type tmp[MB_LEN_MAX];
1649 size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
1650 if (n == size_t(-1) || n == 0) // on error
1651 return error;
1652 --n;
1653 if (n > static_cast<size_t>(to_end-to_nxt)) // is there room?
1654 return partial;
1655 for (extern_type* p = tmp; n; --n) // write it
1656 *to_nxt++ = *p++;
1657 return ok;
1658}
1659
1660int
1661codecvt<wchar_t, char, mbstate_t>::do_encoding() const _NOEXCEPT
1662{
1663 if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0)
1664 return -1;
1665
1666 // stateless encoding
1667 if (__l == 0 || __libcpp_mb_cur_max_l(__l) == 1) // there are no known constant length encodings
1668 return 1; // which take more than 1 char to form a wchar_t
1669 return 0;
1670}
1671
1672bool
1673codecvt<wchar_t, char, mbstate_t>::do_always_noconv() const _NOEXCEPT
1674{
1675 return false;
1676}
1677
1678int
1679codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st,
1680 const extern_type* frm, const extern_type* frm_end, size_t mx) const
1681{
1682 int nbytes = 0;
1683 for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t)
1684 {
1685 size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l);
1686 switch (n)
1687 {
1688 case 0:
1689 ++nbytes;
1690 ++frm;
1691 break;
1692 case size_t(-1):
1693 case size_t(-2):
1694 return nbytes;
1695 default:
1696 nbytes += n;
1697 frm += n;
1698 break;
1699 }
1700 }
1701 return nbytes;
1702}
1703
1704int
1705codecvt<wchar_t, char, mbstate_t>::do_max_length() const _NOEXCEPT
1706{
1707 return __l == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l));
1708}
1709
1710// Valid UTF ranges
1711// UTF-32 UTF-16 UTF-8 # of code points
1712// first second first second third fourth
1713// 000000 - 00007F 0000 - 007F 00 - 7F 127
1714// 000080 - 0007FF 0080 - 07FF C2 - DF, 80 - BF 1920
1715// 000800 - 000FFF 0800 - 0FFF E0 - E0, A0 - BF, 80 - BF 2048
1716// 001000 - 00CFFF 1000 - CFFF E1 - EC, 80 - BF, 80 - BF 49152
1717// 00D000 - 00D7FF D000 - D7FF ED - ED, 80 - 9F, 80 - BF 2048
1718// 00D800 - 00DFFF invalid
1719// 00E000 - 00FFFF E000 - FFFF EE - EF, 80 - BF, 80 - BF 8192
1720// 010000 - 03FFFF D800 - D8BF, DC00 - DFFF F0 - F0, 90 - BF, 80 - BF, 80 - BF 196608
1721// 040000 - 0FFFFF D8C0 - DBBF, DC00 - DFFF F1 - F3, 80 - BF, 80 - BF, 80 - BF 786432
1722// 100000 - 10FFFF DBC0 - DBFF, DC00 - DFFF F4 - F4, 80 - 8F, 80 - BF, 80 - BF 65536
1723
1724static
1725codecvt_base::result
1726utf16_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
1727 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
1728 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1729{
1730 frm_nxt = frm;
1731 to_nxt = to;
1732 if (mode & generate_header)
1733 {
1734 if (to_end-to_nxt < 3)
1735 return codecvt_base::partial;
1736 *to_nxt++ = static_cast<uint8_t>(0xEF);
1737 *to_nxt++ = static_cast<uint8_t>(0xBB);
1738 *to_nxt++ = static_cast<uint8_t>(0xBF);
1739 }
1740 for (; frm_nxt < frm_end; ++frm_nxt)
1741 {
1742 uint16_t wc1 = *frm_nxt;
1743 if (wc1 > Maxcode)
1744 return codecvt_base::error;
1745 if (wc1 < 0x0080)
1746 {
1747 if (to_end-to_nxt < 1)
1748 return codecvt_base::partial;
1749 *to_nxt++ = static_cast<uint8_t>(wc1);
1750 }
1751 else if (wc1 < 0x0800)
1752 {
1753 if (to_end-to_nxt < 2)
1754 return codecvt_base::partial;
1755 *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
1756 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1757 }
1758 else if (wc1 < 0xD800)
1759 {
1760 if (to_end-to_nxt < 3)
1761 return codecvt_base::partial;
1762 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
1763 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1764 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1765 }
1766 else if (wc1 < 0xDC00)
1767 {
1768 if (frm_end-frm_nxt < 2)
1769 return codecvt_base::partial;
1770 uint16_t wc2 = frm_nxt[1];
1771 if ((wc2 & 0xFC00) != 0xDC00)
1772 return codecvt_base::error;
1773 if (to_end-to_nxt < 4)
1774 return codecvt_base::partial;
1775 if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
1776 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
1777 return codecvt_base::error;
1778 ++frm_nxt;
1779 uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
1780 *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
1781 *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2));
1782 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
1783 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc2 & 0x003F));
1784 }
1785 else if (wc1 < 0xE000)
1786 {
1787 return codecvt_base::error;
1788 }
1789 else
1790 {
1791 if (to_end-to_nxt < 3)
1792 return codecvt_base::partial;
1793 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
1794 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1795 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1796 }
1797 }
1798 return codecvt_base::ok;
1799}
1800
1801static
1802codecvt_base::result
1803utf16_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
1804 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
1805 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1806{
1807 frm_nxt = frm;
1808 to_nxt = to;
1809 if (mode & generate_header)
1810 {
1811 if (to_end-to_nxt < 3)
1812 return codecvt_base::partial;
1813 *to_nxt++ = static_cast<uint8_t>(0xEF);
1814 *to_nxt++ = static_cast<uint8_t>(0xBB);
1815 *to_nxt++ = static_cast<uint8_t>(0xBF);
1816 }
1817 for (; frm_nxt < frm_end; ++frm_nxt)
1818 {
1819 uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
1820 if (wc1 > Maxcode)
1821 return codecvt_base::error;
1822 if (wc1 < 0x0080)
1823 {
1824 if (to_end-to_nxt < 1)
1825 return codecvt_base::partial;
1826 *to_nxt++ = static_cast<uint8_t>(wc1);
1827 }
1828 else if (wc1 < 0x0800)
1829 {
1830 if (to_end-to_nxt < 2)
1831 return codecvt_base::partial;
1832 *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
1833 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1834 }
1835 else if (wc1 < 0xD800)
1836 {
1837 if (to_end-to_nxt < 3)
1838 return codecvt_base::partial;
1839 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
1840 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1841 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1842 }
1843 else if (wc1 < 0xDC00)
1844 {
1845 if (frm_end-frm_nxt < 2)
1846 return codecvt_base::partial;
1847 uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
1848 if ((wc2 & 0xFC00) != 0xDC00)
1849 return codecvt_base::error;
1850 if (to_end-to_nxt < 4)
1851 return codecvt_base::partial;
1852 if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
1853 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
1854 return codecvt_base::error;
1855 ++frm_nxt;
1856 uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
1857 *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
1858 *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2));
1859 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
1860 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc2 & 0x003F));
1861 }
1862 else if (wc1 < 0xE000)
1863 {
1864 return codecvt_base::error;
1865 }
1866 else
1867 {
1868 if (to_end-to_nxt < 3)
1869 return codecvt_base::partial;
1870 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
1871 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1872 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1873 }
1874 }
1875 return codecvt_base::ok;
1876}
1877
1878static
1879codecvt_base::result
1880utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
1881 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
1882 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1883{
1884 frm_nxt = frm;
1885 to_nxt = to;
1886 if (mode & consume_header)
1887 {
1888 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
1889 frm_nxt[2] == 0xBF)
1890 frm_nxt += 3;
1891 }
1892 for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
1893 {
1894 uint8_t c1 = *frm_nxt;
1895 if (c1 > Maxcode)
1896 return codecvt_base::error;
1897 if (c1 < 0x80)
1898 {
1899 *to_nxt = static_cast<uint16_t>(c1);
1900 ++frm_nxt;
1901 }
1902 else if (c1 < 0xC2)
1903 {
1904 return codecvt_base::error;
1905 }
1906 else if (c1 < 0xE0)
1907 {
1908 if (frm_end-frm_nxt < 2)
1909 return codecvt_base::partial;
1910 uint8_t c2 = frm_nxt[1];
1911 if ((c2 & 0xC0) != 0x80)
1912 return codecvt_base::error;
1913 uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
1914 if (t > Maxcode)
1915 return codecvt_base::error;
1916 *to_nxt = t;
1917 frm_nxt += 2;
1918 }
1919 else if (c1 < 0xF0)
1920 {
1921 if (frm_end-frm_nxt < 3)
1922 return codecvt_base::partial;
1923 uint8_t c2 = frm_nxt[1];
1924 uint8_t c3 = frm_nxt[2];
1925 switch (c1)
1926 {
1927 case 0xE0:
1928 if ((c2 & 0xE0) != 0xA0)
1929 return codecvt_base::error;
1930 break;
1931 case 0xED:
1932 if ((c2 & 0xE0) != 0x80)
1933 return codecvt_base::error;
1934 break;
1935 default:
1936 if ((c2 & 0xC0) != 0x80)
1937 return codecvt_base::error;
1938 break;
1939 }
1940 if ((c3 & 0xC0) != 0x80)
1941 return codecvt_base::error;
1942 uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
1943 | ((c2 & 0x3F) << 6)
1944 | (c3 & 0x3F));
1945 if (t > Maxcode)
1946 return codecvt_base::error;
1947 *to_nxt = t;
1948 frm_nxt += 3;
1949 }
1950 else if (c1 < 0xF5)
1951 {
1952 if (frm_end-frm_nxt < 4)
1953 return codecvt_base::partial;
1954 uint8_t c2 = frm_nxt[1];
1955 uint8_t c3 = frm_nxt[2];
1956 uint8_t c4 = frm_nxt[3];
1957 switch (c1)
1958 {
1959 case 0xF0:
1960 if (!(0x90 <= c2 && c2 <= 0xBF))
1961 return codecvt_base::error;
1962 break;
1963 case 0xF4:
1964 if ((c2 & 0xF0) != 0x80)
1965 return codecvt_base::error;
1966 break;
1967 default:
1968 if ((c2 & 0xC0) != 0x80)
1969 return codecvt_base::error;
1970 break;
1971 }
1972 if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
1973 return codecvt_base::error;
1974 if (to_end-to_nxt < 2)
1975 return codecvt_base::partial;
1976 if ((((c1 & 7UL) << 18) +
1977 ((c2 & 0x3FUL) << 12) +
1978 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
1979 return codecvt_base::error;
1980 *to_nxt = static_cast<uint16_t>(
1981 0xD800
1982 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
1983 | ((c2 & 0x0F) << 2)
1984 | ((c3 & 0x30) >> 4));
1985 *++to_nxt = static_cast<uint16_t>(
1986 0xDC00
1987 | ((c3 & 0x0F) << 6)
1988 | (c4 & 0x3F));
1989 frm_nxt += 4;
1990 }
1991 else
1992 {
1993 return codecvt_base::error;
1994 }
1995 }
1996 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
1997}
1998
1999static
2000codecvt_base::result
2001utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2002 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2003 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2004{
2005 frm_nxt = frm;
2006 to_nxt = to;
2007 if (mode & consume_header)
2008 {
2009 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2010 frm_nxt[2] == 0xBF)
2011 frm_nxt += 3;
2012 }
2013 for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2014 {
2015 uint8_t c1 = *frm_nxt;
2016 if (c1 > Maxcode)
2017 return codecvt_base::error;
2018 if (c1 < 0x80)
2019 {
2020 *to_nxt = static_cast<uint32_t>(c1);
2021 ++frm_nxt;
2022 }
2023 else if (c1 < 0xC2)
2024 {
2025 return codecvt_base::error;
2026 }
2027 else if (c1 < 0xE0)
2028 {
2029 if (frm_end-frm_nxt < 2)
2030 return codecvt_base::partial;
2031 uint8_t c2 = frm_nxt[1];
2032 if ((c2 & 0xC0) != 0x80)
2033 return codecvt_base::error;
2034 uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
2035 if (t > Maxcode)
2036 return codecvt_base::error;
2037 *to_nxt = static_cast<uint32_t>(t);
2038 frm_nxt += 2;
2039 }
2040 else if (c1 < 0xF0)
2041 {
2042 if (frm_end-frm_nxt < 3)
2043 return codecvt_base::partial;
2044 uint8_t c2 = frm_nxt[1];
2045 uint8_t c3 = frm_nxt[2];
2046 switch (c1)
2047 {
2048 case 0xE0:
2049 if ((c2 & 0xE0) != 0xA0)
2050 return codecvt_base::error;
2051 break;
2052 case 0xED:
2053 if ((c2 & 0xE0) != 0x80)
2054 return codecvt_base::error;
2055 break;
2056 default:
2057 if ((c2 & 0xC0) != 0x80)
2058 return codecvt_base::error;
2059 break;
2060 }
2061 if ((c3 & 0xC0) != 0x80)
2062 return codecvt_base::error;
2063 uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
2064 | ((c2 & 0x3F) << 6)
2065 | (c3 & 0x3F));
2066 if (t > Maxcode)
2067 return codecvt_base::error;
2068 *to_nxt = static_cast<uint32_t>(t);
2069 frm_nxt += 3;
2070 }
2071 else if (c1 < 0xF5)
2072 {
2073 if (frm_end-frm_nxt < 4)
2074 return codecvt_base::partial;
2075 uint8_t c2 = frm_nxt[1];
2076 uint8_t c3 = frm_nxt[2];
2077 uint8_t c4 = frm_nxt[3];
2078 switch (c1)
2079 {
2080 case 0xF0:
2081 if (!(0x90 <= c2 && c2 <= 0xBF))
2082 return codecvt_base::error;
2083 break;
2084 case 0xF4:
2085 if ((c2 & 0xF0) != 0x80)
2086 return codecvt_base::error;
2087 break;
2088 default:
2089 if ((c2 & 0xC0) != 0x80)
2090 return codecvt_base::error;
2091 break;
2092 }
2093 if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2094 return codecvt_base::error;
2095 if (to_end-to_nxt < 2)
2096 return codecvt_base::partial;
2097 if ((((c1 & 7UL) << 18) +
2098 ((c2 & 0x3FUL) << 12) +
2099 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
2100 return codecvt_base::error;
2101 *to_nxt = static_cast<uint32_t>(
2102 0xD800
2103 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
2104 | ((c2 & 0x0F) << 2)
2105 | ((c3 & 0x30) >> 4));
2106 *++to_nxt = static_cast<uint32_t>(
2107 0xDC00
2108 | ((c3 & 0x0F) << 6)
2109 | (c4 & 0x3F));
2110 frm_nxt += 4;
2111 }
2112 else
2113 {
2114 return codecvt_base::error;
2115 }
2116 }
2117 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2118}
2119
2120static
2121int
2122utf8_to_utf16_length(const uint8_t* frm, const uint8_t* frm_end,
2123 size_t mx, unsigned long Maxcode = 0x10FFFF,
2124 codecvt_mode mode = codecvt_mode(0))
2125{
2126 const uint8_t* frm_nxt = frm;
2127 if (mode & consume_header)
2128 {
2129 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2130 frm_nxt[2] == 0xBF)
2131 frm_nxt += 3;
2132 }
2133 for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t)
2134 {
2135 uint8_t c1 = *frm_nxt;
2136 if (c1 > Maxcode)
2137 break;
2138 if (c1 < 0x80)
2139 {
2140 ++frm_nxt;
2141 }
2142 else if (c1 < 0xC2)
2143 {
2144 break;
2145 }
2146 else if (c1 < 0xE0)
2147 {
2148 if ((frm_end-frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
2149 break;
2150 uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
2151 if (t > Maxcode)
2152 break;
2153 frm_nxt += 2;
2154 }
2155 else if (c1 < 0xF0)
2156 {
2157 if (frm_end-frm_nxt < 3)
2158 break;
2159 uint8_t c2 = frm_nxt[1];
2160 uint8_t c3 = frm_nxt[2];
2161 switch (c1)
2162 {
2163 case 0xE0:
2164 if ((c2 & 0xE0) != 0xA0)
2165 return static_cast<int>(frm_nxt - frm);
2166 break;
2167 case 0xED:
2168 if ((c2 & 0xE0) != 0x80)
2169 return static_cast<int>(frm_nxt - frm);
2170 break;
2171 default:
2172 if ((c2 & 0xC0) != 0x80)
2173 return static_cast<int>(frm_nxt - frm);
2174 break;
2175 }
2176 if ((c3 & 0xC0) != 0x80)
2177 break;
2178 if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
2179 break;
2180 frm_nxt += 3;
2181 }
2182 else if (c1 < 0xF5)
2183 {
2184 if (frm_end-frm_nxt < 4 || mx-nchar16_t < 2)
2185 break;
2186 uint8_t c2 = frm_nxt[1];
2187 uint8_t c3 = frm_nxt[2];
2188 uint8_t c4 = frm_nxt[3];
2189 switch (c1)
2190 {
2191 case 0xF0:
2192 if (!(0x90 <= c2 && c2 <= 0xBF))
2193 return static_cast<int>(frm_nxt - frm);
2194 break;
2195 case 0xF4:
2196 if ((c2 & 0xF0) != 0x80)
2197 return static_cast<int>(frm_nxt - frm);
2198 break;
2199 default:
2200 if ((c2 & 0xC0) != 0x80)
2201 return static_cast<int>(frm_nxt - frm);
2202 break;
2203 }
2204 if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2205 break;
2206 if ((((c1 & 7UL) << 18) +
2207 ((c2 & 0x3FUL) << 12) +
2208 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
2209 break;
2210 ++nchar16_t;
2211 frm_nxt += 4;
2212 }
2213 else
2214 {
2215 break;
2216 }
2217 }
2218 return static_cast<int>(frm_nxt - frm);
2219}
2220
2221static
2222codecvt_base::result
2223ucs4_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
2224 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2225 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2226{
2227 frm_nxt = frm;
2228 to_nxt = to;
2229 if (mode & generate_header)
2230 {
2231 if (to_end-to_nxt < 3)
2232 return codecvt_base::partial;
2233 *to_nxt++ = static_cast<uint8_t>(0xEF);
2234 *to_nxt++ = static_cast<uint8_t>(0xBB);
2235 *to_nxt++ = static_cast<uint8_t>(0xBF);
2236 }
2237 for (; frm_nxt < frm_end; ++frm_nxt)
2238 {
2239 uint32_t wc = *frm_nxt;
2240 if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
2241 return codecvt_base::error;
2242 if (wc < 0x000080)
2243 {
2244 if (to_end-to_nxt < 1)
2245 return codecvt_base::partial;
2246 *to_nxt++ = static_cast<uint8_t>(wc);
2247 }
2248 else if (wc < 0x000800)
2249 {
2250 if (to_end-to_nxt < 2)
2251 return codecvt_base::partial;
2252 *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
2253 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2254 }
2255 else if (wc < 0x010000)
2256 {
2257 if (to_end-to_nxt < 3)
2258 return codecvt_base::partial;
2259 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12));
2260 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
2261 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F));
2262 }
2263 else // if (wc < 0x110000)
2264 {
2265 if (to_end-to_nxt < 4)
2266 return codecvt_base::partial;
2267 *to_nxt++ = static_cast<uint8_t>(0xF0 | (wc >> 18));
2268 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
2269 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
2270 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x00003F));
2271 }
2272 }
2273 return codecvt_base::ok;
2274}
2275
2276static
2277codecvt_base::result
2278utf8_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2279 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2280 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2281{
2282 frm_nxt = frm;
2283 to_nxt = to;
2284 if (mode & consume_header)
2285 {
2286 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2287 frm_nxt[2] == 0xBF)
2288 frm_nxt += 3;
2289 }
2290 for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2291 {
2292 uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2293 if (c1 < 0x80)
2294 {
2295 if (c1 > Maxcode)
2296 return codecvt_base::error;
2297 *to_nxt = static_cast<uint32_t>(c1);
2298 ++frm_nxt;
2299 }
2300 else if (c1 < 0xC2)
2301 {
2302 return codecvt_base::error;
2303 }
2304 else if (c1 < 0xE0)
2305 {
2306 if (frm_end-frm_nxt < 2)
2307 return codecvt_base::partial;
2308 uint8_t c2 = frm_nxt[1];
2309 if ((c2 & 0xC0) != 0x80)
2310 return codecvt_base::error;
2311 uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6)
2312 | (c2 & 0x3F));
2313 if (t > Maxcode)
2314 return codecvt_base::error;
2315 *to_nxt = t;
2316 frm_nxt += 2;
2317 }
2318 else if (c1 < 0xF0)
2319 {
2320 if (frm_end-frm_nxt < 3)
2321 return codecvt_base::partial;
2322 uint8_t c2 = frm_nxt[1];
2323 uint8_t c3 = frm_nxt[2];
2324 switch (c1)
2325 {
2326 case 0xE0:
2327 if ((c2 & 0xE0) != 0xA0)
2328 return codecvt_base::error;
2329 break;
2330 case 0xED:
2331 if ((c2 & 0xE0) != 0x80)
2332 return codecvt_base::error;
2333 break;
2334 default:
2335 if ((c2 & 0xC0) != 0x80)
2336 return codecvt_base::error;
2337 break;
2338 }
2339 if ((c3 & 0xC0) != 0x80)
2340 return codecvt_base::error;
2341 uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12)
2342 | ((c2 & 0x3F) << 6)
2343 | (c3 & 0x3F));
2344 if (t > Maxcode)
2345 return codecvt_base::error;
2346 *to_nxt = t;
2347 frm_nxt += 3;
2348 }
2349 else if (c1 < 0xF5)
2350 {
2351 if (frm_end-frm_nxt < 4)
2352 return codecvt_base::partial;
2353 uint8_t c2 = frm_nxt[1];
2354 uint8_t c3 = frm_nxt[2];
2355 uint8_t c4 = frm_nxt[3];
2356 switch (c1)
2357 {
2358 case 0xF0:
2359 if (!(0x90 <= c2 && c2 <= 0xBF))
2360 return codecvt_base::error;
2361 break;
2362 case 0xF4:
2363 if ((c2 & 0xF0) != 0x80)
2364 return codecvt_base::error;
2365 break;
2366 default:
2367 if ((c2 & 0xC0) != 0x80)
2368 return codecvt_base::error;
2369 break;
2370 }
2371 if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2372 return codecvt_base::error;
2373 uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18)
2374 | ((c2 & 0x3F) << 12)
2375 | ((c3 & 0x3F) << 6)
2376 | (c4 & 0x3F));
2377 if (t > Maxcode)
2378 return codecvt_base::error;
2379 *to_nxt = t;
2380 frm_nxt += 4;
2381 }
2382 else
2383 {
2384 return codecvt_base::error;
2385 }
2386 }
2387 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2388}
2389
2390static
2391int
2392utf8_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
2393 size_t mx, unsigned long Maxcode = 0x10FFFF,
2394 codecvt_mode mode = codecvt_mode(0))
2395{
2396 const uint8_t* frm_nxt = frm;
2397 if (mode & consume_header)
2398 {
2399 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2400 frm_nxt[2] == 0xBF)
2401 frm_nxt += 3;
2402 }
2403 for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
2404 {
2405 uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2406 if (c1 < 0x80)
2407 {
2408 if (c1 > Maxcode)
2409 break;
2410 ++frm_nxt;
2411 }
2412 else if (c1 < 0xC2)
2413 {
2414 break;
2415 }
2416 else if (c1 < 0xE0)
2417 {
2418 if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
2419 break;
2420 if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
2421 break;
2422 frm_nxt += 2;
2423 }
2424 else if (c1 < 0xF0)
2425 {
2426 if (frm_end-frm_nxt < 3)
2427 break;
2428 uint8_t c2 = frm_nxt[1];
2429 uint8_t c3 = frm_nxt[2];
2430 switch (c1)
2431 {
2432 case 0xE0:
2433 if ((c2 & 0xE0) != 0xA0)
2434 return static_cast<int>(frm_nxt - frm);
2435 break;
2436 case 0xED:
2437 if ((c2 & 0xE0) != 0x80)
2438 return static_cast<int>(frm_nxt - frm);
2439 break;
2440 default:
2441 if ((c2 & 0xC0) != 0x80)
2442 return static_cast<int>(frm_nxt - frm);
2443 break;
2444 }
2445 if ((c3 & 0xC0) != 0x80)
2446 break;
2447 if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
2448 break;
2449 frm_nxt += 3;
2450 }
2451 else if (c1 < 0xF5)
2452 {
2453 if (frm_end-frm_nxt < 4)
2454 break;
2455 uint8_t c2 = frm_nxt[1];
2456 uint8_t c3 = frm_nxt[2];
2457 uint8_t c4 = frm_nxt[3];
2458 switch (c1)
2459 {
2460 case 0xF0:
2461 if (!(0x90 <= c2 && c2 <= 0xBF))
2462 return static_cast<int>(frm_nxt - frm);
2463 break;
2464 case 0xF4:
2465 if ((c2 & 0xF0) != 0x80)
2466 return static_cast<int>(frm_nxt - frm);
2467 break;
2468 default:
2469 if ((c2 & 0xC0) != 0x80)
2470 return static_cast<int>(frm_nxt - frm);
2471 break;
2472 }
2473 if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2474 break;
2475 if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) |
2476 ((c3 & 0x3Fu) << 6) | (c4 & 0x3Fu)) > Maxcode)
2477 break;
2478 frm_nxt += 4;
2479 }
2480 else
2481 {
2482 break;
2483 }
2484 }
2485 return static_cast<int>(frm_nxt - frm);
2486}
2487
2488static
2489codecvt_base::result
2490ucs2_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
2491 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2492 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2493{
2494 frm_nxt = frm;
2495 to_nxt = to;
2496 if (mode & generate_header)
2497 {
2498 if (to_end-to_nxt < 3)
2499 return codecvt_base::partial;
2500 *to_nxt++ = static_cast<uint8_t>(0xEF);
2501 *to_nxt++ = static_cast<uint8_t>(0xBB);
2502 *to_nxt++ = static_cast<uint8_t>(0xBF);
2503 }
2504 for (; frm_nxt < frm_end; ++frm_nxt)
2505 {
2506 uint16_t wc = *frm_nxt;
2507 if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
2508 return codecvt_base::error;
2509 if (wc < 0x0080)
2510 {
2511 if (to_end-to_nxt < 1)
2512 return codecvt_base::partial;
2513 *to_nxt++ = static_cast<uint8_t>(wc);
2514 }
2515 else if (wc < 0x0800)
2516 {
2517 if (to_end-to_nxt < 2)
2518 return codecvt_base::partial;
2519 *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
2520 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2521 }
2522 else // if (wc <= 0xFFFF)
2523 {
2524 if (to_end-to_nxt < 3)
2525 return codecvt_base::partial;
2526 *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12));
2527 *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
2528 *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F));
2529 }
2530 }
2531 return codecvt_base::ok;
2532}
2533
2534static
2535codecvt_base::result
2536utf8_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2537 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
2538 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2539{
2540 frm_nxt = frm;
2541 to_nxt = to;
2542 if (mode & consume_header)
2543 {
2544 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2545 frm_nxt[2] == 0xBF)
2546 frm_nxt += 3;
2547 }
2548 for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2549 {
2550 uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2551 if (c1 < 0x80)
2552 {
2553 if (c1 > Maxcode)
2554 return codecvt_base::error;
2555 *to_nxt = static_cast<uint16_t>(c1);
2556 ++frm_nxt;
2557 }
2558 else if (c1 < 0xC2)
2559 {
2560 return codecvt_base::error;
2561 }
2562 else if (c1 < 0xE0)
2563 {
2564 if (frm_end-frm_nxt < 2)
2565 return codecvt_base::partial;
2566 uint8_t c2 = frm_nxt[1];
2567 if ((c2 & 0xC0) != 0x80)
2568 return codecvt_base::error;
2569 uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6)
2570 | (c2 & 0x3F));
2571 if (t > Maxcode)
2572 return codecvt_base::error;
2573 *to_nxt = t;
2574 frm_nxt += 2;
2575 }
2576 else if (c1 < 0xF0)
2577 {
2578 if (frm_end-frm_nxt < 3)
2579 return codecvt_base::partial;
2580 uint8_t c2 = frm_nxt[1];
2581 uint8_t c3 = frm_nxt[2];
2582 switch (c1)
2583 {
2584 case 0xE0:
2585 if ((c2 & 0xE0) != 0xA0)
2586 return codecvt_base::error;
2587 break;
2588 case 0xED:
2589 if ((c2 & 0xE0) != 0x80)
2590 return codecvt_base::error;
2591 break;
2592 default:
2593 if ((c2 & 0xC0) != 0x80)
2594 return codecvt_base::error;
2595 break;
2596 }
2597 if ((c3 & 0xC0) != 0x80)
2598 return codecvt_base::error;
2599 uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
2600 | ((c2 & 0x3F) << 6)
2601 | (c3 & 0x3F));
2602 if (t > Maxcode)
2603 return codecvt_base::error;
2604 *to_nxt = t;
2605 frm_nxt += 3;
2606 }
2607 else
2608 {
2609 return codecvt_base::error;
2610 }
2611 }
2612 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2613}
2614
2615static
2616int
2617utf8_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
2618 size_t mx, unsigned long Maxcode = 0x10FFFF,
2619 codecvt_mode mode = codecvt_mode(0))
2620{
2621 const uint8_t* frm_nxt = frm;
2622 if (mode & consume_header)
2623 {
2624 if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2625 frm_nxt[2] == 0xBF)
2626 frm_nxt += 3;
2627 }
2628 for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
2629 {
2630 uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2631 if (c1 < 0x80)
2632 {
2633 if (c1 > Maxcode)
2634 break;
2635 ++frm_nxt;
2636 }
2637 else if (c1 < 0xC2)
2638 {
2639 break;
2640 }
2641 else if (c1 < 0xE0)
2642 {
2643 if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
2644 break;
2645 if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
2646 break;
2647 frm_nxt += 2;
2648 }
2649 else if (c1 < 0xF0)
2650 {
2651 if (frm_end-frm_nxt < 3)
2652 break;
2653 uint8_t c2 = frm_nxt[1];
2654 uint8_t c3 = frm_nxt[2];
2655 switch (c1)
2656 {
2657 case 0xE0:
2658 if ((c2 & 0xE0) != 0xA0)
2659 return static_cast<int>(frm_nxt - frm);
2660 break;
2661 case 0xED:
2662 if ((c2 & 0xE0) != 0x80)
2663 return static_cast<int>(frm_nxt - frm);
2664 break;
2665 default:
2666 if ((c2 & 0xC0) != 0x80)
2667 return static_cast<int>(frm_nxt - frm);
2668 break;
2669 }
2670 if ((c3 & 0xC0) != 0x80)
2671 break;
2672 if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
2673 break;
2674 frm_nxt += 3;
2675 }
2676 else
2677 {
2678 break;
2679 }
2680 }
2681 return static_cast<int>(frm_nxt - frm);
2682}
2683
2684static
2685codecvt_base::result
2686ucs4_to_utf16be(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
2687 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2688 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2689{
2690 frm_nxt = frm;
2691 to_nxt = to;
2692 if (mode & generate_header)
2693 {
2694 if (to_end-to_nxt < 2)
2695 return codecvt_base::partial;
2696 *to_nxt++ = static_cast<uint8_t>(0xFE);
2697 *to_nxt++ = static_cast<uint8_t>(0xFF);
2698 }
2699 for (; frm_nxt < frm_end; ++frm_nxt)
2700 {
2701 uint32_t wc = *frm_nxt;
2702 if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
2703 return codecvt_base::error;
2704 if (wc < 0x010000)
2705 {
2706 if (to_end-to_nxt < 2)
2707 return codecvt_base::partial;
2708 *to_nxt++ = static_cast<uint8_t>(wc >> 8);
2709 *to_nxt++ = static_cast<uint8_t>(wc);
2710 }
2711 else
2712 {
2713 if (to_end-to_nxt < 4)
2714 return codecvt_base::partial;
2715 uint16_t t = static_cast<uint16_t>(
2716 0xD800
2717 | ((((wc & 0x1F0000) >> 16) - 1) << 6)
2718 | ((wc & 0x00FC00) >> 10));
2719 *to_nxt++ = static_cast<uint8_t>(t >> 8);
2720 *to_nxt++ = static_cast<uint8_t>(t);
2721 t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
2722 *to_nxt++ = static_cast<uint8_t>(t >> 8);
2723 *to_nxt++ = static_cast<uint8_t>(t);
2724 }
2725 }
2726 return codecvt_base::ok;
2727}
2728
2729static
2730codecvt_base::result
2731utf16be_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2732 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2733 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2734{
2735 frm_nxt = frm;
2736 to_nxt = to;
2737 if (mode & consume_header)
2738 {
2739 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
2740 frm_nxt += 2;
2741 }
2742 for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
2743 {
2744 uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
2745 if ((c1 & 0xFC00) == 0xDC00)
2746 return codecvt_base::error;
2747 if ((c1 & 0xFC00) != 0xD800)
2748 {
2749 if (c1 > Maxcode)
2750 return codecvt_base::error;
2751 *to_nxt = static_cast<uint32_t>(c1);
2752 frm_nxt += 2;
2753 }
2754 else
2755 {
2756 if (frm_end-frm_nxt < 4)
2757 return codecvt_base::partial;
2758 uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
2759 if ((c2 & 0xFC00) != 0xDC00)
2760 return codecvt_base::error;
2761 uint32_t t = static_cast<uint32_t>(
2762 ((((c1 & 0x03C0) >> 6) + 1) << 16)
2763 | ((c1 & 0x003F) << 10)
2764 | (c2 & 0x03FF));
2765 if (t > Maxcode)
2766 return codecvt_base::error;
2767 *to_nxt = t;
2768 frm_nxt += 4;
2769 }
2770 }
2771 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2772}
2773
2774static
2775int
2776utf16be_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
2777 size_t mx, unsigned long Maxcode = 0x10FFFF,
2778 codecvt_mode mode = codecvt_mode(0))
2779{
2780 const uint8_t* frm_nxt = frm;
2781 if (mode & consume_header)
2782 {
2783 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
2784 frm_nxt += 2;
2785 }
2786 for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
2787 {
2788 uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
2789 if ((c1 & 0xFC00) == 0xDC00)
2790 break;
2791 if ((c1 & 0xFC00) != 0xD800)
2792 {
2793 if (c1 > Maxcode)
2794 break;
2795 frm_nxt += 2;
2796 }
2797 else
2798 {
2799 if (frm_end-frm_nxt < 4)
2800 break;
2801 uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
2802 if ((c2 & 0xFC00) != 0xDC00)
2803 break;
2804 uint32_t t = static_cast<uint32_t>(
2805 ((((c1 & 0x03C0) >> 6) + 1) << 16)
2806 | ((c1 & 0x003F) << 10)
2807 | (c2 & 0x03FF));
2808 if (t > Maxcode)
2809 break;
2810 frm_nxt += 4;
2811 }
2812 }
2813 return static_cast<int>(frm_nxt - frm);
2814}
2815
2816static
2817codecvt_base::result
2818ucs4_to_utf16le(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
2819 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2820 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2821{
2822 frm_nxt = frm;
2823 to_nxt = to;
2824 if (mode & generate_header)
2825 {
2826 if (to_end - to_nxt < 2)
2827 return codecvt_base::partial;
2828 *to_nxt++ = static_cast<uint8_t>(0xFF);
2829 *to_nxt++ = static_cast<uint8_t>(0xFE);
2830 }
2831 for (; frm_nxt < frm_end; ++frm_nxt)
2832 {
2833 uint32_t wc = *frm_nxt;
2834 if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
2835 return codecvt_base::error;
2836 if (wc < 0x010000)
2837 {
2838 if (to_end-to_nxt < 2)
2839 return codecvt_base::partial;
2840 *to_nxt++ = static_cast<uint8_t>(wc);
2841 *to_nxt++ = static_cast<uint8_t>(wc >> 8);
2842 }
2843 else
2844 {
2845 if (to_end-to_nxt < 4)
2846 return codecvt_base::partial;
2847 uint16_t t = static_cast<uint16_t>(
2848 0xD800
2849 | ((((wc & 0x1F0000) >> 16) - 1) << 6)
2850 | ((wc & 0x00FC00) >> 10));
2851 *to_nxt++ = static_cast<uint8_t>(t);
2852 *to_nxt++ = static_cast<uint8_t>(t >> 8);
2853 t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
2854 *to_nxt++ = static_cast<uint8_t>(t);
2855 *to_nxt++ = static_cast<uint8_t>(t >> 8);
2856 }
2857 }
2858 return codecvt_base::ok;
2859}
2860
2861static
2862codecvt_base::result
2863utf16le_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2864 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2865 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2866{
2867 frm_nxt = frm;
2868 to_nxt = to;
2869 if (mode & consume_header)
2870 {
2871 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
2872 frm_nxt += 2;
2873 }
2874 for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
2875 {
2876 uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
2877 if ((c1 & 0xFC00) == 0xDC00)
2878 return codecvt_base::error;
2879 if ((c1 & 0xFC00) != 0xD800)
2880 {
2881 if (c1 > Maxcode)
2882 return codecvt_base::error;
2883 *to_nxt = static_cast<uint32_t>(c1);
2884 frm_nxt += 2;
2885 }
2886 else
2887 {
2888 if (frm_end-frm_nxt < 4)
2889 return codecvt_base::partial;
2890 uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
2891 if ((c2 & 0xFC00) != 0xDC00)
2892 return codecvt_base::error;
2893 uint32_t t = static_cast<uint32_t>(
2894 ((((c1 & 0x03C0) >> 6) + 1) << 16)
2895 | ((c1 & 0x003F) << 10)
2896 | (c2 & 0x03FF));
2897 if (t > Maxcode)
2898 return codecvt_base::error;
2899 *to_nxt = t;
2900 frm_nxt += 4;
2901 }
2902 }
2903 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2904}
2905
2906static
2907int
2908utf16le_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
2909 size_t mx, unsigned long Maxcode = 0x10FFFF,
2910 codecvt_mode mode = codecvt_mode(0))
2911{
2912 const uint8_t* frm_nxt = frm;
2913 if (mode & consume_header)
2914 {
2915 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
2916 frm_nxt += 2;
2917 }
2918 for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
2919 {
2920 uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
2921 if ((c1 & 0xFC00) == 0xDC00)
2922 break;
2923 if ((c1 & 0xFC00) != 0xD800)
2924 {
2925 if (c1 > Maxcode)
2926 break;
2927 frm_nxt += 2;
2928 }
2929 else
2930 {
2931 if (frm_end-frm_nxt < 4)
2932 break;
2933 uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
2934 if ((c2 & 0xFC00) != 0xDC00)
2935 break;
2936 uint32_t t = static_cast<uint32_t>(
2937 ((((c1 & 0x03C0) >> 6) + 1) << 16)
2938 | ((c1 & 0x003F) << 10)
2939 | (c2 & 0x03FF));
2940 if (t > Maxcode)
2941 break;
2942 frm_nxt += 4;
2943 }
2944 }
2945 return static_cast<int>(frm_nxt - frm);
2946}
2947
2948static
2949codecvt_base::result
2950ucs2_to_utf16be(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
2951 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2952 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2953{
2954 frm_nxt = frm;
2955 to_nxt = to;
2956 if (mode & generate_header)
2957 {
2958 if (to_end-to_nxt < 2)
2959 return codecvt_base::partial;
2960 *to_nxt++ = static_cast<uint8_t>(0xFE);
2961 *to_nxt++ = static_cast<uint8_t>(0xFF);
2962 }
2963 for (; frm_nxt < frm_end; ++frm_nxt)
2964 {
2965 uint16_t wc = *frm_nxt;
2966 if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
2967 return codecvt_base::error;
2968 if (to_end-to_nxt < 2)
2969 return codecvt_base::partial;
2970 *to_nxt++ = static_cast<uint8_t>(wc >> 8);
2971 *to_nxt++ = static_cast<uint8_t>(wc);
2972 }
2973 return codecvt_base::ok;
2974}
2975
2976static
2977codecvt_base::result
2978utf16be_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2979 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
2980 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2981{
2982 frm_nxt = frm;
2983 to_nxt = to;
2984 if (mode & consume_header)
2985 {
2986 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
2987 frm_nxt += 2;
2988 }
2989 for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
2990 {
2991 uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
2992 if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
2993 return codecvt_base::error;
2994 *to_nxt = c1;
2995 frm_nxt += 2;
2996 }
2997 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2998}
2999
3000static
3001int
3002utf16be_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
3003 size_t mx, unsigned long Maxcode = 0x10FFFF,
3004 codecvt_mode mode = codecvt_mode(0))
3005{
3006 const uint8_t* frm_nxt = frm;
3007 if (mode & consume_header)
3008 {
3009 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
3010 frm_nxt += 2;
3011 }
3012 for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
3013 {
3014 uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
3015 if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
3016 break;
3017 frm_nxt += 2;
3018 }
3019 return static_cast<int>(frm_nxt - frm);
3020}
3021
3022static
3023codecvt_base::result
3024ucs2_to_utf16le(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
3025 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
3026 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
3027{
3028 frm_nxt = frm;
3029 to_nxt = to;
3030 if (mode & generate_header)
3031 {
3032 if (to_end-to_nxt < 2)
3033 return codecvt_base::partial;
3034 *to_nxt++ = static_cast<uint8_t>(0xFF);
3035 *to_nxt++ = static_cast<uint8_t>(0xFE);
3036 }
3037 for (; frm_nxt < frm_end; ++frm_nxt)
3038 {
3039 uint16_t wc = *frm_nxt;
3040 if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
3041 return codecvt_base::error;
3042 if (to_end-to_nxt < 2)
3043 return codecvt_base::partial;
3044 *to_nxt++ = static_cast<uint8_t>(wc);
3045 *to_nxt++ = static_cast<uint8_t>(wc >> 8);
3046 }
3047 return codecvt_base::ok;
3048}
3049
3050static
3051codecvt_base::result
3052utf16le_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
3053 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
3054 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
3055{
3056 frm_nxt = frm;
3057 to_nxt = to;
3058 if (mode & consume_header)
3059 {
3060 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
3061 frm_nxt += 2;
3062 }
3063 for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
3064 {
3065 uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
3066 if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
3067 return codecvt_base::error;
3068 *to_nxt = c1;
3069 frm_nxt += 2;
3070 }
3071 return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
3072}
3073
3074static
3075int
3076utf16le_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
3077 size_t mx, unsigned long Maxcode = 0x10FFFF,
3078 codecvt_mode mode = codecvt_mode(0))
3079{
3080 const uint8_t* frm_nxt = frm;
3081 frm_nxt = frm;
3082 if (mode & consume_header)
3083 {
3084 if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
3085 frm_nxt += 2;
3086 }
3087 for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
3088 {
3089 uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
3090 if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
3091 break;
3092 frm_nxt += 2;
3093 }
3094 return static_cast<int>(frm_nxt - frm);
3095}
3096
3097// template <> class codecvt<char16_t, char, mbstate_t>
3098
3099locale::id codecvt<char16_t, char, mbstate_t>::id;
3100
3101codecvt<char16_t, char, mbstate_t>::~codecvt()
3102{
3103}
3104
3105codecvt<char16_t, char, mbstate_t>::result
3106codecvt<char16_t, char, mbstate_t>::do_out(state_type&,
3107 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3108 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3109{
3110 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3111 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3112 const uint16_t* _frm_nxt = _frm;
3113 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3114 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3115 uint8_t* _to_nxt = _to;
3116 result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3117 frm_nxt = frm + (_frm_nxt - _frm);
3118 to_nxt = to + (_to_nxt - _to);
3119 return r;
3120}
3121
3122codecvt<char16_t, char, mbstate_t>::result
3123codecvt<char16_t, char, mbstate_t>::do_in(state_type&,
3124 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3125 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3126{
3127 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3128 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3129 const uint8_t* _frm_nxt = _frm;
3130 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3131 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3132 uint16_t* _to_nxt = _to;
3133 result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3134 frm_nxt = frm + (_frm_nxt - _frm);
3135 to_nxt = to + (_to_nxt - _to);
3136 return r;
3137}
3138
3139codecvt<char16_t, char, mbstate_t>::result
3140codecvt<char16_t, char, mbstate_t>::do_unshift(state_type&,
3141 extern_type* to, extern_type*, extern_type*& to_nxt) const
3142{
3143 to_nxt = to;
3144 return noconv;
3145}
3146
3147int
3148codecvt<char16_t, char, mbstate_t>::do_encoding() const _NOEXCEPT
3149{
3150 return 0;
3151}
3152
3153bool
3154codecvt<char16_t, char, mbstate_t>::do_always_noconv() const _NOEXCEPT
3155{
3156 return false;
3157}
3158
3159int
3160codecvt<char16_t, char, mbstate_t>::do_length(state_type&,
3161 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3162{
3163 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3164 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3165 return utf8_to_utf16_length(_frm, _frm_end, mx);
3166}
3167
3168int
3169codecvt<char16_t, char, mbstate_t>::do_max_length() const _NOEXCEPT
3170{
3171 return 4;
3172}
3173
3174// template <> class codecvt<char32_t, char, mbstate_t>
3175
3176locale::id codecvt<char32_t, char, mbstate_t>::id;
3177
3178codecvt<char32_t, char, mbstate_t>::~codecvt()
3179{
3180}
3181
3182codecvt<char32_t, char, mbstate_t>::result
3183codecvt<char32_t, char, mbstate_t>::do_out(state_type&,
3184 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3185 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3186{
3187 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3188 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3189 const uint32_t* _frm_nxt = _frm;
3190 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3191 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3192 uint8_t* _to_nxt = _to;
3193 result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3194 frm_nxt = frm + (_frm_nxt - _frm);
3195 to_nxt = to + (_to_nxt - _to);
3196 return r;
3197}
3198
3199codecvt<char32_t, char, mbstate_t>::result
3200codecvt<char32_t, char, mbstate_t>::do_in(state_type&,
3201 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3202 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3203{
3204 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3205 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3206 const uint8_t* _frm_nxt = _frm;
3207 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3208 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3209 uint32_t* _to_nxt = _to;
3210 result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3211 frm_nxt = frm + (_frm_nxt - _frm);
3212 to_nxt = to + (_to_nxt - _to);
3213 return r;
3214}
3215
3216codecvt<char32_t, char, mbstate_t>::result
3217codecvt<char32_t, char, mbstate_t>::do_unshift(state_type&,
3218 extern_type* to, extern_type*, extern_type*& to_nxt) const
3219{
3220 to_nxt = to;
3221 return noconv;
3222}
3223
3224int
3225codecvt<char32_t, char, mbstate_t>::do_encoding() const _NOEXCEPT
3226{
3227 return 0;
3228}
3229
3230bool
3231codecvt<char32_t, char, mbstate_t>::do_always_noconv() const _NOEXCEPT
3232{
3233 return false;
3234}
3235
3236int
3237codecvt<char32_t, char, mbstate_t>::do_length(state_type&,
3238 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3239{
3240 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3241 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3242 return utf8_to_ucs4_length(_frm, _frm_end, mx);
3243}
3244
3245int
3246codecvt<char32_t, char, mbstate_t>::do_max_length() const _NOEXCEPT
3247{
3248 return 4;
3249}
3250
3251// __codecvt_utf8<wchar_t>
3252
3253__codecvt_utf8<wchar_t>::result
3254__codecvt_utf8<wchar_t>::do_out(state_type&,
3255 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3256 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3257{
3258#if defined(_LIBCPP_SHORT_WCHAR)
3259 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3260 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3261 const uint16_t* _frm_nxt = _frm;
3262#else
3263 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3264 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3265 const uint32_t* _frm_nxt = _frm;
3266#endif
3267 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3268 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3269 uint8_t* _to_nxt = _to;
3270#if defined(_LIBCPP_SHORT_WCHAR)
3271 result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3272 _Maxcode_, _Mode_);
3273#else
3274 result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3275 _Maxcode_, _Mode_);
3276#endif
3277 frm_nxt = frm + (_frm_nxt - _frm);
3278 to_nxt = to + (_to_nxt - _to);
3279 return r;
3280}
3281
3282__codecvt_utf8<wchar_t>::result
3283__codecvt_utf8<wchar_t>::do_in(state_type&,
3284 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3285 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3286{
3287 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3288 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3289 const uint8_t* _frm_nxt = _frm;
3290#if defined(_LIBCPP_SHORT_WCHAR)
3291 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3292 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3293 uint16_t* _to_nxt = _to;
3294 result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3295 _Maxcode_, _Mode_);
3296#else
3297 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3298 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3299 uint32_t* _to_nxt = _to;
3300 result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3301 _Maxcode_, _Mode_);
3302#endif
3303 frm_nxt = frm + (_frm_nxt - _frm);
3304 to_nxt = to + (_to_nxt - _to);
3305 return r;
3306}
3307
3308__codecvt_utf8<wchar_t>::result
3309__codecvt_utf8<wchar_t>::do_unshift(state_type&,
3310 extern_type* to, extern_type*, extern_type*& to_nxt) const
3311{
3312 to_nxt = to;
3313 return noconv;
3314}
3315
3316int
3317__codecvt_utf8<wchar_t>::do_encoding() const _NOEXCEPT
3318{
3319 return 0;
3320}
3321
3322bool
3323__codecvt_utf8<wchar_t>::do_always_noconv() const _NOEXCEPT
3324{
3325 return false;
3326}
3327
3328int
3329__codecvt_utf8<wchar_t>::do_length(state_type&,
3330 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3331{
3332 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3333 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3334 return utf8_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3335}
3336
3337int
3338__codecvt_utf8<wchar_t>::do_max_length() const _NOEXCEPT
3339{
3340 if (_Mode_ & consume_header)
3341 return 7;
3342 return 4;
3343}
3344
3345// __codecvt_utf8<char16_t>
3346
3347__codecvt_utf8<char16_t>::result
3348__codecvt_utf8<char16_t>::do_out(state_type&,
3349 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3350 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3351{
3352 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3353 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3354 const uint16_t* _frm_nxt = _frm;
3355 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3356 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3357 uint8_t* _to_nxt = _to;
3358 result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3359 _Maxcode_, _Mode_);
3360 frm_nxt = frm + (_frm_nxt - _frm);
3361 to_nxt = to + (_to_nxt - _to);
3362 return r;
3363}
3364
3365__codecvt_utf8<char16_t>::result
3366__codecvt_utf8<char16_t>::do_in(state_type&,
3367 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3368 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3369{
3370 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3371 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3372 const uint8_t* _frm_nxt = _frm;
3373 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3374 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3375 uint16_t* _to_nxt = _to;
3376 result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3377 _Maxcode_, _Mode_);
3378 frm_nxt = frm + (_frm_nxt - _frm);
3379 to_nxt = to + (_to_nxt - _to);
3380 return r;
3381}
3382
3383__codecvt_utf8<char16_t>::result
3384__codecvt_utf8<char16_t>::do_unshift(state_type&,
3385 extern_type* to, extern_type*, extern_type*& to_nxt) const
3386{
3387 to_nxt = to;
3388 return noconv;
3389}
3390
3391int
3392__codecvt_utf8<char16_t>::do_encoding() const _NOEXCEPT
3393{
3394 return 0;
3395}
3396
3397bool
3398__codecvt_utf8<char16_t>::do_always_noconv() const _NOEXCEPT
3399{
3400 return false;
3401}
3402
3403int
3404__codecvt_utf8<char16_t>::do_length(state_type&,
3405 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3406{
3407 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3408 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3409 return utf8_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3410}
3411
3412int
3413__codecvt_utf8<char16_t>::do_max_length() const _NOEXCEPT
3414{
3415 if (_Mode_ & consume_header)
3416 return 6;
3417 return 3;
3418}
3419
3420// __codecvt_utf8<char32_t>
3421
3422__codecvt_utf8<char32_t>::result
3423__codecvt_utf8<char32_t>::do_out(state_type&,
3424 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3425 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3426{
3427 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3428 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3429 const uint32_t* _frm_nxt = _frm;
3430 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3431 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3432 uint8_t* _to_nxt = _to;
3433 result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3434 _Maxcode_, _Mode_);
3435 frm_nxt = frm + (_frm_nxt - _frm);
3436 to_nxt = to + (_to_nxt - _to);
3437 return r;
3438}
3439
3440__codecvt_utf8<char32_t>::result
3441__codecvt_utf8<char32_t>::do_in(state_type&,
3442 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3443 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3444{
3445 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3446 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3447 const uint8_t* _frm_nxt = _frm;
3448 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3449 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3450 uint32_t* _to_nxt = _to;
3451 result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3452 _Maxcode_, _Mode_);
3453 frm_nxt = frm + (_frm_nxt - _frm);
3454 to_nxt = to + (_to_nxt - _to);
3455 return r;
3456}
3457
3458__codecvt_utf8<char32_t>::result
3459__codecvt_utf8<char32_t>::do_unshift(state_type&,
3460 extern_type* to, extern_type*, extern_type*& to_nxt) const
3461{
3462 to_nxt = to;
3463 return noconv;
3464}
3465
3466int
3467__codecvt_utf8<char32_t>::do_encoding() const _NOEXCEPT
3468{
3469 return 0;
3470}
3471
3472bool
3473__codecvt_utf8<char32_t>::do_always_noconv() const _NOEXCEPT
3474{
3475 return false;
3476}
3477
3478int
3479__codecvt_utf8<char32_t>::do_length(state_type&,
3480 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3481{
3482 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3483 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3484 return utf8_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3485}
3486
3487int
3488__codecvt_utf8<char32_t>::do_max_length() const _NOEXCEPT
3489{
3490 if (_Mode_ & consume_header)
3491 return 7;
3492 return 4;
3493}
3494
3495// __codecvt_utf16<wchar_t, false>
3496
3497__codecvt_utf16<wchar_t, false>::result
3498__codecvt_utf16<wchar_t, false>::do_out(state_type&,
3499 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3500 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3501{
3502 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3503 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3504 const uint32_t* _frm_nxt = _frm;
3505 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3506 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3507 uint8_t* _to_nxt = _to;
3508 result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3509 _Maxcode_, _Mode_);
3510 frm_nxt = frm + (_frm_nxt - _frm);
3511 to_nxt = to + (_to_nxt - _to);
3512 return r;
3513}
3514
3515__codecvt_utf16<wchar_t, false>::result
3516__codecvt_utf16<wchar_t, false>::do_in(state_type&,
3517 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3518 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3519{
3520 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3521 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3522 const uint8_t* _frm_nxt = _frm;
3523 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3524 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3525 uint32_t* _to_nxt = _to;
3526 result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3527 _Maxcode_, _Mode_);
3528 frm_nxt = frm + (_frm_nxt - _frm);
3529 to_nxt = to + (_to_nxt - _to);
3530 return r;
3531}
3532
3533__codecvt_utf16<wchar_t, false>::result
3534__codecvt_utf16<wchar_t, false>::do_unshift(state_type&,
3535 extern_type* to, extern_type*, extern_type*& to_nxt) const
3536{
3537 to_nxt = to;
3538 return noconv;
3539}
3540
3541int
3542__codecvt_utf16<wchar_t, false>::do_encoding() const _NOEXCEPT
3543{
3544 return 0;
3545}
3546
3547bool
3548__codecvt_utf16<wchar_t, false>::do_always_noconv() const _NOEXCEPT
3549{
3550 return false;
3551}
3552
3553int
3554__codecvt_utf16<wchar_t, false>::do_length(state_type&,
3555 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3556{
3557 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3558 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3559 return utf16be_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3560}
3561
3562int
3563__codecvt_utf16<wchar_t, false>::do_max_length() const _NOEXCEPT
3564{
3565 if (_Mode_ & consume_header)
3566 return 6;
3567 return 4;
3568}
3569
3570// __codecvt_utf16<wchar_t, true>
3571
3572__codecvt_utf16<wchar_t, true>::result
3573__codecvt_utf16<wchar_t, true>::do_out(state_type&,
3574 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3575 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3576{
3577 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3578 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3579 const uint32_t* _frm_nxt = _frm;
3580 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3581 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3582 uint8_t* _to_nxt = _to;
3583 result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3584 _Maxcode_, _Mode_);
3585 frm_nxt = frm + (_frm_nxt - _frm);
3586 to_nxt = to + (_to_nxt - _to);
3587 return r;
3588}
3589
3590__codecvt_utf16<wchar_t, true>::result
3591__codecvt_utf16<wchar_t, true>::do_in(state_type&,
3592 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3593 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3594{
3595 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3596 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3597 const uint8_t* _frm_nxt = _frm;
3598 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3599 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3600 uint32_t* _to_nxt = _to;
3601 result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3602 _Maxcode_, _Mode_);
3603 frm_nxt = frm + (_frm_nxt - _frm);
3604 to_nxt = to + (_to_nxt - _to);
3605 return r;
3606}
3607
3608__codecvt_utf16<wchar_t, true>::result
3609__codecvt_utf16<wchar_t, true>::do_unshift(state_type&,
3610 extern_type* to, extern_type*, extern_type*& to_nxt) const
3611{
3612 to_nxt = to;
3613 return noconv;
3614}
3615
3616int
3617__codecvt_utf16<wchar_t, true>::do_encoding() const _NOEXCEPT
3618{
3619 return 0;
3620}
3621
3622bool
3623__codecvt_utf16<wchar_t, true>::do_always_noconv() const _NOEXCEPT
3624{
3625 return false;
3626}
3627
3628int
3629__codecvt_utf16<wchar_t, true>::do_length(state_type&,
3630 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3631{
3632 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3633 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3634 return utf16le_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3635}
3636
3637int
3638__codecvt_utf16<wchar_t, true>::do_max_length() const _NOEXCEPT
3639{
3640 if (_Mode_ & consume_header)
3641 return 6;
3642 return 4;
3643}
3644
3645// __codecvt_utf16<char16_t, false>
3646
3647__codecvt_utf16<char16_t, false>::result
3648__codecvt_utf16<char16_t, false>::do_out(state_type&,
3649 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3650 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3651{
3652 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3653 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3654 const uint16_t* _frm_nxt = _frm;
3655 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3656 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3657 uint8_t* _to_nxt = _to;
3658 result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3659 _Maxcode_, _Mode_);
3660 frm_nxt = frm + (_frm_nxt - _frm);
3661 to_nxt = to + (_to_nxt - _to);
3662 return r;
3663}
3664
3665__codecvt_utf16<char16_t, false>::result
3666__codecvt_utf16<char16_t, false>::do_in(state_type&,
3667 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3668 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3669{
3670 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3671 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3672 const uint8_t* _frm_nxt = _frm;
3673 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3674 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3675 uint16_t* _to_nxt = _to;
3676 result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3677 _Maxcode_, _Mode_);
3678 frm_nxt = frm + (_frm_nxt - _frm);
3679 to_nxt = to + (_to_nxt - _to);
3680 return r;
3681}
3682
3683__codecvt_utf16<char16_t, false>::result
3684__codecvt_utf16<char16_t, false>::do_unshift(state_type&,
3685 extern_type* to, extern_type*, extern_type*& to_nxt) const
3686{
3687 to_nxt = to;
3688 return noconv;
3689}
3690
3691int
3692__codecvt_utf16<char16_t, false>::do_encoding() const _NOEXCEPT
3693{
3694 return 0;
3695}
3696
3697bool
3698__codecvt_utf16<char16_t, false>::do_always_noconv() const _NOEXCEPT
3699{
3700 return false;
3701}
3702
3703int
3704__codecvt_utf16<char16_t, false>::do_length(state_type&,
3705 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3706{
3707 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3708 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3709 return utf16be_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3710}
3711
3712int
3713__codecvt_utf16<char16_t, false>::do_max_length() const _NOEXCEPT
3714{
3715 if (_Mode_ & consume_header)
3716 return 4;
3717 return 2;
3718}
3719
3720// __codecvt_utf16<char16_t, true>
3721
3722__codecvt_utf16<char16_t, true>::result
3723__codecvt_utf16<char16_t, true>::do_out(state_type&,
3724 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3725 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3726{
3727 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3728 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3729 const uint16_t* _frm_nxt = _frm;
3730 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3731 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3732 uint8_t* _to_nxt = _to;
3733 result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3734 _Maxcode_, _Mode_);
3735 frm_nxt = frm + (_frm_nxt - _frm);
3736 to_nxt = to + (_to_nxt - _to);
3737 return r;
3738}
3739
3740__codecvt_utf16<char16_t, true>::result
3741__codecvt_utf16<char16_t, true>::do_in(state_type&,
3742 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3743 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3744{
3745 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3746 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3747 const uint8_t* _frm_nxt = _frm;
3748 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3749 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3750 uint16_t* _to_nxt = _to;
3751 result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3752 _Maxcode_, _Mode_);
3753 frm_nxt = frm + (_frm_nxt - _frm);
3754 to_nxt = to + (_to_nxt - _to);
3755 return r;
3756}
3757
3758__codecvt_utf16<char16_t, true>::result
3759__codecvt_utf16<char16_t, true>::do_unshift(state_type&,
3760 extern_type* to, extern_type*, extern_type*& to_nxt) const
3761{
3762 to_nxt = to;
3763 return noconv;
3764}
3765
3766int
3767__codecvt_utf16<char16_t, true>::do_encoding() const _NOEXCEPT
3768{
3769 return 0;
3770}
3771
3772bool
3773__codecvt_utf16<char16_t, true>::do_always_noconv() const _NOEXCEPT
3774{
3775 return false;
3776}
3777
3778int
3779__codecvt_utf16<char16_t, true>::do_length(state_type&,
3780 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3781{
3782 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3783 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3784 return utf16le_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3785}
3786
3787int
3788__codecvt_utf16<char16_t, true>::do_max_length() const _NOEXCEPT
3789{
3790 if (_Mode_ & consume_header)
3791 return 4;
3792 return 2;
3793}
3794
3795// __codecvt_utf16<char32_t, false>
3796
3797__codecvt_utf16<char32_t, false>::result
3798__codecvt_utf16<char32_t, false>::do_out(state_type&,
3799 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3800 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3801{
3802 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3803 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3804 const uint32_t* _frm_nxt = _frm;
3805 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3806 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3807 uint8_t* _to_nxt = _to;
3808 result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3809 _Maxcode_, _Mode_);
3810 frm_nxt = frm + (_frm_nxt - _frm);
3811 to_nxt = to + (_to_nxt - _to);
3812 return r;
3813}
3814
3815__codecvt_utf16<char32_t, false>::result
3816__codecvt_utf16<char32_t, false>::do_in(state_type&,
3817 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3818 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3819{
3820 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3821 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3822 const uint8_t* _frm_nxt = _frm;
3823 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3824 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3825 uint32_t* _to_nxt = _to;
3826 result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3827 _Maxcode_, _Mode_);
3828 frm_nxt = frm + (_frm_nxt - _frm);
3829 to_nxt = to + (_to_nxt - _to);
3830 return r;
3831}
3832
3833__codecvt_utf16<char32_t, false>::result
3834__codecvt_utf16<char32_t, false>::do_unshift(state_type&,
3835 extern_type* to, extern_type*, extern_type*& to_nxt) const
3836{
3837 to_nxt = to;
3838 return noconv;
3839}
3840
3841int
3842__codecvt_utf16<char32_t, false>::do_encoding() const _NOEXCEPT
3843{
3844 return 0;
3845}
3846
3847bool
3848__codecvt_utf16<char32_t, false>::do_always_noconv() const _NOEXCEPT
3849{
3850 return false;
3851}
3852
3853int
3854__codecvt_utf16<char32_t, false>::do_length(state_type&,
3855 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3856{
3857 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3858 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3859 return utf16be_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3860}
3861
3862int
3863__codecvt_utf16<char32_t, false>::do_max_length() const _NOEXCEPT
3864{
3865 if (_Mode_ & consume_header)
3866 return 6;
3867 return 4;
3868}
3869
3870// __codecvt_utf16<char32_t, true>
3871
3872__codecvt_utf16<char32_t, true>::result
3873__codecvt_utf16<char32_t, true>::do_out(state_type&,
3874 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3875 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3876{
3877 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3878 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3879 const uint32_t* _frm_nxt = _frm;
3880 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3881 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3882 uint8_t* _to_nxt = _to;
3883 result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3884 _Maxcode_, _Mode_);
3885 frm_nxt = frm + (_frm_nxt - _frm);
3886 to_nxt = to + (_to_nxt - _to);
3887 return r;
3888}
3889
3890__codecvt_utf16<char32_t, true>::result
3891__codecvt_utf16<char32_t, true>::do_in(state_type&,
3892 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3893 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3894{
3895 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3896 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3897 const uint8_t* _frm_nxt = _frm;
3898 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3899 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3900 uint32_t* _to_nxt = _to;
3901 result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3902 _Maxcode_, _Mode_);
3903 frm_nxt = frm + (_frm_nxt - _frm);
3904 to_nxt = to + (_to_nxt - _to);
3905 return r;
3906}
3907
3908__codecvt_utf16<char32_t, true>::result
3909__codecvt_utf16<char32_t, true>::do_unshift(state_type&,
3910 extern_type* to, extern_type*, extern_type*& to_nxt) const
3911{
3912 to_nxt = to;
3913 return noconv;
3914}
3915
3916int
3917__codecvt_utf16<char32_t, true>::do_encoding() const _NOEXCEPT
3918{
3919 return 0;
3920}
3921
3922bool
3923__codecvt_utf16<char32_t, true>::do_always_noconv() const _NOEXCEPT
3924{
3925 return false;
3926}
3927
3928int
3929__codecvt_utf16<char32_t, true>::do_length(state_type&,
3930 const extern_type* frm, const extern_type* frm_end, size_t mx) const
3931{
3932 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3933 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3934 return utf16le_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3935}
3936
3937int
3938__codecvt_utf16<char32_t, true>::do_max_length() const _NOEXCEPT
3939{
3940 if (_Mode_ & consume_header)
3941 return 6;
3942 return 4;
3943}
3944
3945// __codecvt_utf8_utf16<wchar_t>
3946
3947__codecvt_utf8_utf16<wchar_t>::result
3948__codecvt_utf8_utf16<wchar_t>::do_out(state_type&,
3949 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3950 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3951{
3952 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3953 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3954 const uint32_t* _frm_nxt = _frm;
3955 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3956 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3957 uint8_t* _to_nxt = _to;
3958 result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3959 _Maxcode_, _Mode_);
3960 frm_nxt = frm + (_frm_nxt - _frm);
3961 to_nxt = to + (_to_nxt - _to);
3962 return r;
3963}
3964
3965__codecvt_utf8_utf16<wchar_t>::result
3966__codecvt_utf8_utf16<wchar_t>::do_in(state_type&,
3967 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3968 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3969{
3970 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3971 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3972 const uint8_t* _frm_nxt = _frm;
3973 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3974 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3975 uint32_t* _to_nxt = _to;
3976 result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3977 _Maxcode_, _Mode_);
3978 frm_nxt = frm + (_frm_nxt - _frm);
3979 to_nxt = to + (_to_nxt - _to);
3980 return r;
3981}
3982
3983__codecvt_utf8_utf16<wchar_t>::result
3984__codecvt_utf8_utf16<wchar_t>::do_unshift(state_type&,
3985 extern_type* to, extern_type*, extern_type*& to_nxt) const
3986{
3987 to_nxt = to;
3988 return noconv;
3989}
3990
3991int
3992__codecvt_utf8_utf16<wchar_t>::do_encoding() const _NOEXCEPT
3993{
3994 return 0;
3995}
3996
3997bool
3998__codecvt_utf8_utf16<wchar_t>::do_always_noconv() const _NOEXCEPT
3999{
4000 return false;
4001}
4002
4003int
4004__codecvt_utf8_utf16<wchar_t>::do_length(state_type&,
4005 const extern_type* frm, const extern_type* frm_end, size_t mx) const
4006{
4007 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
4008 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4009 return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
4010}
4011
4012int
4013__codecvt_utf8_utf16<wchar_t>::do_max_length() const _NOEXCEPT
4014{
4015 if (_Mode_ & consume_header)
4016 return 7;
4017 return 4;
4018}
4019
4020// __codecvt_utf8_utf16<char16_t>
4021
4022__codecvt_utf8_utf16<char16_t>::result
4023__codecvt_utf8_utf16<char16_t>::do_out(state_type&,
4024 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
4025 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
4026{
4027 const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
4028 const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
4029 const uint16_t* _frm_nxt = _frm;
4030 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
4031 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
4032 uint8_t* _to_nxt = _to;
4033 result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4034 _Maxcode_, _Mode_);
4035 frm_nxt = frm + (_frm_nxt - _frm);
4036 to_nxt = to + (_to_nxt - _to);
4037 return r;
4038}
4039
4040__codecvt_utf8_utf16<char16_t>::result
4041__codecvt_utf8_utf16<char16_t>::do_in(state_type&,
4042 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
4043 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
4044{
4045 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
4046 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4047 const uint8_t* _frm_nxt = _frm;
4048 uint16_t* _to = reinterpret_cast<uint16_t*>(to);
4049 uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
4050 uint16_t* _to_nxt = _to;
4051 result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4052 _Maxcode_, _Mode_);
4053 frm_nxt = frm + (_frm_nxt - _frm);
4054 to_nxt = to + (_to_nxt - _to);
4055 return r;
4056}
4057
4058__codecvt_utf8_utf16<char16_t>::result
4059__codecvt_utf8_utf16<char16_t>::do_unshift(state_type&,
4060 extern_type* to, extern_type*, extern_type*& to_nxt) const
4061{
4062 to_nxt = to;
4063 return noconv;
4064}
4065
4066int
4067__codecvt_utf8_utf16<char16_t>::do_encoding() const _NOEXCEPT
4068{
4069 return 0;
4070}
4071
4072bool
4073__codecvt_utf8_utf16<char16_t>::do_always_noconv() const _NOEXCEPT
4074{
4075 return false;
4076}
4077
4078int
4079__codecvt_utf8_utf16<char16_t>::do_length(state_type&,
4080 const extern_type* frm, const extern_type* frm_end, size_t mx) const
4081{
4082 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
4083 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4084 return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
4085}
4086
4087int
4088__codecvt_utf8_utf16<char16_t>::do_max_length() const _NOEXCEPT
4089{
4090 if (_Mode_ & consume_header)
4091 return 7;
4092 return 4;
4093}
4094
4095// __codecvt_utf8_utf16<char32_t>
4096
4097__codecvt_utf8_utf16<char32_t>::result
4098__codecvt_utf8_utf16<char32_t>::do_out(state_type&,
4099 const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
4100 extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
4101{
4102 const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
4103 const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
4104 const uint32_t* _frm_nxt = _frm;
4105 uint8_t* _to = reinterpret_cast<uint8_t*>(to);
4106 uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
4107 uint8_t* _to_nxt = _to;
4108 result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4109 _Maxcode_, _Mode_);
4110 frm_nxt = frm + (_frm_nxt - _frm);
4111 to_nxt = to + (_to_nxt - _to);
4112 return r;
4113}
4114
4115__codecvt_utf8_utf16<char32_t>::result
4116__codecvt_utf8_utf16<char32_t>::do_in(state_type&,
4117 const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
4118 intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
4119{
4120 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
4121 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4122 const uint8_t* _frm_nxt = _frm;
4123 uint32_t* _to = reinterpret_cast<uint32_t*>(to);
4124 uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
4125 uint32_t* _to_nxt = _to;
4126 result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4127 _Maxcode_, _Mode_);
4128 frm_nxt = frm + (_frm_nxt - _frm);
4129 to_nxt = to + (_to_nxt - _to);
4130 return r;
4131}
4132
4133__codecvt_utf8_utf16<char32_t>::result
4134__codecvt_utf8_utf16<char32_t>::do_unshift(state_type&,
4135 extern_type* to, extern_type*, extern_type*& to_nxt) const
4136{
4137 to_nxt = to;
4138 return noconv;
4139}
4140
4141int
4142__codecvt_utf8_utf16<char32_t>::do_encoding() const _NOEXCEPT
4143{
4144 return 0;
4145}
4146
4147bool
4148__codecvt_utf8_utf16<char32_t>::do_always_noconv() const _NOEXCEPT
4149{
4150 return false;
4151}
4152
4153int
4154__codecvt_utf8_utf16<char32_t>::do_length(state_type&,
4155 const extern_type* frm, const extern_type* frm_end, size_t mx) const
4156{
4157 const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
4158 const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4159 return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
4160}
4161
4162int
4163__codecvt_utf8_utf16<char32_t>::do_max_length() const _NOEXCEPT
4164{
4165 if (_Mode_ & consume_header)
4166 return 7;
4167 return 4;
4168}
4169
4170// __narrow_to_utf8<16>
4171
4172__narrow_to_utf8<16>::~__narrow_to_utf8()
4173{
4174}
4175
4176// __narrow_to_utf8<32>
4177
4178__narrow_to_utf8<32>::~__narrow_to_utf8()
4179{
4180}
4181
4182// __widen_from_utf8<16>
4183
4184__widen_from_utf8<16>::~__widen_from_utf8()
4185{
4186}
4187
4188// __widen_from_utf8<32>
4189
4190__widen_from_utf8<32>::~__widen_from_utf8()
4191{
4192}
4193
4194
4195static bool checked_string_to_wchar_convert(wchar_t& dest,
4196 const char* ptr,
4197 locale_t loc) {
4198 if (*ptr == '\0')
4199 return false;
4200 mbstate_t mb = {};
4201 wchar_t out;
4202 size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc);
4203 if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) {
4204 return false;
4205 }
4206 dest = out;
4207 return true;
4208}
4209
4210static bool checked_string_to_char_convert(char& dest,
4211 const char* ptr,
4212 locale_t __loc) {
4213 if (*ptr == '\0')
4214 return false;
4215 if (!ptr[1]) {
4216 dest = *ptr;
4217 return true;
4218 }
4219 // First convert the MBS into a wide char then attempt to narrow it using
4220 // wctob_l.
4221 wchar_t wout;
4222 if (!checked_string_to_wchar_convert(wout, ptr, __loc))
4223 return false;
4224 int res;
4225 if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) {
4226 dest = res;
4227 return true;
4228 }
4229 // FIXME: Work around specific multibyte sequences that we can reasonable
4230 // translate into a different single byte.
4231 switch (wout) {
4232 case L'\u202F': // narrow non-breaking space
4233 case L'\u00A0': // non-breaking space
4234 dest = ' ';
4235 return true;
4236 default:
4237 return false;
4238 }
4239 _LIBCPP_UNREACHABLE();
4240}
4241
4242
4243// numpunct<char> && numpunct<wchar_t>
4244
4245locale::id numpunct< char >::id;
4246locale::id numpunct<wchar_t>::id;
4247
4248numpunct<char>::numpunct(size_t refs)
4249 : locale::facet(refs),
4250 __decimal_point_('.'),
4251 __thousands_sep_(',')
4252{
4253}
4254
4255numpunct<wchar_t>::numpunct(size_t refs)
4256 : locale::facet(refs),
4257 __decimal_point_(L'.'),
4258 __thousands_sep_(L',')
4259{
4260}
4261
4262numpunct<char>::~numpunct()
4263{
4264}
4265
4266numpunct<wchar_t>::~numpunct()
4267{
4268}
4269
4270 char numpunct< char >::do_decimal_point() const {return __decimal_point_;}
4271wchar_t numpunct<wchar_t>::do_decimal_point() const {return __decimal_point_;}
4272
4273 char numpunct< char >::do_thousands_sep() const {return __thousands_sep_;}
4274wchar_t numpunct<wchar_t>::do_thousands_sep() const {return __thousands_sep_;}
4275
4276string numpunct< char >::do_grouping() const {return __grouping_;}
4277string numpunct<wchar_t>::do_grouping() const {return __grouping_;}
4278
4279 string numpunct< char >::do_truename() const {return "true";}
4280wstring numpunct<wchar_t>::do_truename() const {return L"true";}
4281
4282 string numpunct< char >::do_falsename() const {return "false";}
4283wstring numpunct<wchar_t>::do_falsename() const {return L"false";}
4284
4285// numpunct_byname<char>
4286
4287numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs)
4288 : numpunct<char>(refs)
4289{
4290 __init(nm);
4291}
4292
4293numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs)
4294 : numpunct<char>(refs)
4295{
4296 __init(nm.c_str());
4297}
4298
4299numpunct_byname<char>::~numpunct_byname()
4300{
4301}
4302
4303void
4304numpunct_byname<char>::__init(const char* nm)
4305{
4306 if (strcmp(nm, "C") != 0)
4307 {
4308 __libcpp_unique_locale loc(nm);
4309 if (!loc)
4310 __throw_runtime_error("numpunct_byname<char>::numpunct_byname"
4311 " failed to construct for " + string(nm));
4312
4313 lconv* lc = __libcpp_localeconv_l(loc.get());
4314 checked_string_to_char_convert(__decimal_point_, lc->decimal_point,
4315 loc.get());
4316 checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep,
4317 loc.get());
4318 __grouping_ = lc->grouping;
4319 // localization for truename and falsename is not available
4320 }
4321}
4322
4323// numpunct_byname<wchar_t>
4324
4325numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs)
4326 : numpunct<wchar_t>(refs)
4327{
4328 __init(nm);
4329}
4330
4331numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs)
4332 : numpunct<wchar_t>(refs)
4333{
4334 __init(nm.c_str());
4335}
4336
4337numpunct_byname<wchar_t>::~numpunct_byname()
4338{
4339}
4340
4341void
4342numpunct_byname<wchar_t>::__init(const char* nm)
4343{
4344 if (strcmp(nm, "C") != 0)
4345 {
4346 __libcpp_unique_locale loc(nm);
4347 if (!loc)
4348 __throw_runtime_error("numpunct_byname<wchar_t>::numpunct_byname"
4349 " failed to construct for " + string(nm));
4350
4351 lconv* lc = __libcpp_localeconv_l(loc.get());
4352 checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point,
4353 loc.get());
4354 checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep,
4355 loc.get());
4356 __grouping_ = lc->grouping;
4357 // localization for truename and falsename is not available
4358 }
4359}
4360
4361// num_get helpers
4362
4363int
4364__num_get_base::__get_base(ios_base& iob)
4365{
4366 ios_base::fmtflags __basefield = iob.flags() & ios_base::basefield;
4367 if (__basefield == ios_base::oct)
4368 return 8;
4369 else if (__basefield == ios_base::hex)
4370 return 16;
4371 else if (__basefield == 0)
4372 return 0;
4373 return 10;
4374}
4375
4376const char __num_get_base::__src[33] = "0123456789abcdefABCDEFxX+-pPiInN";
4377
4378void
4379__check_grouping(const string& __grouping, unsigned* __g, unsigned* __g_end,
4380 ios_base::iostate& __err)
4381{
4382// if the grouping pattern is empty _or_ there are no grouping bits, then do nothing
4383// we always have at least a single entry in [__g, __g_end); the end of the input sequence
4384 if (__grouping.size() != 0 && __g_end - __g > 1)
4385 {
4386 reverse(__g, __g_end);
4387 const char* __ig = __grouping.data();
4388 const char* __eg = __ig + __grouping.size();
4389 for (unsigned* __r = __g; __r < __g_end-1; ++__r)
4390 {
4391 if (0 < *__ig && *__ig < numeric_limits<char>::max())
4392 {
4393 if (static_cast<unsigned>(*__ig) != *__r)
4394 {
4395 __err = ios_base::failbit;
4396 return;
4397 }
4398 }
4399 if (__eg - __ig > 1)
4400 ++__ig;
4401 }
4402 if (0 < *__ig && *__ig < numeric_limits<char>::max())
4403 {
4404 if (static_cast<unsigned>(*__ig) < __g_end[-1] || __g_end[-1] == 0)
4405 __err = ios_base::failbit;
4406 }
4407 }
4408}
4409
4410void
4411__num_put_base::__format_int(char* __fmtp, const char* __len, bool __signd,
4412 ios_base::fmtflags __flags)
4413{
4414 if (__flags & ios_base::showpos)
4415 *__fmtp++ = '+';
4416 if (__flags & ios_base::showbase)
4417 *__fmtp++ = '#';
4418 while(*__len)
4419 *__fmtp++ = *__len++;
4420 if ((__flags & ios_base::basefield) == ios_base::oct)
4421 *__fmtp = 'o';
4422 else if ((__flags & ios_base::basefield) == ios_base::hex)
4423 {
4424 if (__flags & ios_base::uppercase)
4425 *__fmtp = 'X';
4426 else
4427 *__fmtp = 'x';
4428 }
4429 else if (__signd)
4430 *__fmtp = 'd';
4431 else
4432 *__fmtp = 'u';
4433}
4434
4435bool
4436__num_put_base::__format_float(char* __fmtp, const char* __len,
4437 ios_base::fmtflags __flags)
4438{
4439 bool specify_precision = true;
4440 if (__flags & ios_base::showpos)
4441 *__fmtp++ = '+';
4442 if (__flags & ios_base::showpoint)
4443 *__fmtp++ = '#';
4444 ios_base::fmtflags floatfield = __flags & ios_base::floatfield;
4445 bool uppercase = (__flags & ios_base::uppercase) != 0;
4446 if (floatfield == (ios_base::fixed | ios_base::scientific))
4447 specify_precision = false;
4448 else
4449 {
4450 *__fmtp++ = '.';
4451 *__fmtp++ = '*';
4452 }
4453 while(*__len)
4454 *__fmtp++ = *__len++;
4455 if (floatfield == ios_base::fixed)
4456 {
4457 if (uppercase)
4458 *__fmtp = 'F';
4459 else
4460 *__fmtp = 'f';
4461 }
4462 else if (floatfield == ios_base::scientific)
4463 {
4464 if (uppercase)
4465 *__fmtp = 'E';
4466 else
4467 *__fmtp = 'e';
4468 }
4469 else if (floatfield == (ios_base::fixed | ios_base::scientific))
4470 {
4471 if (uppercase)
4472 *__fmtp = 'A';
4473 else
4474 *__fmtp = 'a';
4475 }
4476 else
4477 {
4478 if (uppercase)
4479 *__fmtp = 'G';
4480 else
4481 *__fmtp = 'g';
4482 }
4483 return specify_precision;
4484}
4485
4486char*
4487__num_put_base::__identify_padding(char* __nb, char* __ne,
4488 const ios_base& __iob)
4489{
4490 switch (__iob.flags() & ios_base::adjustfield)
4491 {
4492 case ios_base::internal:
4493 if (__nb[0] == '-' || __nb[0] == '+')
4494 return __nb+1;
4495 if (__ne - __nb >= 2 && __nb[0] == '0'
4496 && (__nb[1] == 'x' || __nb[1] == 'X'))
4497 return __nb+2;
4498 break;
4499 case ios_base::left:
4500 return __ne;
4501 case ios_base::right:
4502 default:
4503 break;
4504 }
4505 return __nb;
4506}
4507
4508// time_get
4509
4510static
4511string*
4512init_weeks()
4513{
4514 static string weeks[14];
4515 weeks[0] = "Sunday";
4516 weeks[1] = "Monday";
4517 weeks[2] = "Tuesday";
4518 weeks[3] = "Wednesday";
4519 weeks[4] = "Thursday";
4520 weeks[5] = "Friday";
4521 weeks[6] = "Saturday";
4522 weeks[7] = "Sun";
4523 weeks[8] = "Mon";
4524 weeks[9] = "Tue";
4525 weeks[10] = "Wed";
4526 weeks[11] = "Thu";
4527 weeks[12] = "Fri";
4528 weeks[13] = "Sat";
4529 return weeks;
4530}
4531
4532static
4533wstring*
4534init_wweeks()
4535{
4536 static wstring weeks[14];
4537 weeks[0] = L"Sunday";
4538 weeks[1] = L"Monday";
4539 weeks[2] = L"Tuesday";
4540 weeks[3] = L"Wednesday";
4541 weeks[4] = L"Thursday";
4542 weeks[5] = L"Friday";
4543 weeks[6] = L"Saturday";
4544 weeks[7] = L"Sun";
4545 weeks[8] = L"Mon";
4546 weeks[9] = L"Tue";
4547 weeks[10] = L"Wed";
4548 weeks[11] = L"Thu";
4549 weeks[12] = L"Fri";
4550 weeks[13] = L"Sat";
4551 return weeks;
4552}
4553
4554template <>
4555const string*
4556__time_get_c_storage<char>::__weeks() const
4557{
4558 static const string* weeks = init_weeks();
4559 return weeks;
4560}
4561
4562template <>
4563const wstring*
4564__time_get_c_storage<wchar_t>::__weeks() const
4565{
4566 static const wstring* weeks = init_wweeks();
4567 return weeks;
4568}
4569
4570static
4571string*
4572init_months()
4573{
4574 static string months[24];
4575 months[0] = "January";
4576 months[1] = "February";
4577 months[2] = "March";
4578 months[3] = "April";
4579 months[4] = "May";
4580 months[5] = "June";
4581 months[6] = "July";
4582 months[7] = "August";
4583 months[8] = "September";
4584 months[9] = "October";
4585 months[10] = "November";
4586 months[11] = "December";
4587 months[12] = "Jan";
4588 months[13] = "Feb";
4589 months[14] = "Mar";
4590 months[15] = "Apr";
4591 months[16] = "May";
4592 months[17] = "Jun";
4593 months[18] = "Jul";
4594 months[19] = "Aug";
4595 months[20] = "Sep";
4596 months[21] = "Oct";
4597 months[22] = "Nov";
4598 months[23] = "Dec";
4599 return months;
4600}
4601
4602static
4603wstring*
4604init_wmonths()
4605{
4606 static wstring months[24];
4607 months[0] = L"January";
4608 months[1] = L"February";
4609 months[2] = L"March";
4610 months[3] = L"April";
4611 months[4] = L"May";
4612 months[5] = L"June";
4613 months[6] = L"July";
4614 months[7] = L"August";
4615 months[8] = L"September";
4616 months[9] = L"October";
4617 months[10] = L"November";
4618 months[11] = L"December";
4619 months[12] = L"Jan";
4620 months[13] = L"Feb";
4621 months[14] = L"Mar";
4622 months[15] = L"Apr";
4623 months[16] = L"May";
4624 months[17] = L"Jun";
4625 months[18] = L"Jul";
4626 months[19] = L"Aug";
4627 months[20] = L"Sep";
4628 months[21] = L"Oct";
4629 months[22] = L"Nov";
4630 months[23] = L"Dec";
4631 return months;
4632}
4633
4634template <>
4635const string*
4636__time_get_c_storage<char>::__months() const
4637{
4638 static const string* months = init_months();
4639 return months;
4640}
4641
4642template <>
4643const wstring*
4644__time_get_c_storage<wchar_t>::__months() const
4645{
4646 static const wstring* months = init_wmonths();
4647 return months;
4648}
4649
4650static
4651string*
4652init_am_pm()
4653{
4654 static string am_pm[2];
4655 am_pm[0] = "AM";
4656 am_pm[1] = "PM";
4657 return am_pm;
4658}
4659
4660static
4661wstring*
4662init_wam_pm()
4663{
4664 static wstring am_pm[2];
4665 am_pm[0] = L"AM";
4666 am_pm[1] = L"PM";
4667 return am_pm;
4668}
4669
4670template <>
4671const string*
4672__time_get_c_storage<char>::__am_pm() const
4673{
4674 static const string* am_pm = init_am_pm();
4675 return am_pm;
4676}
4677
4678template <>
4679const wstring*
4680__time_get_c_storage<wchar_t>::__am_pm() const
4681{
4682 static const wstring* am_pm = init_wam_pm();
4683 return am_pm;
4684}
4685
4686template <>
4687const string&
4688__time_get_c_storage<char>::__x() const
4689{
4690 static string s("%m/%d/%y");
4691 return s;
4692}
4693
4694template <>
4695const wstring&
4696__time_get_c_storage<wchar_t>::__x() const
4697{
4698 static wstring s(L"%m/%d/%y");
4699 return s;
4700}
4701
4702template <>
4703const string&
4704__time_get_c_storage<char>::__X() const
4705{
4706 static string s("%H:%M:%S");
4707 return s;
4708}
4709
4710template <>
4711const wstring&
4712__time_get_c_storage<wchar_t>::__X() const
4713{
4714 static wstring s(L"%H:%M:%S");
4715 return s;
4716}
4717
4718template <>
4719const string&
4720__time_get_c_storage<char>::__c() const
4721{
4722 static string s("%a %b %d %H:%M:%S %Y");
4723 return s;
4724}
4725
4726template <>
4727const wstring&
4728__time_get_c_storage<wchar_t>::__c() const
4729{
4730 static wstring s(L"%a %b %d %H:%M:%S %Y");
4731 return s;
4732}
4733
4734template <>
4735const string&
4736__time_get_c_storage<char>::__r() const
4737{
4738 static string s("%I:%M:%S %p");
4739 return s;
4740}
4741
4742template <>
4743const wstring&
4744__time_get_c_storage<wchar_t>::__r() const
4745{
4746 static wstring s(L"%I:%M:%S %p");
4747 return s;
4748}
4749
4750// time_get_byname
4751
4752__time_get::__time_get(const char* nm)
4753 : __loc_(newlocale(LC_ALL_MASK, nm, 0))
4754{
4755 if (__loc_ == 0)
4756 __throw_runtime_error("time_get_byname"
4757 " failed to construct for " + string(nm));
4758}
4759
4760__time_get::__time_get(const string& nm)
4761 : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
4762{
4763 if (__loc_ == 0)
4764 __throw_runtime_error("time_get_byname"
4765 " failed to construct for " + nm);
4766}
4767
4768__time_get::~__time_get()
4769{
4770 freelocale(__loc_);
4771}
4772#if defined(__clang__)
4773#pragma clang diagnostic ignored "-Wmissing-field-initializers"
4774#endif
4775#if defined(__GNUG__)
4776#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
4777#endif
4778
4779template <>
4780string
4781__time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct)
4782{
4783 tm t = {0};
4784 t.tm_sec = 59;
4785 t.tm_min = 55;
4786 t.tm_hour = 23;
4787 t.tm_mday = 31;
4788 t.tm_mon = 11;
4789 t.tm_year = 161;
4790 t.tm_wday = 6;
4791 t.tm_yday = 364;
4792 t.tm_isdst = -1;
4793 char buf[100];
4794 char f[3] = {0};
4795 f[0] = '%';
4796 f[1] = fmt;
4797 size_t n = strftime_l(buf, countof(buf), f, &t, __loc_);
4798 char* bb = buf;
4799 char* be = buf + n;
4800 string result;
4801 while (bb != be)
4802 {
4803 if (ct.is(ctype_base::space, *bb))
4804 {
4805 result.push_back(' ');
4806 for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
4807 ;
4808 continue;
4809 }
4810 char* w = bb;
4811 ios_base::iostate err = ios_base::goodbit;
4812 ptrdiff_t i = __scan_keyword(w, be, this->__weeks_, this->__weeks_+14,
4813 ct, err, false)
4814 - this->__weeks_;
4815 if (i < 14)
4816 {
4817 result.push_back('%');
4818 if (i < 7)
4819 result.push_back('A');
4820 else
4821 result.push_back('a');
4822 bb = w;
4823 continue;
4824 }
4825 w = bb;
4826 i = __scan_keyword(w, be, this->__months_, this->__months_+24,
4827 ct, err, false)
4828 - this->__months_;
4829 if (i < 24)
4830 {
4831 result.push_back('%');
4832 if (i < 12)
4833 result.push_back('B');
4834 else
4835 result.push_back('b');
4836 if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
4837 result.back() = 'm';
4838 bb = w;
4839 continue;
4840 }
4841 if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
4842 {
4843 w = bb;
4844 i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_+2,
4845 ct, err, false) - this->__am_pm_;
4846 if (i < 2)
4847 {
4848 result.push_back('%');
4849 result.push_back('p');
4850 bb = w;
4851 continue;
4852 }
4853 }
4854 w = bb;
4855 if (ct.is(ctype_base::digit, *bb))
4856 {
4857 switch(__get_up_to_n_digits(bb, be, err, ct, 4))
4858 {
4859 case 6:
4860 result.push_back('%');
4861 result.push_back('w');
4862 break;
4863 case 7:
4864 result.push_back('%');
4865 result.push_back('u');
4866 break;
4867 case 11:
4868 result.push_back('%');
4869 result.push_back('I');
4870 break;
4871 case 12:
4872 result.push_back('%');
4873 result.push_back('m');
4874 break;
4875 case 23:
4876 result.push_back('%');
4877 result.push_back('H');
4878 break;
4879 case 31:
4880 result.push_back('%');
4881 result.push_back('d');
4882 break;
4883 case 55:
4884 result.push_back('%');
4885 result.push_back('M');
4886 break;
4887 case 59:
4888 result.push_back('%');
4889 result.push_back('S');
4890 break;
4891 case 61:
4892 result.push_back('%');
4893 result.push_back('y');
4894 break;
4895 case 364:
4896 result.push_back('%');
4897 result.push_back('j');
4898 break;
4899 case 2061:
4900 result.push_back('%');
4901 result.push_back('Y');
4902 break;
4903 default:
4904 for (; w != bb; ++w)
4905 result.push_back(*w);
4906 break;
4907 }
4908 continue;
4909 }
4910 if (*bb == '%')
4911 {
4912 result.push_back('%');
4913 result.push_back('%');
4914 ++bb;
4915 continue;
4916 }
4917 result.push_back(*bb);
4918 ++bb;
4919 }
4920 return result;
4921}
4922
4923#if defined(__clang__)
4924#pragma clang diagnostic ignored "-Wmissing-braces"
4925#endif
4926
4927template <>
4928wstring
4929__time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)
4930{
4931 tm t = {0};
4932 t.tm_sec = 59;
4933 t.tm_min = 55;
4934 t.tm_hour = 23;
4935 t.tm_mday = 31;
4936 t.tm_mon = 11;
4937 t.tm_year = 161;
4938 t.tm_wday = 6;
4939 t.tm_yday = 364;
4940 t.tm_isdst = -1;
4941 char buf[100];
4942 char f[3] = {0};
4943 f[0] = '%';
4944 f[1] = fmt;
4945 strftime_l(buf, countof(buf), f, &t, __loc_);
4946 wchar_t wbuf[100];
4947 wchar_t* wbb = wbuf;
4948 mbstate_t mb = {0};
4949 const char* bb = buf;
4950 size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_);
4951 if (j == size_t(-1))
4952 __throw_runtime_error("locale not supported");
4953 wchar_t* wbe = wbb + j;
4954 wstring result;
4955 while (wbb != wbe)
4956 {
4957 if (ct.is(ctype_base::space, *wbb))
4958 {
4959 result.push_back(L' ');
4960 for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
4961 ;
4962 continue;
4963 }
4964 wchar_t* w = wbb;
4965 ios_base::iostate err = ios_base::goodbit;
4966 ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_+14,
4967 ct, err, false)
4968 - this->__weeks_;
4969 if (i < 14)
4970 {
4971 result.push_back(L'%');
4972 if (i < 7)
4973 result.push_back(L'A');
4974 else
4975 result.push_back(L'a');
4976 wbb = w;
4977 continue;
4978 }
4979 w = wbb;
4980 i = __scan_keyword(w, wbe, this->__months_, this->__months_+24,
4981 ct, err, false)
4982 - this->__months_;
4983 if (i < 24)
4984 {
4985 result.push_back(L'%');
4986 if (i < 12)
4987 result.push_back(L'B');
4988 else
4989 result.push_back(L'b');
4990 if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
4991 result.back() = L'm';
4992 wbb = w;
4993 continue;
4994 }
4995 if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
4996 {
4997 w = wbb;
4998 i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_+2,
4999 ct, err, false) - this->__am_pm_;
5000 if (i < 2)
5001 {
5002 result.push_back(L'%');
5003 result.push_back(L'p');
5004 wbb = w;
5005 continue;
5006 }
5007 }
5008 w = wbb;
5009 if (ct.is(ctype_base::digit, *wbb))
5010 {
5011 switch(__get_up_to_n_digits(wbb, wbe, err, ct, 4))
5012 {
5013 case 6:
5014 result.push_back(L'%');
5015 result.push_back(L'w');
5016 break;
5017 case 7:
5018 result.push_back(L'%');
5019 result.push_back(L'u');
5020 break;
5021 case 11:
5022 result.push_back(L'%');
5023 result.push_back(L'I');
5024 break;
5025 case 12:
5026 result.push_back(L'%');
5027 result.push_back(L'm');
5028 break;
5029 case 23:
5030 result.push_back(L'%');
5031 result.push_back(L'H');
5032 break;
5033 case 31:
5034 result.push_back(L'%');
5035 result.push_back(L'd');
5036 break;
5037 case 55:
5038 result.push_back(L'%');
5039 result.push_back(L'M');
5040 break;
5041 case 59:
5042 result.push_back(L'%');
5043 result.push_back(L'S');
5044 break;
5045 case 61:
5046 result.push_back(L'%');
5047 result.push_back(L'y');
5048 break;
5049 case 364:
5050 result.push_back(L'%');
5051 result.push_back(L'j');
5052 break;
5053 case 2061:
5054 result.push_back(L'%');
5055 result.push_back(L'Y');
5056 break;
5057 default:
5058 for (; w != wbb; ++w)
5059 result.push_back(*w);
5060 break;
5061 }
5062 continue;
5063 }
5064 if (ct.narrow(*wbb, 0) == '%')
5065 {
5066 result.push_back(L'%');
5067 result.push_back(L'%');
5068 ++wbb;
5069 continue;
5070 }
5071 result.push_back(*wbb);
5072 ++wbb;
5073 }
5074 return result;
5075}
5076
5077template <>
5078void
5079__time_get_storage<char>::init(const ctype<char>& ct)
5080{
5081 tm t = {0};
5082 char buf[100];
5083 // __weeks_
5084 for (int i = 0; i < 7; ++i)
5085 {
5086 t.tm_wday = i;
5087 strftime_l(buf, countof(buf), "%A", &t, __loc_);
5088 __weeks_[i] = buf;
5089 strftime_l(buf, countof(buf), "%a", &t, __loc_);
5090 __weeks_[i+7] = buf;
5091 }
5092 // __months_
5093 for (int i = 0; i < 12; ++i)
5094 {
5095 t.tm_mon = i;
5096 strftime_l(buf, countof(buf), "%B", &t, __loc_);
5097 __months_[i] = buf;
5098 strftime_l(buf, countof(buf), "%b", &t, __loc_);
5099 __months_[i+12] = buf;
5100 }
5101 // __am_pm_
5102 t.tm_hour = 1;
5103 strftime_l(buf, countof(buf), "%p", &t, __loc_);
5104 __am_pm_[0] = buf;
5105 t.tm_hour = 13;
5106 strftime_l(buf, countof(buf), "%p", &t, __loc_);
5107 __am_pm_[1] = buf;
5108 __c_ = __analyze('c', ct);
5109 __r_ = __analyze('r', ct);
5110 __x_ = __analyze('x', ct);
5111 __X_ = __analyze('X', ct);
5112}
5113
5114template <>
5115void
5116__time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct)
5117{
5118 tm t = {0};
5119 char buf[100];
5120 wchar_t wbuf[100];
5121 wchar_t* wbe;
5122 mbstate_t mb = {0};
5123 // __weeks_
5124 for (int i = 0; i < 7; ++i)
5125 {
5126 t.tm_wday = i;
5127 strftime_l(buf, countof(buf), "%A", &t, __loc_);
5128 mb = mbstate_t();
5129 const char* bb = buf;
5130 size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5131 if (j == size_t(-1))
5132 __throw_runtime_error("locale not supported");
5133 wbe = wbuf + j;
5134 __weeks_[i].assign(wbuf, wbe);
5135 strftime_l(buf, countof(buf), "%a", &t, __loc_);
5136 mb = mbstate_t();
5137 bb = buf;
5138 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5139 if (j == size_t(-1))
5140 __throw_runtime_error("locale not supported");
5141 wbe = wbuf + j;
5142 __weeks_[i+7].assign(wbuf, wbe);
5143 }
5144 // __months_
5145 for (int i = 0; i < 12; ++i)
5146 {
5147 t.tm_mon = i;
5148 strftime_l(buf, countof(buf), "%B", &t, __loc_);
5149 mb = mbstate_t();
5150 const char* bb = buf;
5151 size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5152 if (j == size_t(-1))
5153 __throw_runtime_error("locale not supported");
5154 wbe = wbuf + j;
5155 __months_[i].assign(wbuf, wbe);
5156 strftime_l(buf, countof(buf), "%b", &t, __loc_);
5157 mb = mbstate_t();
5158 bb = buf;
5159 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5160 if (j == size_t(-1))
5161 __throw_runtime_error("locale not supported");
5162 wbe = wbuf + j;
5163 __months_[i+12].assign(wbuf, wbe);
5164 }
5165 // __am_pm_
5166 t.tm_hour = 1;
5167 strftime_l(buf, countof(buf), "%p", &t, __loc_);
5168 mb = mbstate_t();
5169 const char* bb = buf;
5170 size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5171 if (j == size_t(-1))
5172 __throw_runtime_error("locale not supported");
5173 wbe = wbuf + j;
5174 __am_pm_[0].assign(wbuf, wbe);
5175 t.tm_hour = 13;
5176 strftime_l(buf, countof(buf), "%p", &t, __loc_);
5177 mb = mbstate_t();
5178 bb = buf;
5179 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5180 if (j == size_t(-1))
5181 __throw_runtime_error("locale not supported");
5182 wbe = wbuf + j;
5183 __am_pm_[1].assign(wbuf, wbe);
5184 __c_ = __analyze('c', ct);
5185 __r_ = __analyze('r', ct);
5186 __x_ = __analyze('x', ct);
5187 __X_ = __analyze('X', ct);
5188}
5189
5190template <class CharT>
5191struct _LIBCPP_HIDDEN __time_get_temp
5192 : public ctype_byname<CharT>
5193{
5194 explicit __time_get_temp(const char* nm)
5195 : ctype_byname<CharT>(nm, 1) {}
5196 explicit __time_get_temp(const string& nm)
5197 : ctype_byname<CharT>(nm, 1) {}
5198};
5199
5200template <>
5201__time_get_storage<char>::__time_get_storage(const char* __nm)
5202 : __time_get(__nm)
5203{
5204 const __time_get_temp<char> ct(__nm);
5205 init(ct);
5206}
5207
5208template <>
5209__time_get_storage<char>::__time_get_storage(const string& __nm)
5210 : __time_get(__nm)
5211{
5212 const __time_get_temp<char> ct(__nm);
5213 init(ct);
5214}
5215
5216template <>
5217__time_get_storage<wchar_t>::__time_get_storage(const char* __nm)
5218 : __time_get(__nm)
5219{
5220 const __time_get_temp<wchar_t> ct(__nm);
5221 init(ct);
5222}
5223
5224template <>
5225__time_get_storage<wchar_t>::__time_get_storage(const string& __nm)
5226 : __time_get(__nm)
5227{
5228 const __time_get_temp<wchar_t> ct(__nm);
5229 init(ct);
5230}
5231
5232template <>
5233time_base::dateorder
5234__time_get_storage<char>::__do_date_order() const
5235{
5236 unsigned i;
5237 for (i = 0; i < __x_.size(); ++i)
5238 if (__x_[i] == '%')
5239 break;
5240 ++i;
5241 switch (__x_[i])
5242 {
5243 case 'y':
5244 case 'Y':
5245 for (++i; i < __x_.size(); ++i)
5246 if (__x_[i] == '%')
5247 break;
5248 if (i == __x_.size())
5249 break;
5250 ++i;
5251 switch (__x_[i])
5252 {
5253 case 'm':
5254 for (++i; i < __x_.size(); ++i)
5255 if (__x_[i] == '%')
5256 break;
5257 if (i == __x_.size())
5258 break;
5259 ++i;
5260 if (__x_[i] == 'd')
5261 return time_base::ymd;
5262 break;
5263 case 'd':
5264 for (++i; i < __x_.size(); ++i)
5265 if (__x_[i] == '%')
5266 break;
5267 if (i == __x_.size())
5268 break;
5269 ++i;
5270 if (__x_[i] == 'm')
5271 return time_base::ydm;
5272 break;
5273 }
5274 break;
5275 case 'm':
5276 for (++i; i < __x_.size(); ++i)
5277 if (__x_[i] == '%')
5278 break;
5279 if (i == __x_.size())
5280 break;
5281 ++i;
5282 if (__x_[i] == 'd')
5283 {
5284 for (++i; i < __x_.size(); ++i)
5285 if (__x_[i] == '%')
5286 break;
5287 if (i == __x_.size())
5288 break;
5289 ++i;
5290 if (__x_[i] == 'y' || __x_[i] == 'Y')
5291 return time_base::mdy;
5292 break;
5293 }
5294 break;
5295 case 'd':
5296 for (++i; i < __x_.size(); ++i)
5297 if (__x_[i] == '%')
5298 break;
5299 if (i == __x_.size())
5300 break;
5301 ++i;
5302 if (__x_[i] == 'm')
5303 {
5304 for (++i; i < __x_.size(); ++i)
5305 if (__x_[i] == '%')
5306 break;
5307 if (i == __x_.size())
5308 break;
5309 ++i;
5310 if (__x_[i] == 'y' || __x_[i] == 'Y')
5311 return time_base::dmy;
5312 break;
5313 }
5314 break;
5315 }
5316 return time_base::no_order;
5317}
5318
5319template <>
5320time_base::dateorder
5321__time_get_storage<wchar_t>::__do_date_order() const
5322{
5323 unsigned i;
5324 for (i = 0; i < __x_.size(); ++i)
5325 if (__x_[i] == L'%')
5326 break;
5327 ++i;
5328 switch (__x_[i])
5329 {
5330 case L'y':
5331 case L'Y':
5332 for (++i; i < __x_.size(); ++i)
5333 if (__x_[i] == L'%')
5334 break;
5335 if (i == __x_.size())
5336 break;
5337 ++i;
5338 switch (__x_[i])
5339 {
5340 case L'm':
5341 for (++i; i < __x_.size(); ++i)
5342 if (__x_[i] == L'%')
5343 break;
5344 if (i == __x_.size())
5345 break;
5346 ++i;
5347 if (__x_[i] == L'd')
5348 return time_base::ymd;
5349 break;
5350 case L'd':
5351 for (++i; i < __x_.size(); ++i)
5352 if (__x_[i] == L'%')
5353 break;
5354 if (i == __x_.size())
5355 break;
5356 ++i;
5357 if (__x_[i] == L'm')
5358 return time_base::ydm;
5359 break;
5360 }
5361 break;
5362 case L'm':
5363 for (++i; i < __x_.size(); ++i)
5364 if (__x_[i] == L'%')
5365 break;
5366 if (i == __x_.size())
5367 break;
5368 ++i;
5369 if (__x_[i] == L'd')
5370 {
5371 for (++i; i < __x_.size(); ++i)
5372 if (__x_[i] == L'%')
5373 break;
5374 if (i == __x_.size())
5375 break;
5376 ++i;
5377 if (__x_[i] == L'y' || __x_[i] == L'Y')
5378 return time_base::mdy;
5379 break;
5380 }
5381 break;
5382 case L'd':
5383 for (++i; i < __x_.size(); ++i)
5384 if (__x_[i] == L'%')
5385 break;
5386 if (i == __x_.size())
5387 break;
5388 ++i;
5389 if (__x_[i] == L'm')
5390 {
5391 for (++i; i < __x_.size(); ++i)
5392 if (__x_[i] == L'%')
5393 break;
5394 if (i == __x_.size())
5395 break;
5396 ++i;
5397 if (__x_[i] == L'y' || __x_[i] == L'Y')
5398 return time_base::dmy;
5399 break;
5400 }
5401 break;
5402 }
5403 return time_base::no_order;
5404}
5405
5406// time_put
5407
5408__time_put::__time_put(const char* nm)
5409 : __loc_(newlocale(LC_ALL_MASK, nm, 0))
5410{
5411 if (__loc_ == 0)
5412 __throw_runtime_error("time_put_byname"
5413 " failed to construct for " + string(nm));
5414}
5415
5416__time_put::__time_put(const string& nm)
5417 : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
5418{
5419 if (__loc_ == 0)
5420 __throw_runtime_error("time_put_byname"
5421 " failed to construct for " + nm);
5422}
5423
5424__time_put::~__time_put()
5425{
5426 if (__loc_ != _LIBCPP_GET_C_LOCALE)
5427 freelocale(__loc_);
5428}
5429
5430void
5431__time_put::__do_put(char* __nb, char*& __ne, const tm* __tm,
5432 char __fmt, char __mod) const
5433{
5434 char fmt[] = {'%', __fmt, __mod, 0};
5435 if (__mod != 0)
5436 swap(fmt[1], fmt[2]);
5437 size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
5438 __ne = __nb + n;
5439}
5440
5441void
5442__time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm,
5443 char __fmt, char __mod) const
5444{
5445 char __nar[100];
5446 char* __ne = __nar + 100;
5447 __do_put(__nar, __ne, __tm, __fmt, __mod);
5448 mbstate_t mb = {0};
5449 const char* __nb = __nar;
5450 size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
5451 if (j == size_t(-1))
5452 __throw_runtime_error("locale not supported");
5453 __we = __wb + j;
5454}
5455
5456// moneypunct_byname
5457
5458template <class charT>
5459static
5460void
5461__init_pat(money_base::pattern& pat, basic_string<charT>& __curr_symbol_,
5462 bool intl, char cs_precedes, char sep_by_space, char sign_posn,
5463 charT space_char)
5464{
5465 const char sign = static_cast<char>(money_base::sign);
5466 const char space = static_cast<char>(money_base::space);
5467 const char none = static_cast<char>(money_base::none);
5468 const char symbol = static_cast<char>(money_base::symbol);
5469 const char value = static_cast<char>(money_base::value);
5470 const bool symbol_contains_sep = intl && __curr_symbol_.size() == 4;
5471
5472 // Comments on case branches reflect 'C11 7.11.2.1 The localeconv
5473 // function'. "Space between sign and symbol or value" means that
5474 // if the sign is adjacent to the symbol, there's a space between
5475 // them, and otherwise there's a space between the sign and value.
5476 //
5477 // C11's localeconv specifies that the fourth character of an
5478 // international curr_symbol is used to separate the sign and
5479 // value when sep_by_space says to do so. C++ can't represent
5480 // that, so we just use a space. When sep_by_space says to
5481 // separate the symbol and value-or-sign with a space, we rearrange the
5482 // curr_symbol to put its spacing character on the correct side of
5483 // the symbol.
5484 //
5485 // We also need to avoid adding an extra space between the sign
5486 // and value when the currency symbol is suppressed (by not
5487 // setting showbase). We match glibc's strfmon by interpreting
5488 // sep_by_space==1 as "omit the space when the currency symbol is
5489 // absent".
5490 //
5491 // Users who want to get this right should use ICU instead.
5492
5493 switch (cs_precedes)
5494 {
5495 case 0: // value before curr_symbol
5496 if (symbol_contains_sep) {
5497 // Move the separator to before the symbol, to place it
5498 // between the value and symbol.
5499 rotate(__curr_symbol_.begin(), __curr_symbol_.begin() + 3,
5500 __curr_symbol_.end());
5501 }
5502 switch (sign_posn)
5503 {
5504 case 0: // Parentheses surround the quantity and currency symbol.
5505 pat.field[0] = sign;
5506 pat.field[1] = value;
5507 pat.field[2] = none; // Any space appears in the symbol.
5508 pat.field[3] = symbol;
5509 switch (sep_by_space)
5510 {
5511 case 0: // No space separates the currency symbol and value.
5512 // This case may have changed between C99 and C11;
5513 // assume the currency symbol matches the intention.
5514 case 2: // Space between sign and currency or value.
5515 // The "sign" is two parentheses, so no space here either.
5516 return;
5517 case 1: // Space between currency-and-sign or currency and value.
5518 if (!symbol_contains_sep) {
5519 // We insert the space into the symbol instead of
5520 // setting pat.field[2]=space so that when
5521 // showbase is not set, the space goes away too.
5522 __curr_symbol_.insert(0, 1, space_char);
5523 }
5524 return;
5525 default:
5526 break;
5527 }
5528 break;
5529 case 1: // The sign string precedes the quantity and currency symbol.
5530 pat.field[0] = sign;
5531 pat.field[3] = symbol;
5532 switch (sep_by_space)
5533 {
5534 case 0: // No space separates the currency symbol and value.
5535 pat.field[1] = value;
5536 pat.field[2] = none;
5537 return;
5538 case 1: // Space between currency-and-sign or currency and value.
5539 pat.field[1] = value;
5540 pat.field[2] = none;
5541 if (!symbol_contains_sep) {
5542 // We insert the space into the symbol instead of
5543 // setting pat.field[2]=space so that when
5544 // showbase is not set, the space goes away too.
5545 __curr_symbol_.insert(0, 1, space_char);
5546 }
5547 return;
5548 case 2: // Space between sign and currency or value.
5549 pat.field[1] = space;
5550 pat.field[2] = value;
5551 if (symbol_contains_sep) {
5552 // Remove the separator from the symbol, since it
5553 // has already appeared after the sign.
5554 __curr_symbol_.erase(__curr_symbol_.begin());
5555 }
5556 return;
5557 default:
5558 break;
5559 }
5560 break;
5561 case 2: // The sign string succeeds the quantity and currency symbol.
5562 pat.field[0] = value;
5563 pat.field[3] = sign;
5564 switch (sep_by_space)
5565 {
5566 case 0: // No space separates the currency symbol and value.
5567 pat.field[1] = none;
5568 pat.field[2] = symbol;
5569 return;
5570 case 1: // Space between currency-and-sign or currency and value.
5571 if (!symbol_contains_sep) {
5572 // We insert the space into the symbol instead of
5573 // setting pat.field[1]=space so that when
5574 // showbase is not set, the space goes away too.
5575 __curr_symbol_.insert(0, 1, space_char);
5576 }
5577 pat.field[1] = none;
5578 pat.field[2] = symbol;
5579 return;
5580 case 2: // Space between sign and currency or value.
5581 pat.field[1] = symbol;
5582 pat.field[2] = space;
5583 if (symbol_contains_sep) {
5584 // Remove the separator from the symbol, since it
5585 // should not be removed if showbase is absent.
5586 __curr_symbol_.erase(__curr_symbol_.begin());
5587 }
5588 return;
5589 default:
5590 break;
5591 }
5592 break;
5593 case 3: // The sign string immediately precedes the currency symbol.
5594 pat.field[0] = value;
5595 pat.field[3] = symbol;
5596 switch (sep_by_space)
5597 {
5598 case 0: // No space separates the currency symbol and value.
5599 pat.field[1] = none;
5600 pat.field[2] = sign;
5601 return;
5602 case 1: // Space between currency-and-sign or currency and value.
5603 pat.field[1] = space;
5604 pat.field[2] = sign;
5605 if (symbol_contains_sep) {
5606 // Remove the separator from the symbol, since it
5607 // has already appeared before the sign.
5608 __curr_symbol_.erase(__curr_symbol_.begin());
5609 }
5610 return;
5611 case 2: // Space between sign and currency or value.
5612 pat.field[1] = sign;
5613 pat.field[2] = none;
5614 if (!symbol_contains_sep) {
5615 // We insert the space into the symbol instead of
5616 // setting pat.field[2]=space so that when
5617 // showbase is not set, the space goes away too.
5618 __curr_symbol_.insert(0, 1, space_char);
5619 }
5620 return;
5621 default:
5622 break;
5623 }
5624 break;
5625 case 4: // The sign string immediately succeeds the currency symbol.
5626 pat.field[0] = value;
5627 pat.field[3] = sign;
5628 switch (sep_by_space)
5629 {
5630 case 0: // No space separates the currency symbol and value.
5631 pat.field[1] = none;
5632 pat.field[2] = symbol;
5633 return;
5634 case 1: // Space between currency-and-sign or currency and value.
5635 pat.field[1] = none;
5636 pat.field[2] = symbol;
5637 if (!symbol_contains_sep) {
5638 // We insert the space into the symbol instead of
5639 // setting pat.field[1]=space so that when
5640 // showbase is not set, the space goes away too.
5641 __curr_symbol_.insert(0, 1, space_char);
5642 }
5643 return;
5644 case 2: // Space between sign and currency or value.
5645 pat.field[1] = symbol;
5646 pat.field[2] = space;
5647 if (symbol_contains_sep) {
5648 // Remove the separator from the symbol, since it
5649 // should not disappear when showbase is absent.
5650 __curr_symbol_.erase(__curr_symbol_.begin());
5651 }
5652 return;
5653 default:
5654 break;
5655 }
5656 break;
5657 default:
5658 break;
5659 }
5660 break;
5661 case 1: // curr_symbol before value
5662 switch (sign_posn)
5663 {
5664 case 0: // Parentheses surround the quantity and currency symbol.
5665 pat.field[0] = sign;
5666 pat.field[1] = symbol;
5667 pat.field[2] = none; // Any space appears in the symbol.
5668 pat.field[3] = value;
5669 switch (sep_by_space)
5670 {
5671 case 0: // No space separates the currency symbol and value.
5672 // This case may have changed between C99 and C11;
5673 // assume the currency symbol matches the intention.
5674 case 2: // Space between sign and currency or value.
5675 // The "sign" is two parentheses, so no space here either.
5676 return;
5677 case 1: // Space between currency-and-sign or currency and value.
5678 if (!symbol_contains_sep) {
5679 // We insert the space into the symbol instead of
5680 // setting pat.field[2]=space so that when
5681 // showbase is not set, the space goes away too.
5682 __curr_symbol_.insert(0, 1, space_char);
5683 }
5684 return;
5685 default:
5686 break;
5687 }
5688 break;
5689 case 1: // The sign string precedes the quantity and currency symbol.
5690 pat.field[0] = sign;
5691 pat.field[3] = value;
5692 switch (sep_by_space)
5693 {
5694 case 0: // No space separates the currency symbol and value.
5695 pat.field[1] = symbol;
5696 pat.field[2] = none;
5697 return;
5698 case 1: // Space between currency-and-sign or currency and value.
5699 pat.field[1] = symbol;
5700 pat.field[2] = none;
5701 if (!symbol_contains_sep) {
5702 // We insert the space into the symbol instead of
5703 // setting pat.field[2]=space so that when
5704 // showbase is not set, the space goes away too.
5705 __curr_symbol_.push_back(space_char);
5706 }
5707 return;
5708 case 2: // Space between sign and currency or value.
5709 pat.field[1] = space;
5710 pat.field[2] = symbol;
5711 if (symbol_contains_sep) {
5712 // Remove the separator from the symbol, since it
5713 // has already appeared after the sign.
5714 __curr_symbol_.pop_back();
5715 }
5716 return;
5717 default:
5718 break;
5719 }
5720 break;
5721 case 2: // The sign string succeeds the quantity and currency symbol.
5722 pat.field[0] = symbol;
5723 pat.field[3] = sign;
5724 switch (sep_by_space)
5725 {
5726 case 0: // No space separates the currency symbol and value.
5727 pat.field[1] = none;
5728 pat.field[2] = value;
5729 return;
5730 case 1: // Space between currency-and-sign or currency and value.
5731 pat.field[1] = none;
5732 pat.field[2] = value;
5733 if (!symbol_contains_sep) {
5734 // We insert the space into the symbol instead of
5735 // setting pat.field[1]=space so that when
5736 // showbase is not set, the space goes away too.
5737 __curr_symbol_.push_back(space_char);
5738 }
5739 return;
5740 case 2: // Space between sign and currency or value.
5741 pat.field[1] = value;
5742 pat.field[2] = space;
5743 if (symbol_contains_sep) {
5744 // Remove the separator from the symbol, since it
5745 // will appear before the sign.
5746 __curr_symbol_.pop_back();
5747 }
5748 return;
5749 default:
5750 break;
5751 }
5752 break;
5753 case 3: // The sign string immediately precedes the currency symbol.
5754 pat.field[0] = sign;
5755 pat.field[3] = value;
5756 switch (sep_by_space)
5757 {
5758 case 0: // No space separates the currency symbol and value.
5759 pat.field[1] = symbol;
5760 pat.field[2] = none;
5761 return;
5762 case 1: // Space between currency-and-sign or currency and value.
5763 pat.field[1] = symbol;
5764 pat.field[2] = none;
5765 if (!symbol_contains_sep) {
5766 // We insert the space into the symbol instead of
5767 // setting pat.field[2]=space so that when
5768 // showbase is not set, the space goes away too.
5769 __curr_symbol_.push_back(space_char);
5770 }
5771 return;
5772 case 2: // Space between sign and currency or value.
5773 pat.field[1] = space;
5774 pat.field[2] = symbol;
5775 if (symbol_contains_sep) {
5776 // Remove the separator from the symbol, since it
5777 // has already appeared after the sign.
5778 __curr_symbol_.pop_back();
5779 }
5780 return;
5781 default:
5782 break;
5783 }
5784 break;
5785 case 4: // The sign string immediately succeeds the currency symbol.
5786 pat.field[0] = symbol;
5787 pat.field[3] = value;
5788 switch (sep_by_space)
5789 {
5790 case 0: // No space separates the currency symbol and value.
5791 pat.field[1] = sign;
5792 pat.field[2] = none;
5793 return;
5794 case 1: // Space between currency-and-sign or currency and value.
5795 pat.field[1] = sign;
5796 pat.field[2] = space;
5797 if (symbol_contains_sep) {
5798 // Remove the separator from the symbol, since it
5799 // should not disappear when showbase is absent.
5800 __curr_symbol_.pop_back();
5801 }
5802 return;
5803 case 2: // Space between sign and currency or value.
5804 pat.field[1] = none;
5805 pat.field[2] = sign;
5806 if (!symbol_contains_sep) {
5807 // We insert the space into the symbol instead of
5808 // setting pat.field[1]=space so that when
5809 // showbase is not set, the space goes away too.
5810 __curr_symbol_.push_back(space_char);
5811 }
5812 return;
5813 default:
5814 break;
5815 }
5816 break;
5817 default:
5818 break;
5819 }
5820 break;
5821 default:
5822 break;
5823 }
5824 pat.field[0] = symbol;
5825 pat.field[1] = sign;
5826 pat.field[2] = none;
5827 pat.field[3] = value;
5828}
5829
5830template<>
5831void
5832moneypunct_byname<char, false>::init(const char* nm)
5833{
5834 typedef moneypunct<char, false> base;
5835 __libcpp_unique_locale loc(nm);
5836 if (!loc)
5837 __throw_runtime_error("moneypunct_byname"
5838 " failed to construct for " + string(nm));
5839
5840 lconv* lc = __libcpp_localeconv_l(loc.get());
5841 if (!checked_string_to_char_convert(__decimal_point_,
5842 lc->mon_decimal_point,
5843 loc.get()))
5844 __decimal_point_ = base::do_decimal_point();
5845 if (!checked_string_to_char_convert(__thousands_sep_,
5846 lc->mon_thousands_sep,
5847 loc.get()))
5848 __thousands_sep_ = base::do_thousands_sep();
5849
5850 __grouping_ = lc->mon_grouping;
5851 __curr_symbol_ = lc->currency_symbol;
5852 if (lc->frac_digits != CHAR_MAX)
5853 __frac_digits_ = lc->frac_digits;
5854 else
5855 __frac_digits_ = base::do_frac_digits();
5856 if (lc->p_sign_posn == 0)
5857 __positive_sign_ = "()";
5858 else
5859 __positive_sign_ = lc->positive_sign;
5860 if (lc->n_sign_posn == 0)
5861 __negative_sign_ = "()";
5862 else
5863 __negative_sign_ = lc->negative_sign;
5864 // Assume the positive and negative formats will want spaces in
5865 // the same places in curr_symbol since there's no way to
5866 // represent anything else.
5867 string_type __dummy_curr_symbol = __curr_symbol_;
5868 __init_pat(__pos_format_, __dummy_curr_symbol, false,
5869 lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
5870 __init_pat(__neg_format_, __curr_symbol_, false,
5871 lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
5872}
5873
5874template<>
5875void
5876moneypunct_byname<char, true>::init(const char* nm)
5877{
5878 typedef moneypunct<char, true> base;
5879 __libcpp_unique_locale loc(nm);
5880 if (!loc)
5881 __throw_runtime_error("moneypunct_byname"
5882 " failed to construct for " + string(nm));
5883
5884 lconv* lc = __libcpp_localeconv_l(loc.get());
5885 if (!checked_string_to_char_convert(__decimal_point_,
5886 lc->mon_decimal_point,
5887 loc.get()))
5888 __decimal_point_ = base::do_decimal_point();
5889 if (!checked_string_to_char_convert(__thousands_sep_,
5890 lc->mon_thousands_sep,
5891 loc.get()))
5892 __thousands_sep_ = base::do_thousands_sep();
5893 __grouping_ = lc->mon_grouping;
5894 __curr_symbol_ = lc->int_curr_symbol;
5895 if (lc->int_frac_digits != CHAR_MAX)
5896 __frac_digits_ = lc->int_frac_digits;
5897 else
5898 __frac_digits_ = base::do_frac_digits();
5899#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
5900 if (lc->p_sign_posn == 0)
5901#else // _LIBCPP_MSVCRT
5902 if (lc->int_p_sign_posn == 0)
5903#endif // !_LIBCPP_MSVCRT
5904 __positive_sign_ = "()";
5905 else
5906 __positive_sign_ = lc->positive_sign;
5907#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
5908 if(lc->n_sign_posn == 0)
5909#else // _LIBCPP_MSVCRT
5910 if (lc->int_n_sign_posn == 0)
5911#endif // !_LIBCPP_MSVCRT
5912 __negative_sign_ = "()";
5913 else
5914 __negative_sign_ = lc->negative_sign;
5915 // Assume the positive and negative formats will want spaces in
5916 // the same places in curr_symbol since there's no way to
5917 // represent anything else.
5918 string_type __dummy_curr_symbol = __curr_symbol_;
5919#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
5920 __init_pat(__pos_format_, __dummy_curr_symbol, true,
5921 lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
5922 __init_pat(__neg_format_, __curr_symbol_, true,
5923 lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
5924#else // _LIBCPP_MSVCRT
5925 __init_pat(__pos_format_, __dummy_curr_symbol, true,
5926 lc->int_p_cs_precedes, lc->int_p_sep_by_space,
5927 lc->int_p_sign_posn, ' ');
5928 __init_pat(__neg_format_, __curr_symbol_, true,
5929 lc->int_n_cs_precedes, lc->int_n_sep_by_space,
5930 lc->int_n_sign_posn, ' ');
5931#endif // !_LIBCPP_MSVCRT
5932}
5933
5934template<>
5935void
5936moneypunct_byname<wchar_t, false>::init(const char* nm)
5937{
5938 typedef moneypunct<wchar_t, false> base;
5939 __libcpp_unique_locale loc(nm);
5940 if (!loc)
5941 __throw_runtime_error("moneypunct_byname"
5942 " failed to construct for " + string(nm));
5943 lconv* lc = __libcpp_localeconv_l(loc.get());
5944 if (!checked_string_to_wchar_convert(__decimal_point_,
5945 lc->mon_decimal_point,
5946 loc.get()))
5947 __decimal_point_ = base::do_decimal_point();
5948 if (!checked_string_to_wchar_convert(__thousands_sep_,
5949 lc->mon_thousands_sep,
5950 loc.get()))
5951 __thousands_sep_ = base::do_thousands_sep();
5952 __grouping_ = lc->mon_grouping;
5953 wchar_t wbuf[100];
5954 mbstate_t mb = {0};
5955 const char* bb = lc->currency_symbol;
5956 size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
5957 if (j == size_t(-1))
5958 __throw_runtime_error("locale not supported");
5959 wchar_t* wbe = wbuf + j;
5960 __curr_symbol_.assign(wbuf, wbe);
5961 if (lc->frac_digits != CHAR_MAX)
5962 __frac_digits_ = lc->frac_digits;
5963 else
5964 __frac_digits_ = base::do_frac_digits();
5965 if (lc->p_sign_posn == 0)
5966 __positive_sign_ = L"()";
5967 else
5968 {
5969 mb = mbstate_t();
5970 bb = lc->positive_sign;
5971 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
5972 if (j == size_t(-1))
5973 __throw_runtime_error("locale not supported");
5974 wbe = wbuf + j;
5975 __positive_sign_.assign(wbuf, wbe);
5976 }
5977 if (lc->n_sign_posn == 0)
5978 __negative_sign_ = L"()";
5979 else
5980 {
5981 mb = mbstate_t();
5982 bb = lc->negative_sign;
5983 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
5984 if (j == size_t(-1))
5985 __throw_runtime_error("locale not supported");
5986 wbe = wbuf + j;
5987 __negative_sign_.assign(wbuf, wbe);
5988 }
5989 // Assume the positive and negative formats will want spaces in
5990 // the same places in curr_symbol since there's no way to
5991 // represent anything else.
5992 string_type __dummy_curr_symbol = __curr_symbol_;
5993 __init_pat(__pos_format_, __dummy_curr_symbol, false,
5994 lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
5995 __init_pat(__neg_format_, __curr_symbol_, false,
5996 lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
5997}
5998
5999template<>
6000void
6001moneypunct_byname<wchar_t, true>::init(const char* nm)
6002{
6003 typedef moneypunct<wchar_t, true> base;
6004 __libcpp_unique_locale loc(nm);
6005 if (!loc)
6006 __throw_runtime_error("moneypunct_byname"
6007 " failed to construct for " + string(nm));
6008
6009 lconv* lc = __libcpp_localeconv_l(loc.get());
6010 if (!checked_string_to_wchar_convert(__decimal_point_,
6011 lc->mon_decimal_point,
6012 loc.get()))
6013 __decimal_point_ = base::do_decimal_point();
6014 if (!checked_string_to_wchar_convert(__thousands_sep_,
6015 lc->mon_thousands_sep,
6016 loc.get()))
6017 __thousands_sep_ = base::do_thousands_sep();
6018 __grouping_ = lc->mon_grouping;
6019 wchar_t wbuf[100];
6020 mbstate_t mb = {0};
6021 const char* bb = lc->int_curr_symbol;
6022 size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
6023 if (j == size_t(-1))
6024 __throw_runtime_error("locale not supported");
6025 wchar_t* wbe = wbuf + j;
6026 __curr_symbol_.assign(wbuf, wbe);
6027 if (lc->int_frac_digits != CHAR_MAX)
6028 __frac_digits_ = lc->int_frac_digits;
6029 else
6030 __frac_digits_ = base::do_frac_digits();
6031#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
6032 if (lc->p_sign_posn == 0)
6033#else // _LIBCPP_MSVCRT
6034 if (lc->int_p_sign_posn == 0)
6035#endif // !_LIBCPP_MSVCRT
6036 __positive_sign_ = L"()";
6037 else
6038 {
6039 mb = mbstate_t();
6040 bb = lc->positive_sign;
6041 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
6042 if (j == size_t(-1))
6043 __throw_runtime_error("locale not supported");
6044 wbe = wbuf + j;
6045 __positive_sign_.assign(wbuf, wbe);
6046 }
6047#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
6048 if (lc->n_sign_posn == 0)
6049#else // _LIBCPP_MSVCRT
6050 if (lc->int_n_sign_posn == 0)
6051#endif // !_LIBCPP_MSVCRT
6052 __negative_sign_ = L"()";
6053 else
6054 {
6055 mb = mbstate_t();
6056 bb = lc->negative_sign;
6057 j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
6058 if (j == size_t(-1))
6059 __throw_runtime_error("locale not supported");
6060 wbe = wbuf + j;
6061 __negative_sign_.assign(wbuf, wbe);
6062 }
6063 // Assume the positive and negative formats will want spaces in
6064 // the same places in curr_symbol since there's no way to
6065 // represent anything else.
6066 string_type __dummy_curr_symbol = __curr_symbol_;
6067#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
6068 __init_pat(__pos_format_, __dummy_curr_symbol, true,
6069 lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
6070 __init_pat(__neg_format_, __curr_symbol_, true,
6071 lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
6072#else // _LIBCPP_MSVCRT
6073 __init_pat(__pos_format_, __dummy_curr_symbol, true,
6074 lc->int_p_cs_precedes, lc->int_p_sep_by_space,
6075 lc->int_p_sign_posn, L' ');
6076 __init_pat(__neg_format_, __curr_symbol_, true,
6077 lc->int_n_cs_precedes, lc->int_n_sep_by_space,
6078 lc->int_n_sign_posn, L' ');
6079#endif // !_LIBCPP_MSVCRT
6080}
6081
6082void __do_nothing(void*) {}
6083
6084void __throw_runtime_error(const char* msg)
6085{
6086#ifndef _LIBCPP_NO_EXCEPTIONS
6087 throw runtime_error(msg);
6088#else
6089 (void)msg;
6090 _VSTD::abort();
6091#endif
6092}
6093
6094template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
6095template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;
6096
6097template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
6098template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;
6099
6100template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
6101template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;
6102
6103template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
6104template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;
6105
6106template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
6107template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;
6108
6109template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
6110template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;
6111
6112template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
6113template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;
6114
6115template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
6116template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;
6117
6118template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
6119template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;
6120
6121template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
6122template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
6123template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;
6124template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;
6125
6126template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
6127template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
6128template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;
6129template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;
6130
6131template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
6132template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;
6133
6134template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
6135template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;
6136
6137template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
6138template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;
6139
6140template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
6141template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;
6142
6143template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
6144template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;
6145
6146template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
6147template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;
6148
6149template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
6150template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;
6151template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
6152template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
6153
6154_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/memory.cpp created+237
...@@ -0,0 +1,237 @@
1//===------------------------ memory.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "memory"
10#ifndef _LIBCPP_HAS_NO_THREADS
11#include "mutex"
12#include "thread"
13#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
14#pragma comment(lib, "pthread")
15#endif
16#endif
17#include "include/atomic_support.h"
18
19_LIBCPP_BEGIN_NAMESPACE_STD
20
21const allocator_arg_t allocator_arg = allocator_arg_t();
22
23bad_weak_ptr::~bad_weak_ptr() _NOEXCEPT {}
24
25const char*
26bad_weak_ptr::what() const _NOEXCEPT
27{
28 return "bad_weak_ptr";
29}
30
31__shared_count::~__shared_count()
32{
33}
34
35__shared_weak_count::~__shared_weak_count()
36{
37}
38
39#if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
40void
41__shared_count::__add_shared() _NOEXCEPT
42{
43 __libcpp_atomic_refcount_increment(__shared_owners_);
44}
45
46bool
47__shared_count::__release_shared() _NOEXCEPT
48{
49 if (__libcpp_atomic_refcount_decrement(__shared_owners_) == -1)
50 {
51 __on_zero_shared();
52 return true;
53 }
54 return false;
55}
56
57void
58__shared_weak_count::__add_shared() _NOEXCEPT
59{
60 __shared_count::__add_shared();
61}
62
63void
64__shared_weak_count::__add_weak() _NOEXCEPT
65{
66 __libcpp_atomic_refcount_increment(__shared_weak_owners_);
67}
68
69void
70__shared_weak_count::__release_shared() _NOEXCEPT
71{
72 if (__shared_count::__release_shared())
73 __release_weak();
74}
75
76#endif // _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
77
78void
79__shared_weak_count::__release_weak() _NOEXCEPT
80{
81 // NOTE: The acquire load here is an optimization of the very
82 // common case where a shared pointer is being destructed while
83 // having no other contended references.
84 //
85 // BENEFIT: We avoid expensive atomic stores like XADD and STREX
86 // in a common case. Those instructions are slow and do nasty
87 // things to caches.
88 //
89 // IS THIS SAFE? Yes. During weak destruction, if we see that we
90 // are the last reference, we know that no-one else is accessing
91 // us. If someone were accessing us, then they would be doing so
92 // while the last shared / weak_ptr was being destructed, and
93 // that's undefined anyway.
94 //
95 // If we see anything other than a 0, then we have possible
96 // contention, and need to use an atomicrmw primitive.
97 // The same arguments don't apply for increment, where it is legal
98 // (though inadvisable) to share shared_ptr references between
99 // threads, and have them all get copied at once. The argument
100 // also doesn't apply for __release_shared, because an outstanding
101 // weak_ptr::lock() could read / modify the shared count.
102 if (__libcpp_atomic_load(&__shared_weak_owners_, _AO_Acquire) == 0)
103 {
104 // no need to do this store, because we are about
105 // to destroy everything.
106 //__libcpp_atomic_store(&__shared_weak_owners_, -1, _AO_Release);
107 __on_zero_shared_weak();
108 }
109 else if (__libcpp_atomic_refcount_decrement(__shared_weak_owners_) == -1)
110 __on_zero_shared_weak();
111}
112
113__shared_weak_count*
114__shared_weak_count::lock() _NOEXCEPT
115{
116 long object_owners = __libcpp_atomic_load(&__shared_owners_);
117 while (object_owners != -1)
118 {
119 if (__libcpp_atomic_compare_exchange(&__shared_owners_,
120 &object_owners,
121 object_owners+1))
122 return this;
123 }
124 return nullptr;
125}
126
127#if !defined(_LIBCPP_NO_RTTI) || !defined(_LIBCPP_BUILD_STATIC)
128
129const void*
130__shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT
131{
132 return nullptr;
133}
134
135#endif // _LIBCPP_NO_RTTI
136
137#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
138
139_LIBCPP_SAFE_STATIC static const std::size_t __sp_mut_count = 16;
140_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut_back[__sp_mut_count] =
141{
142 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
143 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
144 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER,
145 _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER
146};
147
148_LIBCPP_CONSTEXPR __sp_mut::__sp_mut(void* p) _NOEXCEPT
149 : __lx(p)
150{
151}
152
153void
154__sp_mut::lock() _NOEXCEPT
155{
156 auto m = static_cast<__libcpp_mutex_t*>(__lx);
157 unsigned count = 0;
158 while (!__libcpp_mutex_trylock(m))
159 {
160 if (++count > 16)
161 {
162 __libcpp_mutex_lock(m);
163 break;
164 }
165 this_thread::yield();
166 }
167}
168
169void
170__sp_mut::unlock() _NOEXCEPT
171{
172 __libcpp_mutex_unlock(static_cast<__libcpp_mutex_t*>(__lx));
173}
174
175__sp_mut&
176__get_sp_mut(const void* p)
177{
178 static __sp_mut muts[__sp_mut_count]
179 {
180 &mut_back[ 0], &mut_back[ 1], &mut_back[ 2], &mut_back[ 3],
181 &mut_back[ 4], &mut_back[ 5], &mut_back[ 6], &mut_back[ 7],
182 &mut_back[ 8], &mut_back[ 9], &mut_back[10], &mut_back[11],
183 &mut_back[12], &mut_back[13], &mut_back[14], &mut_back[15]
184 };
185 return muts[hash<const void*>()(p) & (__sp_mut_count-1)];
186}
187
188#endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
189
190void
191declare_reachable(void*)
192{
193}
194
195void
196declare_no_pointers(char*, size_t)
197{
198}
199
200void
201undeclare_no_pointers(char*, size_t)
202{
203}
204
205#if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE)
206pointer_safety get_pointer_safety() _NOEXCEPT
207{
208 return pointer_safety::relaxed;
209}
210#endif
211
212void*
213__undeclare_reachable(void* p)
214{
215 return p;
216}
217
218void*
219align(size_t alignment, size_t size, void*& ptr, size_t& space)
220{
221 void* r = nullptr;
222 if (size <= space)
223 {
224 char* p1 = static_cast<char*>(ptr);
225 char* p2 = reinterpret_cast<char*>(reinterpret_cast<size_t>(p1 + (alignment - 1)) & -alignment);
226 size_t d = static_cast<size_t>(p2 - p1);
227 if (d <= space - size)
228 {
229 r = p2;
230 ptr = r;
231 space -= d;
232 }
233 }
234 return r;
235}
236
237_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/mutex.cpp created+260
...@@ -0,0 +1,260 @@
1//===------------------------- mutex.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "mutex"
10#include "limits"
11#include "system_error"
12#include "include/atomic_support.h"
13#include "__undef_macros"
14
15#ifndef _LIBCPP_HAS_NO_THREADS
16#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
17#pragma comment(lib, "pthread")
18#endif
19#endif
20
21_LIBCPP_BEGIN_NAMESPACE_STD
22#ifndef _LIBCPP_HAS_NO_THREADS
23
24const defer_lock_t defer_lock{};
25const try_to_lock_t try_to_lock{};
26const adopt_lock_t adopt_lock{};
27
28// ~mutex is defined elsewhere
29
30void
31mutex::lock()
32{
33 int ec = __libcpp_mutex_lock(&__m_);
34 if (ec)
35 __throw_system_error(ec, "mutex lock failed");
36}
37
38bool
39mutex::try_lock() _NOEXCEPT
40{
41 return __libcpp_mutex_trylock(&__m_);
42}
43
44void
45mutex::unlock() _NOEXCEPT
46{
47 int ec = __libcpp_mutex_unlock(&__m_);
48 (void)ec;
49 _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
50}
51
52// recursive_mutex
53
54recursive_mutex::recursive_mutex()
55{
56 int ec = __libcpp_recursive_mutex_init(&__m_);
57 if (ec)
58 __throw_system_error(ec, "recursive_mutex constructor failed");
59}
60
61recursive_mutex::~recursive_mutex()
62{
63 int e = __libcpp_recursive_mutex_destroy(&__m_);
64 (void)e;
65 _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
66}
67
68void
69recursive_mutex::lock()
70{
71 int ec = __libcpp_recursive_mutex_lock(&__m_);
72 if (ec)
73 __throw_system_error(ec, "recursive_mutex lock failed");
74}
75
76void
77recursive_mutex::unlock() _NOEXCEPT
78{
79 int e = __libcpp_recursive_mutex_unlock(&__m_);
80 (void)e;
81 _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
82}
83
84bool
85recursive_mutex::try_lock() _NOEXCEPT
86{
87 return __libcpp_recursive_mutex_trylock(&__m_);
88}
89
90// timed_mutex
91
92timed_mutex::timed_mutex()
93 : __locked_(false)
94{
95}
96
97timed_mutex::~timed_mutex()
98{
99 lock_guard<mutex> _(__m_);
100}
101
102void
103timed_mutex::lock()
104{
105 unique_lock<mutex> lk(__m_);
106 while (__locked_)
107 __cv_.wait(lk);
108 __locked_ = true;
109}
110
111bool
112timed_mutex::try_lock() _NOEXCEPT
113{
114 unique_lock<mutex> lk(__m_, try_to_lock);
115 if (lk.owns_lock() && !__locked_)
116 {
117 __locked_ = true;
118 return true;
119 }
120 return false;
121}
122
123void
124timed_mutex::unlock() _NOEXCEPT
125{
126 lock_guard<mutex> _(__m_);
127 __locked_ = false;
128 __cv_.notify_one();
129}
130
131// recursive_timed_mutex
132
133recursive_timed_mutex::recursive_timed_mutex()
134 : __count_(0),
135 __id_{}
136{
137}
138
139recursive_timed_mutex::~recursive_timed_mutex()
140{
141 lock_guard<mutex> _(__m_);
142}
143
144void
145recursive_timed_mutex::lock()
146{
147 __thread_id id = this_thread::get_id();
148 unique_lock<mutex> lk(__m_);
149 if (id ==__id_)
150 {
151 if (__count_ == numeric_limits<size_t>::max())
152 __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
153 ++__count_;
154 return;
155 }
156 while (__count_ != 0)
157 __cv_.wait(lk);
158 __count_ = 1;
159 __id_ = id;
160}
161
162bool
163recursive_timed_mutex::try_lock() _NOEXCEPT
164{
165 __thread_id id = this_thread::get_id();
166 unique_lock<mutex> lk(__m_, try_to_lock);
167 if (lk.owns_lock() && (__count_ == 0 || id == __id_))
168 {
169 if (__count_ == numeric_limits<size_t>::max())
170 return false;
171 ++__count_;
172 __id_ = id;
173 return true;
174 }
175 return false;
176}
177
178void
179recursive_timed_mutex::unlock() _NOEXCEPT
180{
181 unique_lock<mutex> lk(__m_);
182 if (--__count_ == 0)
183 {
184 __id_.__reset();
185 lk.unlock();
186 __cv_.notify_one();
187 }
188}
189
190#endif // !_LIBCPP_HAS_NO_THREADS
191
192// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
193// without illegal macros (unexpected macros not beginning with _UpperCase or
194// __lowercase), and if it stops spinning waiting threads, then call_once should
195// call into dispatch_once_f instead of here. Relevant radar this code needs to
196// keep in sync with: 7741191.
197
198#ifndef _LIBCPP_HAS_NO_THREADS
199_LIBCPP_SAFE_STATIC static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
200_LIBCPP_SAFE_STATIC static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
201#endif
202
203void __call_once(volatile once_flag::_State_type& flag, void* arg,
204 void (*func)(void*))
205{
206#if defined(_LIBCPP_HAS_NO_THREADS)
207 if (flag == 0)
208 {
209#ifndef _LIBCPP_NO_EXCEPTIONS
210 try
211 {
212#endif // _LIBCPP_NO_EXCEPTIONS
213 flag = 1;
214 func(arg);
215 flag = ~once_flag::_State_type(0);
216#ifndef _LIBCPP_NO_EXCEPTIONS
217 }
218 catch (...)
219 {
220 flag = 0;
221 throw;
222 }
223#endif // _LIBCPP_NO_EXCEPTIONS
224 }
225#else // !_LIBCPP_HAS_NO_THREADS
226 __libcpp_mutex_lock(&mut);
227 while (flag == 1)
228 __libcpp_condvar_wait(&cv, &mut);
229 if (flag == 0)
230 {
231#ifndef _LIBCPP_NO_EXCEPTIONS
232 try
233 {
234#endif // _LIBCPP_NO_EXCEPTIONS
235 __libcpp_relaxed_store(&flag, once_flag::_State_type(1));
236 __libcpp_mutex_unlock(&mut);
237 func(arg);
238 __libcpp_mutex_lock(&mut);
239 __libcpp_atomic_store(&flag, ~once_flag::_State_type(0),
240 _AO_Release);
241 __libcpp_mutex_unlock(&mut);
242 __libcpp_condvar_broadcast(&cv);
243#ifndef _LIBCPP_NO_EXCEPTIONS
244 }
245 catch (...)
246 {
247 __libcpp_mutex_lock(&mut);
248 __libcpp_relaxed_store(&flag, once_flag::_State_type(0));
249 __libcpp_mutex_unlock(&mut);
250 __libcpp_condvar_broadcast(&cv);
251 throw;
252 }
253#endif // _LIBCPP_NO_EXCEPTIONS
254 }
255 else
256 __libcpp_mutex_unlock(&mut);
257#endif // !_LIBCPP_HAS_NO_THREADS
258}
259
260_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/mutex_destructor.cpp created+50
...@@ -0,0 +1,50 @@
1//===--------------------- mutex_destructor.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Define ~mutex.
10//
11// On some platforms ~mutex has been made trivial and the definition is only
12// provided for ABI compatibility.
13//
14// In order to avoid ODR violations within libc++ itself, we need to ensure
15// that *nothing* sees the non-trivial mutex declaration. For this reason
16// we re-declare the entire class in this file instead of using
17// _LIBCPP_BUILDING_LIBRARY to change the definition in the headers.
18
19#include "__config"
20#include "__threading_support"
21
22#if !defined(_LIBCPP_HAS_NO_THREADS)
23#if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION)
24#define NEEDS_MUTEX_DESTRUCTOR
25#endif
26#endif
27
28_LIBCPP_BEGIN_NAMESPACE_STD
29
30#ifdef NEEDS_MUTEX_DESTRUCTOR
31class _LIBCPP_TYPE_VIS mutex
32{
33 __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;
34
35public:
36 _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY
37 constexpr mutex() = default;
38 mutex(const mutex&) = delete;
39 mutex& operator=(const mutex&) = delete;
40 ~mutex() noexcept;
41};
42
43
44mutex::~mutex() _NOEXCEPT
45{
46 __libcpp_mutex_destroy(&__m_);
47}
48
49#endif // !_LIBCPP_HAS_NO_THREADS
50_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/new.cpp created+297
...@@ -0,0 +1,297 @@
1//===--------------------------- new.cpp ----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <stdlib.h>
10
11#include "new"
12#include "include/atomic_support.h"
13
14#if defined(_LIBCPP_ABI_MICROSOFT)
15# if !defined(_LIBCPP_ABI_VCRUNTIME)
16# include "support/runtime/new_handler_fallback.ipp"
17# endif
18#elif defined(LIBCXX_BUILDING_LIBCXXABI)
19# include <cxxabi.h>
20#elif defined(LIBCXXRT)
21# include <cxxabi.h>
22# include "support/runtime/new_handler_fallback.ipp"
23#elif defined(__GLIBCXX__)
24 // nothing to do
25#else
26# include "support/runtime/new_handler_fallback.ipp"
27#endif
28
29namespace std
30{
31
32#ifndef __GLIBCXX__
33const nothrow_t nothrow{};
34#endif
35
36#ifndef LIBSTDCXX
37
38void
39__throw_bad_alloc()
40{
41#ifndef _LIBCPP_NO_EXCEPTIONS
42 throw bad_alloc();
43#else
44 _VSTD::abort();
45#endif
46}
47
48#endif // !LIBSTDCXX
49
50} // std
51
52#if !defined(__GLIBCXX__) && \
53 !defined(_LIBCPP_ABI_VCRUNTIME) && \
54 !defined(_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS)
55
56// Implement all new and delete operators as weak definitions
57// in this shared library, so that they can be overridden by programs
58// that define non-weak copies of the functions.
59
60_LIBCPP_WEAK
61void *
62operator new(std::size_t size) _THROW_BAD_ALLOC
63{
64 if (size == 0)
65 size = 1;
66 void* p;
67 while ((p = ::malloc(size)) == 0)
68 {
69 // If malloc fails and there is a new_handler,
70 // call it to try free up memory.
71 std::new_handler nh = std::get_new_handler();
72 if (nh)
73 nh();
74 else
75#ifndef _LIBCPP_NO_EXCEPTIONS
76 throw std::bad_alloc();
77#else
78 break;
79#endif
80 }
81 return p;
82}
83
84_LIBCPP_WEAK
85void*
86operator new(size_t size, const std::nothrow_t&) _NOEXCEPT
87{
88 void* p = 0;
89#ifndef _LIBCPP_NO_EXCEPTIONS
90 try
91 {
92#endif // _LIBCPP_NO_EXCEPTIONS
93 p = ::operator new(size);
94#ifndef _LIBCPP_NO_EXCEPTIONS
95 }
96 catch (...)
97 {
98 }
99#endif // _LIBCPP_NO_EXCEPTIONS
100 return p;
101}
102
103_LIBCPP_WEAK
104void*
105operator new[](size_t size) _THROW_BAD_ALLOC
106{
107 return ::operator new(size);
108}
109
110_LIBCPP_WEAK
111void*
112operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT
113{
114 void* p = 0;
115#ifndef _LIBCPP_NO_EXCEPTIONS
116 try
117 {
118#endif // _LIBCPP_NO_EXCEPTIONS
119 p = ::operator new[](size);
120#ifndef _LIBCPP_NO_EXCEPTIONS
121 }
122 catch (...)
123 {
124 }
125#endif // _LIBCPP_NO_EXCEPTIONS
126 return p;
127}
128
129_LIBCPP_WEAK
130void
131operator delete(void* ptr) _NOEXCEPT
132{
133 ::free(ptr);
134}
135
136_LIBCPP_WEAK
137void
138operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT
139{
140 ::operator delete(ptr);
141}
142
143_LIBCPP_WEAK
144void
145operator delete(void* ptr, size_t) _NOEXCEPT
146{
147 ::operator delete(ptr);
148}
149
150_LIBCPP_WEAK
151void
152operator delete[] (void* ptr) _NOEXCEPT
153{
154 ::operator delete(ptr);
155}
156
157_LIBCPP_WEAK
158void
159operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT
160{
161 ::operator delete[](ptr);
162}
163
164_LIBCPP_WEAK
165void
166operator delete[] (void* ptr, size_t) _NOEXCEPT
167{
168 ::operator delete[](ptr);
169}
170
171#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
172
173_LIBCPP_WEAK
174void *
175operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
176{
177 if (size == 0)
178 size = 1;
179 if (static_cast<size_t>(alignment) < sizeof(void*))
180 alignment = std::align_val_t(sizeof(void*));
181 void* p;
182#if defined(_LIBCPP_MSVCRT_LIKE)
183 while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr)
184#else
185 while (::posix_memalign(&p, static_cast<size_t>(alignment), size) != 0)
186#endif
187 {
188 // If posix_memalign fails and there is a new_handler,
189 // call it to try free up memory.
190 std::new_handler nh = std::get_new_handler();
191 if (nh)
192 nh();
193 else {
194#ifndef _LIBCPP_NO_EXCEPTIONS
195 throw std::bad_alloc();
196#else
197 p = nullptr; // posix_memalign doesn't initialize 'p' on failure
198 break;
199#endif
200 }
201 }
202 return p;
203}
204
205_LIBCPP_WEAK
206void*
207operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
208{
209 void* p = 0;
210#ifndef _LIBCPP_NO_EXCEPTIONS
211 try
212 {
213#endif // _LIBCPP_NO_EXCEPTIONS
214 p = ::operator new(size, alignment);
215#ifndef _LIBCPP_NO_EXCEPTIONS
216 }
217 catch (...)
218 {
219 }
220#endif // _LIBCPP_NO_EXCEPTIONS
221 return p;
222}
223
224_LIBCPP_WEAK
225void*
226operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
227{
228 return ::operator new(size, alignment);
229}
230
231_LIBCPP_WEAK
232void*
233operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
234{
235 void* p = 0;
236#ifndef _LIBCPP_NO_EXCEPTIONS
237 try
238 {
239#endif // _LIBCPP_NO_EXCEPTIONS
240 p = ::operator new[](size, alignment);
241#ifndef _LIBCPP_NO_EXCEPTIONS
242 }
243 catch (...)
244 {
245 }
246#endif // _LIBCPP_NO_EXCEPTIONS
247 return p;
248}
249
250_LIBCPP_WEAK
251void
252operator delete(void* ptr, std::align_val_t) _NOEXCEPT
253{
254#if defined(_LIBCPP_MSVCRT_LIKE)
255 ::_aligned_free(ptr);
256#else
257 ::free(ptr);
258#endif
259}
260
261_LIBCPP_WEAK
262void
263operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
264{
265 ::operator delete(ptr, alignment);
266}
267
268_LIBCPP_WEAK
269void
270operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
271{
272 ::operator delete(ptr, alignment);
273}
274
275_LIBCPP_WEAK
276void
277operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT
278{
279 ::operator delete(ptr, alignment);
280}
281
282_LIBCPP_WEAK
283void
284operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT
285{
286 ::operator delete[](ptr, alignment);
287}
288
289_LIBCPP_WEAK
290void
291operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
292{
293 ::operator delete[](ptr, alignment);
294}
295
296#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
297#endif // !__GLIBCXX__ && !_LIBCPP_ABI_VCRUNTIME && !_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS
lib/libcxx/src/optional.cpp created+41
...@@ -0,0 +1,41 @@
1//===------------------------ optional.cpp --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "optional"
10
11namespace std
12{
13
14bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
15
16const char* bad_optional_access::what() const _NOEXCEPT {
17 return "bad_optional_access";
18 }
19
20} // std
21
22
23#include <experimental/__config>
24
25// Preserve std::experimental::bad_optional_access for ABI compatibility
26// Even though it no longer exists in a header file
27_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
28
29class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS bad_optional_access
30 : public std::logic_error
31{
32public:
33 bad_optional_access() : std::logic_error("Bad optional Access") {}
34
35// Get the key function ~bad_optional_access() into the dylib
36 virtual ~bad_optional_access() _NOEXCEPT;
37};
38
39bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
40
41_LIBCPP_END_NAMESPACE_EXPERIMENTAL
lib/libcxx/src/random.cpp created+178
...@@ -0,0 +1,178 @@
1//===-------------------------- random.cpp --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <__config>
10
11#if defined(_LIBCPP_USING_WIN32_RANDOM)
12// Must be defined before including stdlib.h to enable rand_s().
13#define _CRT_RAND_S
14#endif // defined(_LIBCPP_USING_WIN32_RANDOM)
15
16#include "random"
17#include "system_error"
18
19#if defined(__sun__)
20#define rename solaris_headers_are_broken
21#endif // defined(__sun__)
22
23#include <errno.h>
24#include <stdio.h>
25#include <stdlib.h>
26
27#if defined(_LIBCPP_USING_GETENTROPY)
28#include <sys/random.h>
29#elif defined(_LIBCPP_USING_DEV_RANDOM)
30#include <fcntl.h>
31#include <unistd.h>
32#elif defined(_LIBCPP_USING_NACL_RANDOM)
33#include <nacl/nacl_random.h>
34#endif
35
36
37_LIBCPP_BEGIN_NAMESPACE_STD
38
39#if defined(_LIBCPP_USING_GETENTROPY)
40
41random_device::random_device(const string& __token)
42{
43 if (__token != "/dev/urandom")
44 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
45}
46
47random_device::~random_device()
48{
49}
50
51unsigned
52random_device::operator()()
53{
54 unsigned r;
55 size_t n = sizeof(r);
56 int err = getentropy(&r, n);
57 if (err)
58 __throw_system_error(errno, "random_device getentropy failed");
59 return r;
60}
61
62#elif defined(_LIBCPP_USING_ARC4_RANDOM)
63
64random_device::random_device(const string& __token)
65{
66 if (__token != "/dev/urandom")
67 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
68}
69
70random_device::~random_device()
71{
72}
73
74unsigned
75random_device::operator()()
76{
77 return arc4random();
78}
79
80#elif defined(_LIBCPP_USING_DEV_RANDOM)
81
82random_device::random_device(const string& __token)
83 : __f_(open(__token.c_str(), O_RDONLY))
84{
85 if (__f_ < 0)
86 __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
87}
88
89random_device::~random_device()
90{
91 close(__f_);
92}
93
94unsigned
95random_device::operator()()
96{
97 unsigned r;
98 size_t n = sizeof(r);
99 char* p = reinterpret_cast<char*>(&r);
100 while (n > 0)
101 {
102 ssize_t s = read(__f_, p, n);
103 if (s == 0)
104 __throw_system_error(ENODATA, "random_device got EOF");
105 if (s == -1)
106 {
107 if (errno != EINTR)
108 __throw_system_error(errno, "random_device got an unexpected error");
109 continue;
110 }
111 n -= static_cast<size_t>(s);
112 p += static_cast<size_t>(s);
113 }
114 return r;
115}
116
117#elif defined(_LIBCPP_USING_NACL_RANDOM)
118
119random_device::random_device(const string& __token)
120{
121 if (__token != "/dev/urandom")
122 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
123 int error = nacl_secure_random_init();
124 if (error)
125 __throw_system_error(error, ("random device failed to open " + __token).c_str());
126}
127
128random_device::~random_device()
129{
130}
131
132unsigned
133random_device::operator()()
134{
135 unsigned r;
136 size_t n = sizeof(r);
137 size_t bytes_written;
138 int error = nacl_secure_random(&r, n, &bytes_written);
139 if (error != 0)
140 __throw_system_error(error, "random_device failed getting bytes");
141 else if (bytes_written != n)
142 __throw_runtime_error("random_device failed to obtain enough bytes");
143 return r;
144}
145
146#elif defined(_LIBCPP_USING_WIN32_RANDOM)
147
148random_device::random_device(const string& __token)
149{
150 if (__token != "/dev/urandom")
151 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
152}
153
154random_device::~random_device()
155{
156}
157
158unsigned
159random_device::operator()()
160{
161 unsigned r;
162 errno_t err = rand_s(&r);
163 if (err)
164 __throw_system_error(err, "random_device rand_s failed.");
165 return r;
166}
167
168#else
169#error "Random device not implemented for this architecture"
170#endif
171
172double
173random_device::entropy() const _NOEXCEPT
174{
175 return 0;
176}
177
178_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/regex.cpp created+316
...@@ -0,0 +1,316 @@
1//===-------------------------- regex.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "regex"
10#include "algorithm"
11#include "iterator"
12
13_LIBCPP_BEGIN_NAMESPACE_STD
14
15static
16const char*
17make_error_type_string(regex_constants::error_type ecode)
18{
19 switch (ecode)
20 {
21 case regex_constants::error_collate:
22 return "The expression contained an invalid collating element name.";
23 case regex_constants::error_ctype:
24 return "The expression contained an invalid character class name.";
25 case regex_constants::error_escape:
26 return "The expression contained an invalid escaped character, or a "
27 "trailing escape.";
28 case regex_constants::error_backref:
29 return "The expression contained an invalid back reference.";
30 case regex_constants::error_brack:
31 return "The expression contained mismatched [ and ].";
32 case regex_constants::error_paren:
33 return "The expression contained mismatched ( and ).";
34 case regex_constants::error_brace:
35 return "The expression contained mismatched { and }.";
36 case regex_constants::error_badbrace:
37 return "The expression contained an invalid range in a {} expression.";
38 case regex_constants::error_range:
39 return "The expression contained an invalid character range, "
40 "such as [b-a] in most encodings.";
41 case regex_constants::error_space:
42 return "There was insufficient memory to convert the expression into "
43 "a finite state machine.";
44 case regex_constants::error_badrepeat:
45 return "One of *?+{ was not preceded by a valid regular expression.";
46 case regex_constants::error_complexity:
47 return "The complexity of an attempted match against a regular "
48 "expression exceeded a pre-set level.";
49 case regex_constants::error_stack:
50 return "There was insufficient memory to determine whether the regular "
51 "expression could match the specified character sequence.";
52 case regex_constants::__re_err_grammar:
53 return "An invalid regex grammar has been requested.";
54 case regex_constants::__re_err_empty:
55 return "An empty regex is not allowed in the POSIX grammar.";
56 case regex_constants::__re_err_parse:
57 return "The parser did not consume the entire regular expression.";
58 default:
59 break;
60 }
61 return "Unknown error type";
62}
63
64regex_error::regex_error(regex_constants::error_type ecode)
65 : runtime_error(make_error_type_string(ecode)),
66 __code_(ecode)
67{}
68
69regex_error::~regex_error() throw() {}
70
71namespace {
72
73struct collationnames
74{
75 const char* elem_;
76 char char_;
77};
78
79const collationnames collatenames[] =
80{
81 {"A", 0x41},
82 {"B", 0x42},
83 {"C", 0x43},
84 {"D", 0x44},
85 {"E", 0x45},
86 {"F", 0x46},
87 {"G", 0x47},
88 {"H", 0x48},
89 {"I", 0x49},
90 {"J", 0x4a},
91 {"K", 0x4b},
92 {"L", 0x4c},
93 {"M", 0x4d},
94 {"N", 0x4e},
95 {"NUL", 0x00},
96 {"O", 0x4f},
97 {"P", 0x50},
98 {"Q", 0x51},
99 {"R", 0x52},
100 {"S", 0x53},
101 {"T", 0x54},
102 {"U", 0x55},
103 {"V", 0x56},
104 {"W", 0x57},
105 {"X", 0x58},
106 {"Y", 0x59},
107 {"Z", 0x5a},
108 {"a", 0x61},
109 {"alert", 0x07},
110 {"ampersand", 0x26},
111 {"apostrophe", 0x27},
112 {"asterisk", 0x2a},
113 {"b", 0x62},
114 {"backslash", 0x5c},
115 {"backspace", 0x08},
116 {"c", 0x63},
117 {"carriage-return", 0x0d},
118 {"circumflex", 0x5e},
119 {"circumflex-accent", 0x5e},
120 {"colon", 0x3a},
121 {"comma", 0x2c},
122 {"commercial-at", 0x40},
123 {"d", 0x64},
124 {"dollar-sign", 0x24},
125 {"e", 0x65},
126 {"eight", 0x38},
127 {"equals-sign", 0x3d},
128 {"exclamation-mark", 0x21},
129 {"f", 0x66},
130 {"five", 0x35},
131 {"form-feed", 0x0c},
132 {"four", 0x34},
133 {"full-stop", 0x2e},
134 {"g", 0x67},
135 {"grave-accent", 0x60},
136 {"greater-than-sign", 0x3e},
137 {"h", 0x68},
138 {"hyphen", 0x2d},
139 {"hyphen-minus", 0x2d},
140 {"i", 0x69},
141 {"j", 0x6a},
142 {"k", 0x6b},
143 {"l", 0x6c},
144 {"left-brace", 0x7b},
145 {"left-curly-bracket", 0x7b},
146 {"left-parenthesis", 0x28},
147 {"left-square-bracket", 0x5b},
148 {"less-than-sign", 0x3c},
149 {"low-line", 0x5f},
150 {"m", 0x6d},
151 {"n", 0x6e},
152 {"newline", 0x0a},
153 {"nine", 0x39},
154 {"number-sign", 0x23},
155 {"o", 0x6f},
156 {"one", 0x31},
157 {"p", 0x70},
158 {"percent-sign", 0x25},
159 {"period", 0x2e},
160 {"plus-sign", 0x2b},
161 {"q", 0x71},
162 {"question-mark", 0x3f},
163 {"quotation-mark", 0x22},
164 {"r", 0x72},
165 {"reverse-solidus", 0x5c},
166 {"right-brace", 0x7d},
167 {"right-curly-bracket", 0x7d},
168 {"right-parenthesis", 0x29},
169 {"right-square-bracket", 0x5d},
170 {"s", 0x73},
171 {"semicolon", 0x3b},
172 {"seven", 0x37},
173 {"six", 0x36},
174 {"slash", 0x2f},
175 {"solidus", 0x2f},
176 {"space", 0x20},
177 {"t", 0x74},
178 {"tab", 0x09},
179 {"three", 0x33},
180 {"tilde", 0x7e},
181 {"two", 0x32},
182 {"u", 0x75},
183 {"underscore", 0x5f},
184 {"v", 0x76},
185 {"vertical-line", 0x7c},
186 {"vertical-tab", 0x0b},
187 {"w", 0x77},
188 {"x", 0x78},
189 {"y", 0x79},
190 {"z", 0x7a},
191 {"zero", 0x30}
192};
193
194struct classnames
195{
196 const char* elem_;
197 regex_traits<char>::char_class_type mask_;
198};
199
200const classnames ClassNames[] =
201{
202 {"alnum", ctype_base::alnum},
203 {"alpha", ctype_base::alpha},
204 {"blank", ctype_base::blank},
205 {"cntrl", ctype_base::cntrl},
206 {"d", ctype_base::digit},
207 {"digit", ctype_base::digit},
208 {"graph", ctype_base::graph},
209 {"lower", ctype_base::lower},
210 {"print", ctype_base::print},
211 {"punct", ctype_base::punct},
212 {"s", ctype_base::space},
213 {"space", ctype_base::space},
214 {"upper", ctype_base::upper},
215 {"w", regex_traits<char>::__regex_word},
216 {"xdigit", ctype_base::xdigit}
217};
218
219struct use_strcmp
220{
221 bool operator()(const collationnames& x, const char* y)
222 {return strcmp(x.elem_, y) < 0;}
223 bool operator()(const classnames& x, const char* y)
224 {return strcmp(x.elem_, y) < 0;}
225};
226
227}
228
229string
230__get_collation_name(const char* s)
231{
232 const collationnames* i =
233 _VSTD::lower_bound(begin(collatenames), end(collatenames), s, use_strcmp());
234 string r;
235 if (i != end(collatenames) && strcmp(s, i->elem_) == 0)
236 r = char(i->char_);
237 return r;
238}
239
240regex_traits<char>::char_class_type
241__get_classname(const char* s, bool __icase)
242{
243 const classnames* i =
244 _VSTD::lower_bound(begin(ClassNames), end(ClassNames), s, use_strcmp());
245 regex_traits<char>::char_class_type r = 0;
246 if (i != end(ClassNames) && strcmp(s, i->elem_) == 0)
247 {
248 r = i->mask_;
249 if (r == regex_traits<char>::__regex_word)
250 r |= ctype_base::alnum | ctype_base::upper | ctype_base::lower;
251 else if (__icase)
252 {
253 if (r & (ctype_base::lower | ctype_base::upper))
254 r |= ctype_base::alpha;
255 }
256 }
257 return r;
258}
259
260template <>
261void
262__match_any_but_newline<char>::__exec(__state& __s) const
263{
264 if (__s.__current_ != __s.__last_)
265 {
266 switch (*__s.__current_)
267 {
268 case '\r':
269 case '\n':
270 __s.__do_ = __state::__reject;
271 __s.__node_ = nullptr;
272 break;
273 default:
274 __s.__do_ = __state::__accept_and_consume;
275 ++__s.__current_;
276 __s.__node_ = this->first();
277 break;
278 }
279 }
280 else
281 {
282 __s.__do_ = __state::__reject;
283 __s.__node_ = nullptr;
284 }
285}
286
287template <>
288void
289__match_any_but_newline<wchar_t>::__exec(__state& __s) const
290{
291 if (__s.__current_ != __s.__last_)
292 {
293 switch (*__s.__current_)
294 {
295 case '\r':
296 case '\n':
297 case 0x2028:
298 case 0x2029:
299 __s.__do_ = __state::__reject;
300 __s.__node_ = nullptr;
301 break;
302 default:
303 __s.__do_ = __state::__accept_and_consume;
304 ++__s.__current_;
305 __s.__node_ = this->first();
306 break;
307 }
308 }
309 else
310 {
311 __s.__do_ = __state::__reject;
312 __s.__node_ = nullptr;
313 }
314}
315
316_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/shared_mutex.cpp created+118
...@@ -0,0 +1,118 @@
1//===---------------------- shared_mutex.cpp ------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10#ifndef _LIBCPP_HAS_NO_THREADS
11
12#include "shared_mutex"
13#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
14#pragma comment(lib, "pthread")
15#endif
16
17_LIBCPP_BEGIN_NAMESPACE_STD
18
19// Shared Mutex Base
20__shared_mutex_base::__shared_mutex_base()
21 : __state_(0)
22{
23}
24
25// Exclusive ownership
26
27void
28__shared_mutex_base::lock()
29{
30 unique_lock<mutex> lk(__mut_);
31 while (__state_ & __write_entered_)
32 __gate1_.wait(lk);
33 __state_ |= __write_entered_;
34 while (__state_ & __n_readers_)
35 __gate2_.wait(lk);
36}
37
38bool
39__shared_mutex_base::try_lock()
40{
41 unique_lock<mutex> lk(__mut_);
42 if (__state_ == 0)
43 {
44 __state_ = __write_entered_;
45 return true;
46 }
47 return false;
48}
49
50void
51__shared_mutex_base::unlock()
52{
53 lock_guard<mutex> _(__mut_);
54 __state_ = 0;
55 __gate1_.notify_all();
56}
57
58// Shared ownership
59
60void
61__shared_mutex_base::lock_shared()
62{
63 unique_lock<mutex> lk(__mut_);
64 while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
65 __gate1_.wait(lk);
66 unsigned num_readers = (__state_ & __n_readers_) + 1;
67 __state_ &= ~__n_readers_;
68 __state_ |= num_readers;
69}
70
71bool
72__shared_mutex_base::try_lock_shared()
73{
74 unique_lock<mutex> lk(__mut_);
75 unsigned num_readers = __state_ & __n_readers_;
76 if (!(__state_ & __write_entered_) && num_readers != __n_readers_)
77 {
78 ++num_readers;
79 __state_ &= ~__n_readers_;
80 __state_ |= num_readers;
81 return true;
82 }
83 return false;
84}
85
86void
87__shared_mutex_base::unlock_shared()
88{
89 lock_guard<mutex> _(__mut_);
90 unsigned num_readers = (__state_ & __n_readers_) - 1;
91 __state_ &= ~__n_readers_;
92 __state_ |= num_readers;
93 if (__state_ & __write_entered_)
94 {
95 if (num_readers == 0)
96 __gate2_.notify_one();
97 }
98 else
99 {
100 if (num_readers == __n_readers_ - 1)
101 __gate1_.notify_one();
102 }
103}
104
105
106// Shared Timed Mutex
107// These routines are here for ABI stability
108shared_timed_mutex::shared_timed_mutex() : __base() {}
109void shared_timed_mutex::lock() { return __base.lock(); }
110bool shared_timed_mutex::try_lock() { return __base.try_lock(); }
111void shared_timed_mutex::unlock() { return __base.unlock(); }
112void shared_timed_mutex::lock_shared() { return __base.lock_shared(); }
113bool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); }
114void shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); }
115
116_LIBCPP_END_NAMESPACE_STD
117
118#endif // !_LIBCPP_HAS_NO_THREADS
lib/libcxx/src/stdexcept.cpp created+19
...@@ -0,0 +1,19 @@
1//===------------------------ stdexcept.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "stdexcept"
10#include "new"
11#include "string"
12#include "system_error"
13
14
15#ifdef _LIBCPP_ABI_VCRUNTIME
16#include "support/runtime/stdexcept_vcruntime.ipp"
17#else
18#include "support/runtime/stdexcept_default.ipp"
19#endif
lib/libcxx/src/string.cpp created+458
...@@ -0,0 +1,458 @@
1//===------------------------- string.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "string"
10#include "charconv"
11#include "cstdlib"
12#include "cwchar"
13#include "cerrno"
14#include "limits"
15#include "stdexcept"
16#include <stdio.h>
17#include "__debug"
18
19_LIBCPP_BEGIN_NAMESPACE_STD
20
21template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
22
23template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
24template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
25
26template
27 string
28 operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
29
30namespace
31{
32
33template<typename T>
34inline
35void throw_helper( const string& msg )
36{
37#ifndef _LIBCPP_NO_EXCEPTIONS
38 throw T( msg );
39#else
40 fprintf(stderr, "%s\n", msg.c_str());
41 _VSTD::abort();
42#endif
43}
44
45inline
46void throw_from_string_out_of_range( const string& func )
47{
48 throw_helper<out_of_range>(func + ": out of range");
49}
50
51inline
52void throw_from_string_invalid_arg( const string& func )
53{
54 throw_helper<invalid_argument>(func + ": no conversion");
55}
56
57// as_integer
58
59template<typename V, typename S, typename F>
60inline
61V
62as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
63{
64 typename S::value_type* ptr = nullptr;
65 const typename S::value_type* const p = str.c_str();
66 typename remove_reference<decltype(errno)>::type errno_save = errno;
67 errno = 0;
68 V r = f(p, &ptr, base);
69 swap(errno, errno_save);
70 if (errno_save == ERANGE)
71 throw_from_string_out_of_range(func);
72 if (ptr == p)
73 throw_from_string_invalid_arg(func);
74 if (idx)
75 *idx = static_cast<size_t>(ptr - p);
76 return r;
77}
78
79template<typename V, typename S>
80inline
81V
82as_integer(const string& func, const S& s, size_t* idx, int base);
83
84// string
85template<>
86inline
87int
88as_integer(const string& func, const string& s, size_t* idx, int base )
89{
90 // Use long as no Standard string to integer exists.
91 long r = as_integer_helper<long>( func, s, idx, base, strtol );
92 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
93 throw_from_string_out_of_range(func);
94 return static_cast<int>(r);
95}
96
97template<>
98inline
99long
100as_integer(const string& func, const string& s, size_t* idx, int base )
101{
102 return as_integer_helper<long>( func, s, idx, base, strtol );
103}
104
105template<>
106inline
107unsigned long
108as_integer( const string& func, const string& s, size_t* idx, int base )
109{
110 return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
111}
112
113template<>
114inline
115long long
116as_integer( const string& func, const string& s, size_t* idx, int base )
117{
118 return as_integer_helper<long long>( func, s, idx, base, strtoll );
119}
120
121template<>
122inline
123unsigned long long
124as_integer( const string& func, const string& s, size_t* idx, int base )
125{
126 return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
127}
128
129// wstring
130template<>
131inline
132int
133as_integer( const string& func, const wstring& s, size_t* idx, int base )
134{
135 // Use long as no Stantard string to integer exists.
136 long r = as_integer_helper<long>( func, s, idx, base, wcstol );
137 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
138 throw_from_string_out_of_range(func);
139 return static_cast<int>(r);
140}
141
142template<>
143inline
144long
145as_integer( const string& func, const wstring& s, size_t* idx, int base )
146{
147 return as_integer_helper<long>( func, s, idx, base, wcstol );
148}
149
150template<>
151inline
152unsigned long
153as_integer( const string& func, const wstring& s, size_t* idx, int base )
154{
155 return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
156}
157
158template<>
159inline
160long long
161as_integer( const string& func, const wstring& s, size_t* idx, int base )
162{
163 return as_integer_helper<long long>( func, s, idx, base, wcstoll );
164}
165
166template<>
167inline
168unsigned long long
169as_integer( const string& func, const wstring& s, size_t* idx, int base )
170{
171 return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
172}
173
174// as_float
175
176template<typename V, typename S, typename F>
177inline
178V
179as_float_helper(const string& func, const S& str, size_t* idx, F f )
180{
181 typename S::value_type* ptr = nullptr;
182 const typename S::value_type* const p = str.c_str();
183 typename remove_reference<decltype(errno)>::type errno_save = errno;
184 errno = 0;
185 V r = f(p, &ptr);
186 swap(errno, errno_save);
187 if (errno_save == ERANGE)
188 throw_from_string_out_of_range(func);
189 if (ptr == p)
190 throw_from_string_invalid_arg(func);
191 if (idx)
192 *idx = static_cast<size_t>(ptr - p);
193 return r;
194}
195
196template<typename V, typename S>
197inline
198V as_float( const string& func, const S& s, size_t* idx = nullptr );
199
200template<>
201inline
202float
203as_float( const string& func, const string& s, size_t* idx )
204{
205 return as_float_helper<float>( func, s, idx, strtof );
206}
207
208template<>
209inline
210double
211as_float(const string& func, const string& s, size_t* idx )
212{
213 return as_float_helper<double>( func, s, idx, strtod );
214}
215
216template<>
217inline
218long double
219as_float( const string& func, const string& s, size_t* idx )
220{
221 return as_float_helper<long double>( func, s, idx, strtold );
222}
223
224template<>
225inline
226float
227as_float( const string& func, const wstring& s, size_t* idx )
228{
229 return as_float_helper<float>( func, s, idx, wcstof );
230}
231
232template<>
233inline
234double
235as_float( const string& func, const wstring& s, size_t* idx )
236{
237 return as_float_helper<double>( func, s, idx, wcstod );
238}
239
240template<>
241inline
242long double
243as_float( const string& func, const wstring& s, size_t* idx )
244{
245 return as_float_helper<long double>( func, s, idx, wcstold );
246}
247
248} // unnamed namespace
249
250int
251stoi(const string& str, size_t* idx, int base)
252{
253 return as_integer<int>( "stoi", str, idx, base );
254}
255
256int
257stoi(const wstring& str, size_t* idx, int base)
258{
259 return as_integer<int>( "stoi", str, idx, base );
260}
261
262long
263stol(const string& str, size_t* idx, int base)
264{
265 return as_integer<long>( "stol", str, idx, base );
266}
267
268long
269stol(const wstring& str, size_t* idx, int base)
270{
271 return as_integer<long>( "stol", str, idx, base );
272}
273
274unsigned long
275stoul(const string& str, size_t* idx, int base)
276{
277 return as_integer<unsigned long>( "stoul", str, idx, base );
278}
279
280unsigned long
281stoul(const wstring& str, size_t* idx, int base)
282{
283 return as_integer<unsigned long>( "stoul", str, idx, base );
284}
285
286long long
287stoll(const string& str, size_t* idx, int base)
288{
289 return as_integer<long long>( "stoll", str, idx, base );
290}
291
292long long
293stoll(const wstring& str, size_t* idx, int base)
294{
295 return as_integer<long long>( "stoll", str, idx, base );
296}
297
298unsigned long long
299stoull(const string& str, size_t* idx, int base)
300{
301 return as_integer<unsigned long long>( "stoull", str, idx, base );
302}
303
304unsigned long long
305stoull(const wstring& str, size_t* idx, int base)
306{
307 return as_integer<unsigned long long>( "stoull", str, idx, base );
308}
309
310float
311stof(const string& str, size_t* idx)
312{
313 return as_float<float>( "stof", str, idx );
314}
315
316float
317stof(const wstring& str, size_t* idx)
318{
319 return as_float<float>( "stof", str, idx );
320}
321
322double
323stod(const string& str, size_t* idx)
324{
325 return as_float<double>( "stod", str, idx );
326}
327
328double
329stod(const wstring& str, size_t* idx)
330{
331 return as_float<double>( "stod", str, idx );
332}
333
334long double
335stold(const string& str, size_t* idx)
336{
337 return as_float<long double>( "stold", str, idx );
338}
339
340long double
341stold(const wstring& str, size_t* idx)
342{
343 return as_float<long double>( "stold", str, idx );
344}
345
346// to_string
347
348namespace
349{
350
351// as_string
352
353template<typename S, typename P, typename V >
354inline
355S
356as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
357{
358 typedef typename S::size_type size_type;
359 size_type available = s.size();
360 while (true)
361 {
362 int status = sprintf_like(&s[0], available + 1, fmt, a);
363 if ( status >= 0 )
364 {
365 size_type used = static_cast<size_type>(status);
366 if ( used <= available )
367 {
368 s.resize( used );
369 break;
370 }
371 available = used; // Assume this is advice of how much space we need.
372 }
373 else
374 available = available * 2 + 1;
375 s.resize(available);
376 }
377 return s;
378}
379
380template <class S>
381struct initial_string;
382
383template <>
384struct initial_string<string>
385{
386 string
387 operator()() const
388 {
389 string s;
390 s.resize(s.capacity());
391 return s;
392 }
393};
394
395template <>
396struct initial_string<wstring>
397{
398 wstring
399 operator()() const
400 {
401 wstring s(20, wchar_t());
402 s.resize(s.capacity());
403 return s;
404 }
405};
406
407typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
408
409inline
410wide_printf
411get_swprintf()
412{
413#ifndef _LIBCPP_MSVCRT
414 return swprintf;
415#else
416 return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
417#endif
418}
419
420template <typename S, typename V>
421S i_to_string(const V v)
422{
423// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
424// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
425// so we need +1 here.
426 constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10
427 char buf[bufsize];
428 const auto res = to_chars(buf, buf + bufsize, v);
429 _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
430 return S(buf, res.ptr);
431}
432
433} // unnamed namespace
434
435string to_string (int val) { return i_to_string< string>(val); }
436string to_string (long val) { return i_to_string< string>(val); }
437string to_string (long long val) { return i_to_string< string>(val); }
438string to_string (unsigned val) { return i_to_string< string>(val); }
439string to_string (unsigned long val) { return i_to_string< string>(val); }
440string to_string (unsigned long long val) { return i_to_string< string>(val); }
441
442wstring to_wstring(int val) { return i_to_string<wstring>(val); }
443wstring to_wstring(long val) { return i_to_string<wstring>(val); }
444wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
445wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
446wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
447wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
448
449
450string to_string (float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
451string to_string (double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
452string to_string (long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
453
454wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
455wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
456wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
457
458_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/strstream.cpp created+335
...@@ -0,0 +1,335 @@
1//===------------------------ strstream.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "strstream"
10#include "algorithm"
11#include "climits"
12#include "cstring"
13#include "cstdlib"
14#include "__debug"
15#include "__undef_macros"
16
17_LIBCPP_BEGIN_NAMESPACE_STD
18
19strstreambuf::strstreambuf(streamsize __alsize)
20 : __strmode_(__dynamic),
21 __alsize_(__alsize),
22 __palloc_(nullptr),
23 __pfree_(nullptr)
24{
25}
26
27strstreambuf::strstreambuf(void* (*__palloc)(size_t), void (*__pfree)(void*))
28 : __strmode_(__dynamic),
29 __alsize_(__default_alsize),
30 __palloc_(__palloc),
31 __pfree_(__pfree)
32{
33}
34
35void
36strstreambuf::__init(char* __gnext, streamsize __n, char* __pbeg)
37{
38 if (__n == 0)
39 __n = static_cast<streamsize>(strlen(__gnext));
40 else if (__n < 0)
41 __n = INT_MAX;
42 if (__pbeg == nullptr)
43 setg(__gnext, __gnext, __gnext + __n);
44 else
45 {
46 setg(__gnext, __gnext, __pbeg);
47 setp(__pbeg, __pbeg + __n);
48 }
49}
50
51strstreambuf::strstreambuf(char* __gnext, streamsize __n, char* __pbeg)
52 : __strmode_(),
53 __alsize_(__default_alsize),
54 __palloc_(nullptr),
55 __pfree_(nullptr)
56{
57 __init(__gnext, __n, __pbeg);
58}
59
60strstreambuf::strstreambuf(const char* __gnext, streamsize __n)
61 : __strmode_(__constant),
62 __alsize_(__default_alsize),
63 __palloc_(nullptr),
64 __pfree_(nullptr)
65{
66 __init(const_cast<char *>(__gnext), __n, nullptr);
67}
68
69strstreambuf::strstreambuf(signed char* __gnext, streamsize __n, signed char* __pbeg)
70 : __strmode_(),
71 __alsize_(__default_alsize),
72 __palloc_(nullptr),
73 __pfree_(nullptr)
74{
75 __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
76}
77
78strstreambuf::strstreambuf(const signed char* __gnext, streamsize __n)
79 : __strmode_(__constant),
80 __alsize_(__default_alsize),
81 __palloc_(nullptr),
82 __pfree_(nullptr)
83{
84 __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
85}
86
87strstreambuf::strstreambuf(unsigned char* __gnext, streamsize __n, unsigned char* __pbeg)
88 : __strmode_(),
89 __alsize_(__default_alsize),
90 __palloc_(nullptr),
91 __pfree_(nullptr)
92{
93 __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, reinterpret_cast<char*>(__pbeg));
94}
95
96strstreambuf::strstreambuf(const unsigned char* __gnext, streamsize __n)
97 : __strmode_(__constant),
98 __alsize_(__default_alsize),
99 __palloc_(nullptr),
100 __pfree_(nullptr)
101{
102 __init(const_cast<char *>(reinterpret_cast<const char*>(__gnext)), __n, nullptr);
103}
104
105strstreambuf::~strstreambuf()
106{
107 if (eback() && (__strmode_ & __allocated) != 0 && (__strmode_ & __frozen) == 0)
108 {
109 if (__pfree_)
110 __pfree_(eback());
111 else
112 delete [] eback();
113 }
114}
115
116void
117strstreambuf::swap(strstreambuf& __rhs)
118{
119 streambuf::swap(__rhs);
120 _VSTD::swap(__strmode_, __rhs.__strmode_);
121 _VSTD::swap(__alsize_, __rhs.__alsize_);
122 _VSTD::swap(__palloc_, __rhs.__palloc_);
123 _VSTD::swap(__pfree_, __rhs.__pfree_);
124}
125
126void
127strstreambuf::freeze(bool __freezefl)
128{
129 if (__strmode_ & __dynamic)
130 {
131 if (__freezefl)
132 __strmode_ |= __frozen;
133 else
134 __strmode_ &= ~__frozen;
135 }
136}
137
138char*
139strstreambuf::str()
140{
141 if (__strmode_ & __dynamic)
142 __strmode_ |= __frozen;
143 return eback();
144}
145
146int
147strstreambuf::pcount() const
148{
149 return static_cast<int>(pptr() - pbase());
150}
151
152strstreambuf::int_type
153strstreambuf::overflow(int_type __c)
154{
155 if (__c == EOF)
156 return int_type(0);
157 if (pptr() == epptr())
158 {
159 if ((__strmode_ & __dynamic) == 0 || (__strmode_ & __frozen) != 0)
160 return int_type(EOF);
161 size_t old_size = static_cast<size_t> ((epptr() ? epptr() : egptr()) - eback());
162 size_t new_size = max<size_t>(static_cast<size_t>(__alsize_), 2*old_size);
163 if (new_size == 0)
164 new_size = __default_alsize;
165 char* buf = nullptr;
166 if (__palloc_)
167 buf = static_cast<char*>(__palloc_(new_size));
168 else
169 buf = new char[new_size];
170 if (buf == nullptr)
171 return int_type(EOF);
172 if (old_size != 0) {
173 _LIBCPP_ASSERT(eback(), "overflow copying from NULL");
174 memcpy(buf, eback(), static_cast<size_t>(old_size));
175 }
176 ptrdiff_t ninp = gptr() - eback();
177 ptrdiff_t einp = egptr() - eback();
178 ptrdiff_t nout = pptr() - pbase();
179 if (__strmode_ & __allocated)
180 {
181 if (__pfree_)
182 __pfree_(eback());
183 else
184 delete [] eback();
185 }
186 setg(buf, buf + ninp, buf + einp);
187 setp(buf + einp, buf + new_size);
188 __pbump(nout);
189 __strmode_ |= __allocated;
190 }
191 *pptr() = static_cast<char>(__c);
192 pbump(1);
193 return int_type(static_cast<unsigned char>(__c));
194}
195
196strstreambuf::int_type
197strstreambuf::pbackfail(int_type __c)
198{
199 if (eback() == gptr())
200 return EOF;
201 if (__c == EOF)
202 {
203 gbump(-1);
204 return int_type(0);
205 }
206 if (__strmode_ & __constant)
207 {
208 if (gptr()[-1] == static_cast<char>(__c))
209 {
210 gbump(-1);
211 return __c;
212 }
213 return EOF;
214 }
215 gbump(-1);
216 *gptr() = static_cast<char>(__c);
217 return __c;
218}
219
220strstreambuf::int_type
221strstreambuf::underflow()
222{
223 if (gptr() == egptr())
224 {
225 if (egptr() >= pptr())
226 return EOF;
227 setg(eback(), gptr(), pptr());
228 }
229 return int_type(static_cast<unsigned char>(*gptr()));
230}
231
232strstreambuf::pos_type
233strstreambuf::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which)
234{
235 off_type __p(-1);
236 bool pos_in = (__which & ios::in) != 0;
237 bool pos_out = (__which & ios::out) != 0;
238 bool legal = false;
239 switch (__way)
240 {
241 case ios::beg:
242 case ios::end:
243 if (pos_in || pos_out)
244 legal = true;
245 break;
246 case ios::cur:
247 if (pos_in != pos_out)
248 legal = true;
249 break;
250 }
251 if (pos_in && gptr() == nullptr)
252 legal = false;
253 if (pos_out && pptr() == nullptr)
254 legal = false;
255 if (legal)
256 {
257 off_type newoff;
258 char* seekhigh = epptr() ? epptr() : egptr();
259 switch (__way)
260 {
261 case ios::beg:
262 newoff = 0;
263 break;
264 case ios::cur:
265 newoff = (pos_in ? gptr() : pptr()) - eback();
266 break;
267 case ios::end:
268 newoff = seekhigh - eback();
269 break;
270 default:
271 _LIBCPP_UNREACHABLE();
272 }
273 newoff += __off;
274 if (0 <= newoff && newoff <= seekhigh - eback())
275 {
276 char* newpos = eback() + newoff;
277 if (pos_in)
278 setg(eback(), newpos, _VSTD::max(newpos, egptr()));
279 if (pos_out)
280 {
281 // min(pbase, newpos), newpos, epptr()
282 __off = epptr() - newpos;
283 setp(min(pbase(), newpos), epptr());
284 __pbump((epptr() - pbase()) - __off);
285 }
286 __p = newoff;
287 }
288 }
289 return pos_type(__p);
290}
291
292strstreambuf::pos_type
293strstreambuf::seekpos(pos_type __sp, ios_base::openmode __which)
294{
295 off_type __p(-1);
296 bool pos_in = (__which & ios::in) != 0;
297 bool pos_out = (__which & ios::out) != 0;
298 if (pos_in || pos_out)
299 {
300 if (!((pos_in && gptr() == nullptr) || (pos_out && pptr() == nullptr)))
301 {
302 off_type newoff = __sp;
303 char* seekhigh = epptr() ? epptr() : egptr();
304 if (0 <= newoff && newoff <= seekhigh - eback())
305 {
306 char* newpos = eback() + newoff;
307 if (pos_in)
308 setg(eback(), newpos, _VSTD::max(newpos, egptr()));
309 if (pos_out)
310 {
311 // min(pbase, newpos), newpos, epptr()
312 off_type temp = epptr() - newpos;
313 setp(min(pbase(), newpos), epptr());
314 __pbump((epptr() - pbase()) - temp);
315 }
316 __p = newoff;
317 }
318 }
319 }
320 return pos_type(__p);
321}
322
323istrstream::~istrstream()
324{
325}
326
327ostrstream::~ostrstream()
328{
329}
330
331strstream::~strstream()
332{
333}
334
335_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/support/runtime/exception_fallback.ipp created+164
...@@ -0,0 +1,164 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <cstdio>
11
12namespace std {
13
14_LIBCPP_SAFE_STATIC static std::terminate_handler __terminate_handler;
15_LIBCPP_SAFE_STATIC static std::unexpected_handler __unexpected_handler;
16
17
18// libcxxrt provides implementations of these functions itself.
19unexpected_handler
20set_unexpected(unexpected_handler func) _NOEXCEPT
21{
22 return __libcpp_atomic_exchange(&__unexpected_handler, func);
23}
24
25unexpected_handler
26get_unexpected() _NOEXCEPT
27{
28 return __libcpp_atomic_load(&__unexpected_handler);
29
30}
31
32_LIBCPP_NORETURN
33void unexpected()
34{
35 (*get_unexpected())();
36 // unexpected handler should not return
37 terminate();
38}
39
40terminate_handler
41set_terminate(terminate_handler func) _NOEXCEPT
42{
43 return __libcpp_atomic_exchange(&__terminate_handler, func);
44}
45
46terminate_handler
47get_terminate() _NOEXCEPT
48{
49 return __libcpp_atomic_load(&__terminate_handler);
50}
51
52#ifndef __EMSCRIPTEN__ // We provide this in JS
53_LIBCPP_NORETURN
54void
55terminate() _NOEXCEPT
56{
57#ifndef _LIBCPP_NO_EXCEPTIONS
58 try
59 {
60#endif // _LIBCPP_NO_EXCEPTIONS
61 (*get_terminate())();
62 // handler should not return
63 fprintf(stderr, "terminate_handler unexpectedly returned\n");
64 ::abort();
65#ifndef _LIBCPP_NO_EXCEPTIONS
66 }
67 catch (...)
68 {
69 // handler should not throw exception
70 fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
71 ::abort();
72 }
73#endif // _LIBCPP_NO_EXCEPTIONS
74}
75#endif // !__EMSCRIPTEN__
76
77#if !defined(__EMSCRIPTEN__)
78bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
79
80int uncaught_exceptions() _NOEXCEPT
81{
82#warning uncaught_exception not yet implemented
83 fprintf(stderr, "uncaught_exceptions not yet implemented\n");
84 ::abort();
85}
86#endif // !__EMSCRIPTEN__
87
88
89exception::~exception() _NOEXCEPT
90{
91}
92
93const char* exception::what() const _NOEXCEPT
94{
95 return "std::exception";
96}
97
98bad_exception::~bad_exception() _NOEXCEPT
99{
100}
101
102const char* bad_exception::what() const _NOEXCEPT
103{
104 return "std::bad_exception";
105}
106
107
108bad_alloc::bad_alloc() _NOEXCEPT
109{
110}
111
112bad_alloc::~bad_alloc() _NOEXCEPT
113{
114}
115
116const char*
117bad_alloc::what() const _NOEXCEPT
118{
119 return "std::bad_alloc";
120}
121
122bad_array_new_length::bad_array_new_length() _NOEXCEPT
123{
124}
125
126bad_array_new_length::~bad_array_new_length() _NOEXCEPT
127{
128}
129
130const char*
131bad_array_new_length::what() const _NOEXCEPT
132{
133 return "bad_array_new_length";
134}
135
136bad_cast::bad_cast() _NOEXCEPT
137{
138}
139
140bad_typeid::bad_typeid() _NOEXCEPT
141{
142}
143
144bad_cast::~bad_cast() _NOEXCEPT
145{
146}
147
148const char*
149bad_cast::what() const _NOEXCEPT
150{
151 return "std::bad_cast";
152}
153
154bad_typeid::~bad_typeid() _NOEXCEPT
155{
156}
157
158const char*
159bad_typeid::what() const _NOEXCEPT
160{
161 return "std::bad_typeid";
162}
163
164} // namespace std
lib/libcxx/src/support/runtime/exception_glibcxx.ipp created+32
...@@ -0,0 +1,32 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef __GLIBCXX__
11#error header can only be used when targeting libstdc++ or libsupc++
12#endif
13
14namespace std {
15
16bad_alloc::bad_alloc() _NOEXCEPT
17{
18}
19
20bad_array_new_length::bad_array_new_length() _NOEXCEPT
21{
22}
23
24bad_cast::bad_cast() _NOEXCEPT
25{
26}
27
28bad_typeid::bad_typeid() _NOEXCEPT
29{
30}
31
32} // namespace std
lib/libcxx/src/support/runtime/exception_libcxxabi.ipp created+27
...@@ -0,0 +1,27 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPPABI_VERSION
11#error this header can only be used with libc++abi
12#endif
13
14namespace std {
15
16bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
17
18int uncaught_exceptions() _NOEXCEPT
19{
20# if _LIBCPPABI_VERSION > 1001
21 return __cxa_uncaught_exceptions();
22# else
23 return __cxa_uncaught_exception() ? 1 : 0;
24# endif
25}
26
27} // namespace std
lib/libcxx/src/support/runtime/exception_libcxxrt.ipp created+25
...@@ -0,0 +1,25 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LIBCXXRT
11#error this header may only be used when targeting libcxxrt
12#endif
13
14namespace std {
15
16bad_exception::~bad_exception() _NOEXCEPT
17{
18}
19
20const char* bad_exception::what() const _NOEXCEPT
21{
22 return "std::bad_exception";
23}
24
25} // namespace std
lib/libcxx/src/support/runtime/exception_msvc.ipp created+163
...@@ -0,0 +1,163 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP_ABI_MICROSOFT
11#error this header can only be used when targeting the MSVC ABI
12#endif
13
14#include <stdio.h>
15#include <stdlib.h>
16
17extern "C" {
18typedef void (__cdecl* terminate_handler)();
19_LIBCPP_CRT_FUNC terminate_handler __cdecl set_terminate(
20 terminate_handler _NewTerminateHandler) throw();
21_LIBCPP_CRT_FUNC terminate_handler __cdecl _get_terminate();
22
23typedef void (__cdecl* unexpected_handler)();
24unexpected_handler __cdecl set_unexpected(
25 unexpected_handler _NewUnexpectedHandler) throw();
26unexpected_handler __cdecl _get_unexpected();
27
28int __cdecl __uncaught_exceptions();
29}
30
31namespace std {
32
33unexpected_handler
34set_unexpected(unexpected_handler func) _NOEXCEPT {
35 return ::set_unexpected(func);
36}
37
38unexpected_handler get_unexpected() _NOEXCEPT {
39 return ::_get_unexpected();
40}
41
42_LIBCPP_NORETURN
43void unexpected() {
44 (*get_unexpected())();
45 // unexpected handler should not return
46 terminate();
47}
48
49terminate_handler set_terminate(terminate_handler func) _NOEXCEPT {
50 return ::set_terminate(func);
51}
52
53terminate_handler get_terminate() _NOEXCEPT {
54 return ::_get_terminate();
55}
56
57_LIBCPP_NORETURN
58void terminate() _NOEXCEPT
59{
60#ifndef _LIBCPP_NO_EXCEPTIONS
61 try
62 {
63#endif // _LIBCPP_NO_EXCEPTIONS
64 (*get_terminate())();
65 // handler should not return
66 fprintf(stderr, "terminate_handler unexpectedly returned\n");
67 ::abort();
68#ifndef _LIBCPP_NO_EXCEPTIONS
69 }
70 catch (...)
71 {
72 // handler should not throw exception
73 fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
74 ::abort();
75 }
76#endif // _LIBCPP_NO_EXCEPTIONS
77}
78
79bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
80
81int uncaught_exceptions() _NOEXCEPT {
82 return __uncaught_exceptions();
83}
84
85#if !defined(_LIBCPP_ABI_VCRUNTIME)
86bad_cast::bad_cast() _NOEXCEPT
87{
88}
89
90bad_cast::~bad_cast() _NOEXCEPT
91{
92}
93
94const char *
95bad_cast::what() const _NOEXCEPT
96{
97 return "std::bad_cast";
98}
99
100bad_typeid::bad_typeid() _NOEXCEPT
101{
102}
103
104bad_typeid::~bad_typeid() _NOEXCEPT
105{
106}
107
108const char *
109bad_typeid::what() const _NOEXCEPT
110{
111 return "std::bad_typeid";
112}
113
114exception::~exception() _NOEXCEPT
115{
116}
117
118const char* exception::what() const _NOEXCEPT
119{
120 return "std::exception";
121}
122
123
124bad_exception::~bad_exception() _NOEXCEPT
125{
126}
127
128const char* bad_exception::what() const _NOEXCEPT
129{
130 return "std::bad_exception";
131}
132
133
134bad_alloc::bad_alloc() _NOEXCEPT
135{
136}
137
138bad_alloc::~bad_alloc() _NOEXCEPT
139{
140}
141
142const char*
143bad_alloc::what() const _NOEXCEPT
144{
145 return "std::bad_alloc";
146}
147
148bad_array_new_length::bad_array_new_length() _NOEXCEPT
149{
150}
151
152bad_array_new_length::~bad_array_new_length() _NOEXCEPT
153{
154}
155
156const char*
157bad_array_new_length::what() const _NOEXCEPT
158{
159 return "bad_array_new_length";
160}
161#endif // !_LIBCPP_ABI_VCRUNTIME
162
163} // namespace std
lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp created+73
...@@ -0,0 +1,73 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef HAVE_DEPENDENT_EH_ABI
11#error this header may only be used with libc++abi or libcxxrt
12#endif
13
14namespace std {
15
16exception_ptr::~exception_ptr() _NOEXCEPT {
17 __cxa_decrement_exception_refcount(__ptr_);
18}
19
20exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
21 : __ptr_(other.__ptr_)
22{
23 __cxa_increment_exception_refcount(__ptr_);
24}
25
26exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
27{
28 if (__ptr_ != other.__ptr_)
29 {
30 __cxa_increment_exception_refcount(other.__ptr_);
31 __cxa_decrement_exception_refcount(__ptr_);
32 __ptr_ = other.__ptr_;
33 }
34 return *this;
35}
36
37nested_exception::nested_exception() _NOEXCEPT
38 : __ptr_(current_exception())
39{
40}
41
42nested_exception::~nested_exception() _NOEXCEPT
43{
44}
45
46_LIBCPP_NORETURN
47void
48nested_exception::rethrow_nested() const
49{
50 if (__ptr_ == nullptr)
51 terminate();
52 rethrow_exception(__ptr_);
53}
54
55exception_ptr current_exception() _NOEXCEPT
56{
57 // be nicer if there was a constructor that took a ptr, then
58 // this whole function would be just:
59 // return exception_ptr(__cxa_current_primary_exception());
60 exception_ptr ptr;
61 ptr.__ptr_ = __cxa_current_primary_exception();
62 return ptr;
63}
64
65_LIBCPP_NORETURN
66void rethrow_exception(exception_ptr p)
67{
68 __cxa_rethrow_primary_exception(p.__ptr_);
69 // if p.__ptr_ is NULL, above returns so we terminate
70 terminate();
71}
72
73} // namespace std
lib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp created+77
...@@ -0,0 +1,77 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10// libsupc++ does not implement the dependent EH ABI and the functionality
11// it uses to implement std::exception_ptr (which it declares as an alias of
12// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
13// we have little choice but to hijack std::__exception_ptr::exception_ptr's
14// (which fortunately has the same layout as our std::exception_ptr) copy
15// constructor, assignment operator and destructor (which are part of its
16// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
17// function.
18
19namespace std {
20
21namespace __exception_ptr
22{
23
24struct exception_ptr
25{
26 void* __ptr_;
27
28 exception_ptr(const exception_ptr&) _NOEXCEPT;
29 exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
30 ~exception_ptr() _NOEXCEPT;
31};
32
33}
34
35_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
36
37exception_ptr::~exception_ptr() _NOEXCEPT
38{
39 reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
40}
41
42exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
43 : __ptr_(other.__ptr_)
44{
45 new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
46 reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
47}
48
49exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
50{
51 *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
52 reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
53 return *this;
54}
55
56nested_exception::nested_exception() _NOEXCEPT
57 : __ptr_(current_exception())
58{
59}
60
61
62_LIBCPP_NORETURN
63void
64nested_exception::rethrow_nested() const
65{
66 if (__ptr_ == nullptr)
67 terminate();
68 rethrow_exception(__ptr_);
69}
70
71_LIBCPP_NORETURN
72void rethrow_exception(exception_ptr p)
73{
74 rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
75}
76
77} // namespace std
lib/libcxx/src/support/runtime/exception_pointer_msvc.ipp created+86
...@@ -0,0 +1,86 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <stdio.h>
11#include <stdlib.h>
12
13_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCreate(void*);
14_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrDestroy(void*);
15_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCopy(void*, const void*);
16_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrAssign(void*, const void*);
17_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrCompare(const void*, const void*);
18_LIBCPP_CRT_FUNC bool __cdecl __ExceptionPtrToBool(const void*);
19_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrSwap(void*, void*);
20_LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrCurrentException(void*);
21[[noreturn]] _LIBCPP_CRT_FUNC void __cdecl __ExceptionPtrRethrow(const void*);
22_LIBCPP_CRT_FUNC void __cdecl
23__ExceptionPtrCopyException(void*, const void*, const void*);
24
25namespace std {
26
27exception_ptr::exception_ptr() _NOEXCEPT { __ExceptionPtrCreate(this); }
28exception_ptr::exception_ptr(nullptr_t) _NOEXCEPT { __ExceptionPtrCreate(this); }
29
30exception_ptr::exception_ptr(const exception_ptr& __other) _NOEXCEPT {
31 __ExceptionPtrCopy(this, &__other);
32}
33exception_ptr& exception_ptr::operator=(const exception_ptr& __other) _NOEXCEPT {
34 __ExceptionPtrAssign(this, &__other);
35 return *this;
36}
37
38exception_ptr& exception_ptr::operator=(nullptr_t) _NOEXCEPT {
39 exception_ptr dummy;
40 __ExceptionPtrAssign(this, &dummy);
41 return *this;
42}
43
44exception_ptr::~exception_ptr() _NOEXCEPT { __ExceptionPtrDestroy(this); }
45
46exception_ptr::operator bool() const _NOEXCEPT {
47 return __ExceptionPtrToBool(this);
48}
49
50bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
51 return __ExceptionPtrCompare(&__x, &__y);
52}
53
54
55void swap(exception_ptr& lhs, exception_ptr& rhs) _NOEXCEPT {
56 __ExceptionPtrSwap(&rhs, &lhs);
57}
58
59exception_ptr __copy_exception_ptr(void* __except, const void* __ptr) {
60 exception_ptr __ret = nullptr;
61 if (__ptr)
62 __ExceptionPtrCopyException(&__ret, __except, __ptr);
63 return __ret;
64}
65
66exception_ptr current_exception() _NOEXCEPT {
67 exception_ptr __ret;
68 __ExceptionPtrCurrentException(&__ret);
69 return __ret;
70}
71
72_LIBCPP_NORETURN
73void rethrow_exception(exception_ptr p) { __ExceptionPtrRethrow(&p); }
74
75nested_exception::nested_exception() _NOEXCEPT : __ptr_(current_exception()) {}
76
77nested_exception::~nested_exception() _NOEXCEPT {}
78
79_LIBCPP_NORETURN
80void nested_exception::rethrow_nested() const {
81 if (__ptr_ == nullptr)
82 terminate();
83 rethrow_exception(__ptr_);
84}
85
86} // namespace std
lib/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp created+79
...@@ -0,0 +1,79 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <stdio.h>
11#include <stdlib.h>
12
13namespace std {
14
15exception_ptr::~exception_ptr() _NOEXCEPT
16{
17# warning exception_ptr not yet implemented
18 fprintf(stderr, "exception_ptr not yet implemented\n");
19 ::abort();
20}
21
22exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
23 : __ptr_(other.__ptr_)
24{
25# warning exception_ptr not yet implemented
26 fprintf(stderr, "exception_ptr not yet implemented\n");
27 ::abort();
28}
29
30exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
31{
32# warning exception_ptr not yet implemented
33 fprintf(stderr, "exception_ptr not yet implemented\n");
34 ::abort();
35}
36
37nested_exception::nested_exception() _NOEXCEPT
38 : __ptr_(current_exception())
39{
40}
41
42#if !defined(__GLIBCXX__)
43
44nested_exception::~nested_exception() _NOEXCEPT
45{
46}
47
48#endif
49
50_LIBCPP_NORETURN
51void
52nested_exception::rethrow_nested() const
53{
54# warning exception_ptr not yet implemented
55 fprintf(stderr, "exception_ptr not yet implemented\n");
56 ::abort();
57#if 0
58 if (__ptr_ == nullptr)
59 terminate();
60 rethrow_exception(__ptr_);
61#endif // FIXME
62}
63
64exception_ptr current_exception() _NOEXCEPT
65{
66# warning exception_ptr not yet implemented
67 fprintf(stderr, "exception_ptr not yet implemented\n");
68 ::abort();
69}
70
71_LIBCPP_NORETURN
72void rethrow_exception(exception_ptr p)
73{
74# warning exception_ptr not yet implemented
75 fprintf(stderr, "exception_ptr not yet implemented\n");
76 ::abort();
77}
78
79} // namespace std
lib/libcxx/src/support/runtime/new_handler_fallback.ipp created+26
...@@ -0,0 +1,26 @@
1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10namespace std {
11
12_LIBCPP_SAFE_STATIC static std::new_handler __new_handler;
13
14new_handler
15set_new_handler(new_handler handler) _NOEXCEPT
16{
17 return __libcpp_atomic_exchange(&__new_handler, handler);
18}
19
20new_handler
21get_new_handler() _NOEXCEPT
22{
23 return __libcpp_atomic_load(&__new_handler);
24}
25
26} // namespace std
lib/libcxx/src/support/runtime/stdexcept_default.ipp created+64
...@@ -0,0 +1,64 @@
1//===--------------------- stdexcept_default.ipp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "../../include/refstring.h"
10
11/* For _LIBCPPABI_VERSION */
12#if !defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY) && \
13 (defined(LIBCXX_BUILDING_LIBCXXABI) || defined(LIBCXXRT))
14#include <cxxabi.h>
15#endif
16
17static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char*), "");
18
19namespace std // purposefully not using versioning namespace
20{
21
22logic_error::logic_error(const string& msg) : __imp_(msg.c_str()) {}
23
24logic_error::logic_error(const char* msg) : __imp_(msg) {}
25
26logic_error::logic_error(const logic_error& le) _NOEXCEPT : __imp_(le.__imp_) {}
27
28logic_error& logic_error::operator=(const logic_error& le) _NOEXCEPT {
29 __imp_ = le.__imp_;
30 return *this;
31}
32
33runtime_error::runtime_error(const string& msg) : __imp_(msg.c_str()) {}
34
35runtime_error::runtime_error(const char* msg) : __imp_(msg) {}
36
37runtime_error::runtime_error(const runtime_error& re) _NOEXCEPT
38 : __imp_(re.__imp_) {}
39
40runtime_error& runtime_error::operator=(const runtime_error& re) _NOEXCEPT {
41 __imp_ = re.__imp_;
42 return *this;
43}
44
45#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)
46
47const char* logic_error::what() const _NOEXCEPT { return __imp_.c_str(); }
48
49const char* runtime_error::what() const _NOEXCEPT { return __imp_.c_str(); }
50
51logic_error::~logic_error() _NOEXCEPT {}
52domain_error::~domain_error() _NOEXCEPT {}
53invalid_argument::~invalid_argument() _NOEXCEPT {}
54length_error::~length_error() _NOEXCEPT {}
55out_of_range::~out_of_range() _NOEXCEPT {}
56
57runtime_error::~runtime_error() _NOEXCEPT {}
58range_error::~range_error() _NOEXCEPT {}
59overflow_error::~overflow_error() _NOEXCEPT {}
60underflow_error::~underflow_error() _NOEXCEPT {}
61
62#endif
63
64} // namespace std
lib/libcxx/src/support/runtime/stdexcept_vcruntime.ipp created+16
...@@ -0,0 +1,16 @@
1//===------------------- stdexcept_vcruntime.ipp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP_ABI_VCRUNTIME
10#error This file may only be used when defering to vcruntime
11#endif
12
13namespace std {
14logic_error::logic_error(std::string const& s) : exception(s.c_str()) {}
15runtime_error::runtime_error(std::string const& s) : exception(s.c_str()) {}
16} // namespace std
lib/libcxx/src/support/solaris/README created+4
...@@ -0,0 +1,4 @@
1This directory contains a partial implementation of the xlocale APIs for
2Solaris. Some portions are lifted from FreeBSD libc, and so are covered by a
32-clause BSD license instead of the MIT/UUIC license that the rest of libc++ is
4distributed under.
lib/libcxx/src/support/solaris/mbsnrtowcs.inc created+76
...@@ -0,0 +1,76 @@
1
2
3/*-
4 * As noted in the source, some portions of this implementation are copied from
5 * FreeBSD libc. These are covered by the following copyright:
6 *
7 * Copyright (c) 2002-2004 Tim J. Robbins.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31size_t
32mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
33 size_t nms, size_t len, mbstate_t * __restrict ps, locale_t loc)
34{
35 const char *s;
36 size_t nchr;
37 wchar_t wc;
38 size_t nb;
39 FIX_LOCALE(loc);
40
41 s = *src;
42 nchr = 0;
43
44 if (dst == NULL) {
45 for (;;) {
46 if ((nb = mbrtowc_l(&wc, s, nms, ps, loc)) == (size_t)-1)
47 /* Invalid sequence - mbrtowc() sets errno. */
48 return ((size_t)-1);
49 else if (nb == 0 || nb == (size_t)-2)
50 return (nchr);
51 s += nb;
52 nms -= nb;
53 nchr++;
54 }
55 /*NOTREACHED*/
56 }
57
58 while (len-- > 0) {
59 if ((nb = mbrtowc_l(dst, s, nms, ps, loc)) == (size_t)-1) {
60 *src = s;
61 return ((size_t)-1);
62 } else if (nb == (size_t)-2) {
63 *src = s + nms;
64 return (nchr);
65 } else if (nb == 0) {
66 *src = NULL;
67 return (nchr);
68 }
69 s += nb;
70 nms -= nb;
71 nchr++;
72 dst++;
73 }
74 *src = s;
75 return (nchr);
76}
lib/libcxx/src/support/solaris/wcsnrtombs.inc created+92
...@@ -0,0 +1,92 @@
1/*-
2 * Copyright (c) 2002-2004 Tim J. Robbins.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26
27size_t
28wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src,
29 size_t nwc, size_t len, mbstate_t * __restrict ps, locale_t loc)
30{
31 FIX_LOCALE(loc);
32 mbstate_t mbsbak;
33 char buf[MB_CUR_MAX_L(loc)];
34 const wchar_t *s;
35 size_t nbytes;
36 size_t nb;
37
38 s = *src;
39 nbytes = 0;
40
41 if (dst == NULL) {
42 while (nwc-- > 0) {
43 if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1)
44 /* Invalid character - wcrtomb() sets errno. */
45 return ((size_t)-1);
46 else if (*s == L'\0')
47 return (nbytes + nb - 1);
48 s++;
49 nbytes += nb;
50 }
51 return (nbytes);
52 }
53
54 while (len > 0 && nwc-- > 0) {
55 if (len > (size_t)MB_CUR_MAX_L(loc)) {
56 /* Enough space to translate in-place. */
57 if ((nb = wcrtomb_l(dst, *s, ps, loc)) == (size_t)-1) {
58 *src = s;
59 return ((size_t)-1);
60 }
61 } else {
62 /*
63 * May not be enough space; use temp. buffer.
64 *
65 * We need to save a copy of the conversion state
66 * here so we can restore it if the multibyte
67 * character is too long for the buffer.
68 */
69 mbsbak = *ps;
70 if ((nb = wcrtomb_l(buf, *s, ps, loc)) == (size_t)-1) {
71 *src = s;
72 return ((size_t)-1);
73 }
74 if (nb > (int)len) {
75 /* MB sequence for character won't fit. */
76 *ps = mbsbak;
77 break;
78 }
79 memcpy(dst, buf, nb);
80 }
81 if (*s == L'\0') {
82 *src = NULL;
83 return (nbytes + nb - 1);
84 }
85 s++;
86 dst += nb;
87 len -= nb;
88 nbytes += nb;
89 }
90 *src = s;
91 return (nbytes);
92}
lib/libcxx/src/support/solaris/xlocale.cpp created+68
...@@ -0,0 +1,68 @@
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifdef __sun__
10
11#include "support/solaris/xlocale.h"
12#include <stdarg.h>
13#include <stdio.h>
14#include <sys/localedef.h>
15
16extern "C" {
17
18int isxdigit_l(int __c, locale_t __l) {
19 return isxdigit(__c);
20}
21
22int iswxdigit_l(wint_t __c, locale_t __l) {
23 return isxdigit(__c);
24}
25
26// FIXME: This disregards the locale, which is Very Wrong
27#define vsnprintf_l(__s, __n, __l, __format, __va) \
28 vsnprintf(__s, __n, __format, __va)
29
30int snprintf_l(char *__s, size_t __n, locale_t __l, const char *__format, ...)
31{
32 va_list __va;
33 va_start(__va, __format);
34 int __res = vsnprintf_l(__s, __n , __l, __format, __va);
35 va_end(__va);
36 return __res;
37}
38
39int asprintf_l(char **__s, locale_t __l, const char *__format, ...) {
40 va_list __va;
41 va_start(__va, __format);
42 // FIXME:
43 int __res = vasprintf(__s, __format, __va);
44 va_end(__va);
45 return __res;
46}
47
48int sscanf_l(const char *__s, locale_t __l, const char *__format, ...) {
49 va_list __va;
50 va_start(__va, __format);
51 // FIXME:
52 int __res = vsscanf(__s, __format, __va);
53 va_end(__va);
54 return __res;
55}
56
57size_t mbrtowc_l(wchar_t *__pwc, const char *__pmb,
58 size_t __max, mbstate_t *__ps, locale_t __loc) {
59 return mbrtowc(__pwc, __pmb, __max, __ps);
60}
61
62struct lconv *localeconv_l(locale_t __l) {
63 return localeconv();
64}
65
66};
67
68#endif // __sun__
lib/libcxx/src/support/win32/locale_win32.cpp created+139
...@@ -0,0 +1,139 @@
1// -*- C++ -*-
2//===-------------------- support/win32/locale_win32.cpp ------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <locale>
11#include <cstdarg> // va_start, va_end
12#include <memory>
13#include <type_traits>
14
15int __libcpp_vasprintf(char **sptr, const char *__restrict fmt, va_list ap);
16
17using std::__libcpp_locale_guard;
18
19// FIXME: base currently unused. Needs manual work to construct the new locale
20locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
21{
22 return {_create_locale( LC_ALL, locale ), locale};
23}
24
25decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
26{
27#if defined(_LIBCPP_MSVCRT)
28 return ___mb_cur_max_l_func(__l);
29#else
30 __libcpp_locale_guard __current(__l);
31 return MB_CUR_MAX;
32#endif
33}
34
35lconv *localeconv_l( locale_t &loc )
36{
37 __libcpp_locale_guard __current(loc);
38 lconv *lc = localeconv();
39 if (!lc)
40 return lc;
41 return loc.__store_lconv(lc);
42}
43size_t mbrlen_l( const char *__restrict s, size_t n,
44 mbstate_t *__restrict ps, locale_t loc )
45{
46 __libcpp_locale_guard __current(loc);
47 return mbrlen( s, n, ps );
48}
49size_t mbsrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
50 size_t len, mbstate_t *__restrict ps, locale_t loc )
51{
52 __libcpp_locale_guard __current(loc);
53 return mbsrtowcs( dst, src, len, ps );
54}
55size_t wcrtomb_l( char *__restrict s, wchar_t wc, mbstate_t *__restrict ps,
56 locale_t loc )
57{
58 __libcpp_locale_guard __current(loc);
59 return wcrtomb( s, wc, ps );
60}
61size_t mbrtowc_l( wchar_t *__restrict pwc, const char *__restrict s,
62 size_t n, mbstate_t *__restrict ps, locale_t loc )
63{
64 __libcpp_locale_guard __current(loc);
65 return mbrtowc( pwc, s, n, ps );
66}
67size_t mbsnrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
68 size_t nms, size_t len, mbstate_t *__restrict ps, locale_t loc )
69{
70 __libcpp_locale_guard __current(loc);
71 return mbsnrtowcs( dst, src, nms, len, ps );
72}
73size_t wcsnrtombs_l( char *__restrict dst, const wchar_t **__restrict src,
74 size_t nwc, size_t len, mbstate_t *__restrict ps, locale_t loc )
75{
76 __libcpp_locale_guard __current(loc);
77 return wcsnrtombs( dst, src, nwc, len, ps );
78}
79wint_t btowc_l( int c, locale_t loc )
80{
81 __libcpp_locale_guard __current(loc);
82 return btowc( c );
83}
84int wctob_l( wint_t c, locale_t loc )
85{
86 __libcpp_locale_guard __current(loc);
87 return wctob( c );
88}
89
90int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...)
91{
92 va_list ap;
93 va_start( ap, format );
94#if defined(_LIBCPP_MSVCRT)
95 // FIXME: Remove usage of internal CRT function and globals.
96 int result = __stdio_common_vsprintf(
97 _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS | _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR,
98 ret, n, format, loc, ap);
99#else
100 __libcpp_locale_guard __current(loc);
101 int result = vsnprintf( ret, n, format, ap );
102#endif
103 va_end(ap);
104 return result;
105}
106
107int asprintf_l( char **ret, locale_t loc, const char *format, ... )
108{
109 va_list ap;
110 va_start( ap, format );
111 int result = vasprintf_l( ret, loc, format, ap );
112 va_end(ap);
113 return result;
114}
115int vasprintf_l( char **ret, locale_t loc, const char *format, va_list ap )
116{
117 __libcpp_locale_guard __current(loc);
118 return __libcpp_vasprintf( ret, format, ap );
119}
120
121#if !defined(_LIBCPP_MSVCRT)
122float strtof_l(const char* nptr, char** endptr, locale_t loc) {
123 __libcpp_locale_guard __current(loc);
124 return strtof(nptr, endptr);
125}
126
127long double strtold_l(const char* nptr, char** endptr, locale_t loc) {
128 __libcpp_locale_guard __current(loc);
129 return strtold(nptr, endptr);
130}
131#endif
132
133#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800
134size_t strftime_l(char *ret, size_t n, const char *format, const struct tm *tm,
135 locale_t loc) {
136 __libcpp_locale_guard __current(loc);
137 return strftime(ret, n, format, tm);
138}
139#endif
lib/libcxx/src/support/win32/support.cpp created+164
...@@ -0,0 +1,164 @@
1// -*- C++ -*-
2//===----------------------- support/win32/support.h ----------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <cstdarg> // va_start, va_end
11#include <cstddef> // size_t
12#include <cstdlib> // malloc
13#include <cstdio> // vsprintf, vsnprintf
14#include <cstring> // strcpy, wcsncpy
15#include <cwchar> // mbstate_t
16
17
18// Like sprintf, but when return value >= 0 it returns
19// a pointer to a malloc'd string in *sptr.
20// If return >= 0, use free to delete *sptr.
21int __libcpp_vasprintf( char **sptr, const char *__restrict format, va_list ap )
22{
23 *sptr = NULL;
24 // Query the count required.
25 int count = _vsnprintf( NULL, 0, format, ap );
26 if (count < 0)
27 return count;
28 size_t buffer_size = static_cast<size_t>(count) + 1;
29 char* p = static_cast<char*>(malloc(buffer_size));
30 if ( ! p )
31 return -1;
32 // If we haven't used exactly what was required, something is wrong.
33 // Maybe bug in vsnprintf. Report the error and return.
34 if (_vsnprintf(p, buffer_size, format, ap) != count) {
35 free(p);
36 return -1;
37 }
38 // All good. This is returning memory to the caller not freeing it.
39 *sptr = p;
40 return count;
41}
42
43// Returns >= 0: the number of wide characters found in the
44// multi byte sequence src (of src_size_bytes), that fit in the buffer dst
45// (of max_dest_chars elements size). The count returned excludes the
46// null terminator. When dst is NULL, no characters are copied
47// and no "out" parameters are updated.
48// Returns (size_t) -1: an incomplete sequence encountered.
49// Leaves *src pointing the next character to convert or NULL
50// if a null character was converted from *src.
51size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
52 size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
53{
54 const size_t terminated_sequence = static_cast<size_t>(0);
55 //const size_t invalid_sequence = static_cast<size_t>(-1);
56 const size_t incomplete_sequence = static_cast< size_t>(-2);
57
58 size_t dest_converted = 0;
59 size_t source_converted = 0;
60 size_t source_remaining = src_size_bytes;
61 size_t result = 0;
62 bool have_result = false;
63
64 // If dst is null then max_dest_chars should be ignored according to the
65 // standard. Setting max_dest_chars to a large value has this effect.
66 if (!dst)
67 max_dest_chars = static_cast<size_t>(-1);
68
69 while ( source_remaining ) {
70 if ( dst && dest_converted >= max_dest_chars )
71 break;
72 // Converts one multi byte character.
73 // if result > 0, it's the size in bytes of that character.
74 // othewise if result is zero it indicates the null character has been found.
75 // otherwise it's an error and errno may be set.
76 size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
77 // Don't do anything to change errno from here on.
78 if ( char_size > 0 ) {
79 source_remaining -= char_size;
80 source_converted += char_size;
81 ++dest_converted;
82 continue;
83 }
84 result = char_size;
85 have_result = true;
86 break;
87 }
88 if ( dst ) {
89 if ( have_result && result == terminated_sequence )
90 *src = NULL;
91 else
92 *src += source_converted;
93 }
94 if ( have_result && result != terminated_sequence && result != incomplete_sequence )
95 return static_cast<size_t>(-1);
96
97 return dest_converted;
98}
99
100// Converts max_source_chars from the wide character buffer pointer to by *src,
101// into the multi byte character sequence buffer stored at dst which must be
102// dst_size_bytes bytes in size.
103// Returns >= 0: the number of bytes in the sequence
104// converted from *src, excluding the null terminator.
105// Returns size_t(-1) if an error occurs, also sets errno.
106// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
107// and no "out" parameters are updated.
108size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
109 size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
110{
111 //const size_t invalid_sequence = static_cast<size_t>(-1);
112
113 size_t source_converted = 0;
114 size_t dest_converted = 0;
115 size_t dest_remaining = dst_size_bytes;
116 size_t char_size = 0;
117 const errno_t no_error = ( errno_t) 0;
118 errno_t result = ( errno_t ) 0;
119 bool have_result = false;
120 bool terminator_found = false;
121
122 // If dst is null then dst_size_bytes should be ignored according to the
123 // standard. Setting dest_remaining to a large value has this effect.
124 if (!dst)
125 dest_remaining = static_cast<size_t>(-1);
126
127 while ( source_converted != max_source_chars ) {
128 if ( ! dest_remaining )
129 break;
130 wchar_t c = (*src)[source_converted];
131 if ( dst )
132 result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
133 else
134 result = wcrtomb_s( &char_size, NULL, 0, c, ps);
135 // If result is zero there is no error and char_size contains the
136 // size of the multi-byte-sequence converted.
137 // Otherwise result indicates an errno type error.
138 if ( result == no_error ) {
139 if ( c == L'\0' ) {
140 terminator_found = true;
141 break;
142 }
143 ++source_converted;
144 if ( dst )
145 dest_remaining -= char_size;
146 dest_converted += char_size;
147 continue;
148 }
149 have_result = true;
150 break;
151 }
152 if ( dst ) {
153 if ( terminator_found )
154 *src = NULL;
155 else
156 *src = *src + source_converted;
157 }
158 if ( have_result && result != no_error ) {
159 errno = result;
160 return static_cast<size_t>(-1);
161 }
162
163 return dest_converted;
164}
lib/libcxx/src/support/win32/thread_win32.cpp created+275
...@@ -0,0 +1,275 @@
1// -*- C++ -*-
2//===-------------------- support/win32/thread_win32.cpp ------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include <__threading_support>
11#include <windows.h>
12#include <process.h>
13#include <fibersapi.h>
14
15_LIBCPP_BEGIN_NAMESPACE_STD
16
17static_assert(sizeof(__libcpp_mutex_t) == sizeof(SRWLOCK), "");
18static_assert(alignof(__libcpp_mutex_t) == alignof(SRWLOCK), "");
19
20static_assert(sizeof(__libcpp_recursive_mutex_t) == sizeof(CRITICAL_SECTION),
21 "");
22static_assert(alignof(__libcpp_recursive_mutex_t) == alignof(CRITICAL_SECTION),
23 "");
24
25static_assert(sizeof(__libcpp_condvar_t) == sizeof(CONDITION_VARIABLE), "");
26static_assert(alignof(__libcpp_condvar_t) == alignof(CONDITION_VARIABLE), "");
27
28static_assert(sizeof(__libcpp_exec_once_flag) == sizeof(INIT_ONCE), "");
29static_assert(alignof(__libcpp_exec_once_flag) == alignof(INIT_ONCE), "");
30
31static_assert(sizeof(__libcpp_thread_id) == sizeof(DWORD), "");
32static_assert(alignof(__libcpp_thread_id) == alignof(DWORD), "");
33
34static_assert(sizeof(__libcpp_thread_t) == sizeof(HANDLE), "");
35static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
36
37static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
38static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
39
40// Mutex
41int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
42{
43 InitializeCriticalSection((LPCRITICAL_SECTION)__m);
44 return 0;
45}
46
47int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m)
48{
49 EnterCriticalSection((LPCRITICAL_SECTION)__m);
50 return 0;
51}
52
53bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m)
54{
55 return TryEnterCriticalSection((LPCRITICAL_SECTION)__m) != 0;
56}
57
58int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t *__m)
59{
60 LeaveCriticalSection((LPCRITICAL_SECTION)__m);
61 return 0;
62}
63
64int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m)
65{
66 DeleteCriticalSection((LPCRITICAL_SECTION)__m);
67 return 0;
68}
69
70int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
71{
72 AcquireSRWLockExclusive((PSRWLOCK)__m);
73 return 0;
74}
75
76bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m)
77{
78 return TryAcquireSRWLockExclusive((PSRWLOCK)__m) != 0;
79}
80
81int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
82{
83 ReleaseSRWLockExclusive((PSRWLOCK)__m);
84 return 0;
85}
86
87int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
88{
89 static_cast<void>(__m);
90 return 0;
91}
92
93// Condition Variable
94int __libcpp_condvar_signal(__libcpp_condvar_t *__cv)
95{
96 WakeConditionVariable((PCONDITION_VARIABLE)__cv);
97 return 0;
98}
99
100int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv)
101{
102 WakeAllConditionVariable((PCONDITION_VARIABLE)__cv);
103 return 0;
104}
105
106int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m)
107{
108 SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m, INFINITE, 0);
109 return 0;
110}
111
112int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
113 __libcpp_timespec_t *__ts)
114{
115 using namespace _VSTD::chrono;
116
117 auto duration = seconds(__ts->tv_sec) + nanoseconds(__ts->tv_nsec);
118 auto abstime =
119 system_clock::time_point(duration_cast<system_clock::duration>(duration));
120 auto timeout_ms = duration_cast<milliseconds>(abstime - system_clock::now());
121
122 if (!SleepConditionVariableSRW((PCONDITION_VARIABLE)__cv, (PSRWLOCK)__m,
123 timeout_ms.count() > 0 ? timeout_ms.count()
124 : 0,
125 0))
126 {
127 auto __ec = GetLastError();
128 return __ec == ERROR_TIMEOUT ? ETIMEDOUT : __ec;
129 }
130 return 0;
131}
132
133int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
134{
135 static_cast<void>(__cv);
136 return 0;
137}
138
139// Execute Once
140static inline _LIBCPP_INLINE_VISIBILITY BOOL CALLBACK
141__libcpp_init_once_execute_once_thunk(PINIT_ONCE __init_once, PVOID __parameter,
142 PVOID *__context)
143{
144 static_cast<void>(__init_once);
145 static_cast<void>(__context);
146
147 void (*init_routine)(void) = reinterpret_cast<void (*)(void)>(__parameter);
148 init_routine();
149 return TRUE;
150}
151
152int __libcpp_execute_once(__libcpp_exec_once_flag *__flag,
153 void (*__init_routine)(void))
154{
155 if (!InitOnceExecuteOnce((PINIT_ONCE)__flag, __libcpp_init_once_execute_once_thunk,
156 reinterpret_cast<void *>(__init_routine), NULL))
157 return GetLastError();
158 return 0;
159}
160
161// Thread ID
162bool __libcpp_thread_id_equal(__libcpp_thread_id __lhs,
163 __libcpp_thread_id __rhs)
164{
165 return __lhs == __rhs;
166}
167
168bool __libcpp_thread_id_less(__libcpp_thread_id __lhs, __libcpp_thread_id __rhs)
169{
170 return __lhs < __rhs;
171}
172
173// Thread
174struct __libcpp_beginthreadex_thunk_data
175{
176 void *(*__func)(void *);
177 void *__arg;
178};
179
180static inline _LIBCPP_INLINE_VISIBILITY unsigned WINAPI
181__libcpp_beginthreadex_thunk(void *__raw_data)
182{
183 auto *__data =
184 static_cast<__libcpp_beginthreadex_thunk_data *>(__raw_data);
185 auto *__func = __data->__func;
186 void *__arg = __data->__arg;
187 delete __data;
188 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(__func(__arg)));
189}
190
191bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) {
192 return *__t == 0;
193}
194
195int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
196 void *__arg)
197{
198 auto *__data = new __libcpp_beginthreadex_thunk_data;
199 __data->__func = __func;
200 __data->__arg = __arg;
201
202 *__t = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0,
203 __libcpp_beginthreadex_thunk,
204 __data, 0, nullptr));
205
206 if (*__t)
207 return 0;
208 return GetLastError();
209}
210
211__libcpp_thread_id __libcpp_thread_get_current_id()
212{
213 return GetCurrentThreadId();
214}
215
216__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t)
217{
218 return GetThreadId(*__t);
219}
220
221int __libcpp_thread_join(__libcpp_thread_t *__t)
222{
223 if (WaitForSingleObjectEx(*__t, INFINITE, FALSE) == WAIT_FAILED)
224 return GetLastError();
225 if (!CloseHandle(*__t))
226 return GetLastError();
227 return 0;
228}
229
230int __libcpp_thread_detach(__libcpp_thread_t *__t)
231{
232 if (!CloseHandle(*__t))
233 return GetLastError();
234 return 0;
235}
236
237void __libcpp_thread_yield()
238{
239 SwitchToThread();
240}
241
242void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
243{
244 using namespace chrono;
245 // round-up to the nearest milisecond
246 milliseconds __ms =
247 duration_cast<milliseconds>(__ns + chrono::nanoseconds(999999));
248 // FIXME(compnerd) this should be an alertable sleep (WFSO or SleepEx)
249 Sleep(__ms.count());
250}
251
252// Thread Local Storage
253int __libcpp_tls_create(__libcpp_tls_key* __key,
254 void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
255{
256 DWORD index = FlsAlloc(__at_exit);
257 if (index == FLS_OUT_OF_INDEXES)
258 return GetLastError();
259 *__key = index;
260 return 0;
261}
262
263void *__libcpp_tls_get(__libcpp_tls_key __key)
264{
265 return FlsGetValue(__key);
266}
267
268int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
269{
270 if (!FlsSetValue(__key, __p))
271 return GetLastError();
272 return 0;
273}
274
275_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/system_error.cpp created+295
...@@ -0,0 +1,295 @@
1//===---------------------- system_error.cpp ------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10
11#include "system_error"
12
13#include "include/config_elast.h"
14#include "cerrno"
15#include "cstring"
16#include "cstdio"
17#include "cstdlib"
18#include "string"
19#include "string.h"
20#include "__debug"
21
22#if defined(__ANDROID__)
23#include <android/api-level.h>
24#endif
25
26_LIBCPP_BEGIN_NAMESPACE_STD
27
28// class error_category
29
30#if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
31error_category::error_category() _NOEXCEPT
32{
33}
34#endif
35
36error_category::~error_category() _NOEXCEPT
37{
38}
39
40error_condition
41error_category::default_error_condition(int ev) const _NOEXCEPT
42{
43 return error_condition(ev, *this);
44}
45
46bool
47error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT
48{
49 return default_error_condition(code) == condition;
50}
51
52bool
53error_category::equivalent(const error_code& code, int condition) const _NOEXCEPT
54{
55 return *this == code.category() && code.value() == condition;
56}
57
58#if !defined(_LIBCPP_HAS_NO_THREADS)
59namespace {
60
61// GLIBC also uses 1024 as the maximum buffer size internally.
62constexpr size_t strerror_buff_size = 1024;
63
64string do_strerror_r(int ev);
65
66#if defined(_LIBCPP_MSVCRT_LIKE)
67string do_strerror_r(int ev) {
68 char buffer[strerror_buff_size];
69 if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
70 return string(buffer);
71 std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
72 return string(buffer);
73}
74#else
75
76// Only one of the two following functions will be used, depending on
77// the return type of strerror_r:
78
79// For the GNU variant, a char* return value:
80__attribute__((unused)) const char *
81handle_strerror_r_return(char *strerror_return, char *buffer) {
82 // GNU always returns a string pointer in its return value. The
83 // string might point to either the input buffer, or a static
84 // buffer, but we don't care which.
85 return strerror_return;
86}
87
88// For the POSIX variant: an int return value.
89__attribute__((unused)) const char *
90handle_strerror_r_return(int strerror_return, char *buffer) {
91 // The POSIX variant either:
92 // - fills in the provided buffer and returns 0
93 // - returns a positive error value, or
94 // - returns -1 and fills in errno with an error value.
95 if (strerror_return == 0)
96 return buffer;
97
98 // Only handle EINVAL. Other errors abort.
99 int new_errno = strerror_return == -1 ? errno : strerror_return;
100 if (new_errno == EINVAL)
101 return "";
102
103 _LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r");
104 // FIXME maybe? 'strerror_buff_size' is likely to exceed the
105 // maximum error size so ERANGE shouldn't be returned.
106 std::abort();
107}
108
109// This function handles both GNU and POSIX variants, dispatching to
110// one of the two above functions.
111string do_strerror_r(int ev) {
112 char buffer[strerror_buff_size];
113 // Preserve errno around the call. (The C++ standard requires that
114 // system_error functions not modify errno).
115 const int old_errno = errno;
116 const char *error_message = handle_strerror_r_return(
117 ::strerror_r(ev, buffer, strerror_buff_size), buffer);
118 // If we didn't get any message, print one now.
119 if (!error_message[0]) {
120 std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
121 error_message = buffer;
122 }
123 errno = old_errno;
124 return string(error_message);
125}
126#endif
127} // end namespace
128#endif
129
130string
131__do_message::message(int ev) const
132{
133#if defined(_LIBCPP_HAS_NO_THREADS)
134 return string(::strerror(ev));
135#else
136 return do_strerror_r(ev);
137#endif
138}
139
140class _LIBCPP_HIDDEN __generic_error_category
141 : public __do_message
142{
143public:
144 virtual const char* name() const _NOEXCEPT;
145 virtual string message(int ev) const;
146};
147
148const char*
149__generic_error_category::name() const _NOEXCEPT
150{
151 return "generic";
152}
153
154string
155__generic_error_category::message(int ev) const
156{
157#ifdef _LIBCPP_ELAST
158 if (ev > _LIBCPP_ELAST)
159 return string("unspecified generic_category error");
160#endif // _LIBCPP_ELAST
161 return __do_message::message(ev);
162}
163
164const error_category&
165generic_category() _NOEXCEPT
166{
167 static __generic_error_category s;
168 return s;
169}
170
171class _LIBCPP_HIDDEN __system_error_category
172 : public __do_message
173{
174public:
175 virtual const char* name() const _NOEXCEPT;
176 virtual string message(int ev) const;
177 virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
178};
179
180const char*
181__system_error_category::name() const _NOEXCEPT
182{
183 return "system";
184}
185
186string
187__system_error_category::message(int ev) const
188{
189#ifdef _LIBCPP_ELAST
190 if (ev > _LIBCPP_ELAST)
191 return string("unspecified system_category error");
192#endif // _LIBCPP_ELAST
193 return __do_message::message(ev);
194}
195
196error_condition
197__system_error_category::default_error_condition(int ev) const _NOEXCEPT
198{
199#ifdef _LIBCPP_ELAST
200 if (ev > _LIBCPP_ELAST)
201 return error_condition(ev, system_category());
202#endif // _LIBCPP_ELAST
203 return error_condition(ev, generic_category());
204}
205
206const error_category&
207system_category() _NOEXCEPT
208{
209 static __system_error_category s;
210 return s;
211}
212
213// error_condition
214
215string
216error_condition::message() const
217{
218 return __cat_->message(__val_);
219}
220
221// error_code
222
223string
224error_code::message() const
225{
226 return __cat_->message(__val_);
227}
228
229// system_error
230
231string
232system_error::__init(const error_code& ec, string what_arg)
233{
234 if (ec)
235 {
236 if (!what_arg.empty())
237 what_arg += ": ";
238 what_arg += ec.message();
239 }
240 return what_arg;
241}
242
243system_error::system_error(error_code ec, const string& what_arg)
244 : runtime_error(__init(ec, what_arg)),
245 __ec_(ec)
246{
247}
248
249system_error::system_error(error_code ec, const char* what_arg)
250 : runtime_error(__init(ec, what_arg)),
251 __ec_(ec)
252{
253}
254
255system_error::system_error(error_code ec)
256 : runtime_error(__init(ec, "")),
257 __ec_(ec)
258{
259}
260
261system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
262 : runtime_error(__init(error_code(ev, ecat), what_arg)),
263 __ec_(error_code(ev, ecat))
264{
265}
266
267system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
268 : runtime_error(__init(error_code(ev, ecat), what_arg)),
269 __ec_(error_code(ev, ecat))
270{
271}
272
273system_error::system_error(int ev, const error_category& ecat)
274 : runtime_error(__init(error_code(ev, ecat), "")),
275 __ec_(error_code(ev, ecat))
276{
277}
278
279system_error::~system_error() _NOEXCEPT
280{
281}
282
283void
284__throw_system_error(int ev, const char* what_arg)
285{
286#ifndef _LIBCPP_NO_EXCEPTIONS
287 throw system_error(error_code(ev, system_category()), what_arg);
288#else
289 (void)ev;
290 (void)what_arg;
291 _VSTD::abort();
292#endif
293}
294
295_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/thread.cpp created+225
...@@ -0,0 +1,225 @@
1//===------------------------- thread.cpp----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__config"
10#ifndef _LIBCPP_HAS_NO_THREADS
11
12#include "thread"
13#include "exception"
14#include "vector"
15#include "future"
16#include "limits"
17#include <sys/types.h>
18
19#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
20# include <sys/param.h>
21# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
22# include <sys/sysctl.h>
23# endif
24#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
25
26#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
27# include <unistd.h>
28#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__) || defined(__wasi__)
29
30#if defined(__NetBSD__)
31#pragma weak pthread_create // Do not create libpthread dependency
32#endif
33
34#if defined(_LIBCPP_WIN32API)
35#include <windows.h>
36#endif
37
38#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
39#pragma comment(lib, "pthread")
40#endif
41
42_LIBCPP_BEGIN_NAMESPACE_STD
43
44thread::~thread()
45{
46 if (!__libcpp_thread_isnull(&__t_))
47 terminate();
48}
49
50void
51thread::join()
52{
53 int ec = EINVAL;
54 if (!__libcpp_thread_isnull(&__t_))
55 {
56 ec = __libcpp_thread_join(&__t_);
57 if (ec == 0)
58 __t_ = _LIBCPP_NULL_THREAD;
59 }
60
61 if (ec)
62 __throw_system_error(ec, "thread::join failed");
63}
64
65void
66thread::detach()
67{
68 int ec = EINVAL;
69 if (!__libcpp_thread_isnull(&__t_))
70 {
71 ec = __libcpp_thread_detach(&__t_);
72 if (ec == 0)
73 __t_ = _LIBCPP_NULL_THREAD;
74 }
75
76 if (ec)
77 __throw_system_error(ec, "thread::detach failed");
78}
79
80unsigned
81thread::hardware_concurrency() _NOEXCEPT
82{
83#if defined(CTL_HW) && defined(HW_NCPU)
84 unsigned n;
85 int mib[2] = {CTL_HW, HW_NCPU};
86 std::size_t s = sizeof(n);
87 sysctl(mib, 2, &n, &s, 0, 0);
88 return n;
89#elif defined(_SC_NPROCESSORS_ONLN)
90 long result = sysconf(_SC_NPROCESSORS_ONLN);
91 // sysconf returns -1 if the name is invalid, the option does not exist or
92 // does not have a definite limit.
93 // if sysconf returns some other negative number, we have no idea
94 // what is going on. Default to something safe.
95 if (result < 0)
96 return 0;
97 return static_cast<unsigned>(result);
98#elif defined(_LIBCPP_WIN32API)
99 SYSTEM_INFO info;
100 GetSystemInfo(&info);
101 return info.dwNumberOfProcessors;
102#else // defined(CTL_HW) && defined(HW_NCPU)
103 // TODO: grovel through /proc or check cpuid on x86 and similar
104 // instructions on other architectures.
105# if defined(_LIBCPP_WARNING)
106 _LIBCPP_WARNING("hardware_concurrency not yet implemented")
107# else
108# warning hardware_concurrency not yet implemented
109# endif
110 return 0; // Means not computable [thread.thread.static]
111#endif // defined(CTL_HW) && defined(HW_NCPU)
112}
113
114namespace this_thread
115{
116
117void
118sleep_for(const chrono::nanoseconds& ns)
119{
120 if (ns > chrono::nanoseconds::zero())
121 {
122 __libcpp_thread_sleep_for(ns);
123 }
124}
125
126} // this_thread
127
128__thread_specific_ptr<__thread_struct>&
129__thread_local_data()
130{
131 static __thread_specific_ptr<__thread_struct> __p;
132 return __p;
133}
134
135// __thread_struct_imp
136
137template <class T>
138class _LIBCPP_HIDDEN __hidden_allocator
139{
140public:
141 typedef T value_type;
142
143 T* allocate(size_t __n)
144 {return static_cast<T*>(::operator new(__n * sizeof(T)));}
145 void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}
146
147 size_t max_size() const {return size_t(~0) / sizeof(T);}
148};
149
150class _LIBCPP_HIDDEN __thread_struct_imp
151{
152 typedef vector<__assoc_sub_state*,
153 __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
154 typedef vector<pair<condition_variable*, mutex*>,
155 __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;
156
157 _AsyncStates async_states_;
158 _Notify notify_;
159
160 __thread_struct_imp(const __thread_struct_imp&);
161 __thread_struct_imp& operator=(const __thread_struct_imp&);
162public:
163 __thread_struct_imp() {}
164 ~__thread_struct_imp();
165
166 void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
167 void __make_ready_at_thread_exit(__assoc_sub_state* __s);
168};
169
170__thread_struct_imp::~__thread_struct_imp()
171{
172 for (_Notify::iterator i = notify_.begin(), e = notify_.end();
173 i != e; ++i)
174 {
175 i->second->unlock();
176 i->first->notify_all();
177 }
178 for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
179 i != e; ++i)
180 {
181 (*i)->__make_ready();
182 (*i)->__release_shared();
183 }
184}
185
186void
187__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
188{
189 notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
190}
191
192void
193__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
194{
195 async_states_.push_back(__s);
196 __s->__add_shared();
197}
198
199// __thread_struct
200
201__thread_struct::__thread_struct()
202 : __p_(new __thread_struct_imp)
203{
204}
205
206__thread_struct::~__thread_struct()
207{
208 delete __p_;
209}
210
211void
212__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
213{
214 __p_->notify_all_at_thread_exit(cv, m);
215}
216
217void
218__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
219{
220 __p_->__make_ready_at_thread_exit(__s);
221}
222
223_LIBCPP_END_NAMESPACE_STD
224
225#endif // !_LIBCPP_HAS_NO_THREADS
lib/libcxx/src/typeinfo.cpp created+57
...@@ -0,0 +1,57 @@
1//===------------------------- typeinfo.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "typeinfo"
10
11#if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_ABI_VCRUNTIME)
12#include <string.h>
13
14int std::type_info::__compare(const type_info &__rhs) const _NOEXCEPT {
15 if (&__data == &__rhs.__data)
16 return 0;
17 return strcmp(&__data.__decorated_name[1], &__rhs.__data.__decorated_name[1]);
18}
19
20const char *std::type_info::name() const _NOEXCEPT {
21 // TODO(compnerd) cache demangled &__data.__decorated_name[1]
22 return &__data.__decorated_name[1];
23}
24
25size_t std::type_info::hash_code() const _NOEXCEPT {
26#if defined(_WIN64)
27 constexpr size_t fnv_offset_basis = 14695981039346656037ull;
28 constexpr size_t fnv_prime = 10995116282110ull;
29#else
30 constexpr size_t fnv_offset_basis = 2166136261ull;
31 constexpr size_t fnv_prime = 16777619ull;
32#endif
33
34 size_t value = fnv_offset_basis;
35 for (const char* c = &__data.__decorated_name[1]; *c; ++c) {
36 value ^= static_cast<size_t>(static_cast<unsigned char>(*c));
37 value *= fnv_prime;
38 }
39
40#if defined(_WIN64)
41 value ^= value >> 32;
42#endif
43
44 return value;
45}
46#endif // _LIBCPP_ABI_MICROSOFT
47
48// FIXME: Remove the _LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY configuration.
49#if (!defined(LIBCXX_BUILDING_LIBCXXABI) && \
50 !defined(LIBCXXRT) && \
51 !defined(__GLIBCXX__) && \
52 !defined(_LIBCPP_ABI_VCRUNTIME)) || \
53 defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY)
54std::type_info::~type_info()
55{
56}
57#endif
lib/libcxx/src/utility.cpp created+15
...@@ -0,0 +1,15 @@
1//===------------------------ utility.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "utility"
10
11_LIBCPP_BEGIN_NAMESPACE_STD
12
13const piecewise_construct_t piecewise_construct{};
14
15_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/valarray.cpp created+57
...@@ -0,0 +1,57 @@
1//===------------------------ valarray.cpp --------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "valarray"
10
11_LIBCPP_BEGIN_NAMESPACE_STD
12
13// These two symbols are part of the v1 ABI but not part of the >=v2 ABI.
14#if _LIBCPP_ABI_VERSION == 1
15template _LIBCPP_FUNC_VIS valarray<size_t>::valarray(size_t);
16template _LIBCPP_FUNC_VIS valarray<size_t>::~valarray();
17#endif
18
19template void valarray<size_t>::resize(size_t, size_t);
20
21void
22gslice::__init(size_t __start)
23{
24 valarray<size_t> __indices(__size_.size());
25 size_t __k = __size_.size() != 0;
26 for (size_t __i = 0; __i < __size_.size(); ++__i)
27 __k *= __size_[__i];
28 __1d_.resize(__k);
29 if (__1d_.size())
30 {
31 __k = 0;
32 __1d_[__k] = __start;
33 while (true)
34 {
35 size_t __i = __indices.size() - 1;
36 while (true)
37 {
38 if (++__indices[__i] < __size_[__i])
39 {
40 ++__k;
41 __1d_[__k] = __1d_[__k-1] + __stride_[__i];
42 for (size_t __j = __i + 1; __j != __indices.size(); ++__j)
43 __1d_[__k] -= __stride_[__j] * (__size_[__j] - 1);
44 break;
45 }
46 else
47 {
48 if (__i == 0)
49 return;
50 __indices[__i--] = 0;
51 }
52 }
53 }
54 }
55}
56
57_LIBCPP_END_NAMESPACE_STD
lib/libcxx/src/variant.cpp created+17
...@@ -0,0 +1,17 @@
1//===------------------------ variant.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "variant"
10
11namespace std {
12
13const char* bad_variant_access::what() const noexcept {
14 return "bad_variant_access";
15}
16
17} // namespace std
lib/libcxx/src/vector.cpp created+15
...@@ -0,0 +1,15 @@
1//===------------------------- vector.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "vector"
10
11_LIBCPP_BEGIN_NAMESPACE_STD
12
13template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
14
15_LIBCPP_END_NAMESPACE_STD
lib/libcxxabi/LICENSE.TXT created+311
...@@ -0,0 +1,311 @@
1==============================================================================
2The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
3==============================================================================
4
5 Apache License
6 Version 2.0, January 2004
7 http://www.apache.org/licenses/
8
9 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
10
11 1. Definitions.
12
13 "License" shall mean the terms and conditions for use, reproduction,
14 and distribution as defined by Sections 1 through 9 of this document.
15
16 "Licensor" shall mean the copyright owner or entity authorized by
17 the copyright owner that is granting the License.
18
19 "Legal Entity" shall mean the union of the acting entity and all
20 other entities that control, are controlled by, or are under common
21 control with that entity. For the purposes of this definition,
22 "control" means (i) the power, direct or indirect, to cause the
23 direction or management of such entity, whether by contract or
24 otherwise, or (ii) ownership of fifty percent (50%) or more of the
25 outstanding shares, or (iii) beneficial ownership of such entity.
26
27 "You" (or "Your") shall mean an individual or Legal Entity
28 exercising permissions granted by this License.
29
30 "Source" form shall mean the preferred form for making modifications,
31 including but not limited to software source code, documentation
32 source, and configuration files.
33
34 "Object" form shall mean any form resulting from mechanical
35 transformation or translation of a Source form, including but
36 not limited to compiled object code, generated documentation,
37 and conversions to other media types.
38
39 "Work" shall mean the work of authorship, whether in Source or
40 Object form, made available under the License, as indicated by a
41 copyright notice that is included in or attached to the work
42 (an example is provided in the Appendix below).
43
44 "Derivative Works" shall mean any work, whether in Source or Object
45 form, that is based on (or derived from) the Work and for which the
46 editorial revisions, annotations, elaborations, or other modifications
47 represent, as a whole, an original work of authorship. For the purposes
48 of this License, Derivative Works shall not include works that remain
49 separable from, or merely link (or bind by name) to the interfaces of,
50 the Work and Derivative Works thereof.
51
52 "Contribution" shall mean any work of authorship, including
53 the original version of the Work and any modifications or additions
54 to that Work or Derivative Works thereof, that is intentionally
55 submitted to Licensor for inclusion in the Work by the copyright owner
56 or by an individual or Legal Entity authorized to submit on behalf of
57 the copyright owner. For the purposes of this definition, "submitted"
58 means any form of electronic, verbal, or written communication sent
59 to the Licensor or its representatives, including but not limited to
60 communication on electronic mailing lists, source code control systems,
61 and issue tracking systems that are managed by, or on behalf of, the
62 Licensor for the purpose of discussing and improving the Work, but
63 excluding communication that is conspicuously marked or otherwise
64 designated in writing by the copyright owner as "Not a Contribution."
65
66 "Contributor" shall mean Licensor and any individual or Legal Entity
67 on behalf of whom a Contribution has been received by Licensor and
68 subsequently incorporated within the Work.
69
70 2. Grant of Copyright License. Subject to the terms and conditions of
71 this License, each Contributor hereby grants to You a perpetual,
72 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73 copyright license to reproduce, prepare Derivative Works of,
74 publicly display, publicly perform, sublicense, and distribute the
75 Work and such Derivative Works in Source or Object form.
76
77 3. Grant of Patent License. Subject to the terms and conditions of
78 this License, each Contributor hereby grants to You a perpetual,
79 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
80 (except as stated in this section) patent license to make, have made,
81 use, offer to sell, sell, import, and otherwise transfer the Work,
82 where such license applies only to those patent claims licensable
83 by such Contributor that are necessarily infringed by their
84 Contribution(s) alone or by combination of their Contribution(s)
85 with the Work to which such Contribution(s) was submitted. If You
86 institute patent litigation against any entity (including a
87 cross-claim or counterclaim in a lawsuit) alleging that the Work
88 or a Contribution incorporated within the Work constitutes direct
89 or contributory patent infringement, then any patent licenses
90 granted to You under this License for that Work shall terminate
91 as of the date such litigation is filed.
92
93 4. Redistribution. You may reproduce and distribute copies of the
94 Work or Derivative Works thereof in any medium, with or without
95 modifications, and in Source or Object form, provided that You
96 meet the following conditions:
97
98 (a) You must give any other recipients of the Work or
99 Derivative Works a copy of this License; and
100
101 (b) You must cause any modified files to carry prominent notices
102 stating that You changed the files; and
103
104 (c) You must retain, in the Source form of any Derivative Works
105 that You distribute, all copyright, patent, trademark, and
106 attribution notices from the Source form of the Work,
107 excluding those notices that do not pertain to any part of
108 the Derivative Works; and
109
110 (d) If the Work includes a "NOTICE" text file as part of its
111 distribution, then any Derivative Works that You distribute must
112 include a readable copy of the attribution notices contained
113 within such NOTICE file, excluding those notices that do not
114 pertain to any part of the Derivative Works, in at least one
115 of the following places: within a NOTICE text file distributed
116 as part of the Derivative Works; within the Source form or
117 documentation, if provided along with the Derivative Works; or,
118 within a display generated by the Derivative Works, if and
119 wherever such third-party notices normally appear. The contents
120 of the NOTICE file are for informational purposes only and
121 do not modify the License. You may add Your own attribution
122 notices within Derivative Works that You distribute, alongside
123 or as an addendum to the NOTICE text from the Work, provided
124 that such additional attribution notices cannot be construed
125 as modifying the License.
126
127 You may add Your own copyright statement to Your modifications and
128 may provide additional or different license terms and conditions
129 for use, reproduction, or distribution of Your modifications, or
130 for any such Derivative Works as a whole, provided Your use,
131 reproduction, and distribution of the Work otherwise complies with
132 the conditions stated in this License.
133
134 5. Submission of Contributions. Unless You explicitly state otherwise,
135 any Contribution intentionally submitted for inclusion in the Work
136 by You to the Licensor shall be under the terms and conditions of
137 this License, without any additional terms or conditions.
138 Notwithstanding the above, nothing herein shall supersede or modify
139 the terms of any separate license agreement you may have executed
140 with Licensor regarding such Contributions.
141
142 6. Trademarks. This License does not grant permission to use the trade
143 names, trademarks, service marks, or product names of the Licensor,
144 except as required for reasonable and customary use in describing the
145 origin of the Work and reproducing the content of the NOTICE file.
146
147 7. Disclaimer of Warranty. Unless required by applicable law or
148 agreed to in writing, Licensor provides the Work (and each
149 Contributor provides its Contributions) on an "AS IS" BASIS,
150 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
151 implied, including, without limitation, any warranties or conditions
152 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
153 PARTICULAR PURPOSE. You are solely responsible for determining the
154 appropriateness of using or redistributing the Work and assume any
155 risks associated with Your exercise of permissions under this License.
156
157 8. Limitation of Liability. In no event and under no legal theory,
158 whether in tort (including negligence), contract, or otherwise,
159 unless required by applicable law (such as deliberate and grossly
160 negligent acts) or agreed to in writing, shall any Contributor be
161 liable to You for damages, including any direct, indirect, special,
162 incidental, or consequential damages of any character arising as a
163 result of this License or out of the use or inability to use the
164 Work (including but not limited to damages for loss of goodwill,
165 work stoppage, computer failure or malfunction, or any and all
166 other commercial damages or losses), even if such Contributor
167 has been advised of the possibility of such damages.
168
169 9. Accepting Warranty or Additional Liability. While redistributing
170 the Work or Derivative Works thereof, You may choose to offer,
171 and charge a fee for, acceptance of support, warranty, indemnity,
172 or other liability obligations and/or rights consistent with this
173 License. However, in accepting such obligations, You may act only
174 on Your own behalf and on Your sole responsibility, not on behalf
175 of any other Contributor, and only if You agree to indemnify,
176 defend, and hold each Contributor harmless for any liability
177 incurred by, or claims asserted against, such Contributor by reason
178 of your accepting any such warranty or additional liability.
179
180 END OF TERMS AND CONDITIONS
181
182 APPENDIX: How to apply the Apache License to your work.
183
184 To apply the Apache License to your work, attach the following
185 boilerplate notice, with the fields enclosed by brackets "[]"
186 replaced with your own identifying information. (Don't include
187 the brackets!) The text should be enclosed in the appropriate
188 comment syntax for the file format. We also recommend that a
189 file or class name and description of purpose be included on the
190 same "printed page" as the copyright notice for easier
191 identification within third-party archives.
192
193 Copyright [yyyy] [name of copyright owner]
194
195 Licensed under the Apache License, Version 2.0 (the "License");
196 you may not use this file except in compliance with the License.
197 You may obtain a copy of the License at
198
199 http://www.apache.org/licenses/LICENSE-2.0
200
201 Unless required by applicable law or agreed to in writing, software
202 distributed under the License is distributed on an "AS IS" BASIS,
203 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
204 See the License for the specific language governing permissions and
205 limitations under the License.
206
207
208---- LLVM Exceptions to the Apache 2.0 License ----
209
210As an exception, if, as a result of your compiling your source code, portions
211of this Software are embedded into an Object form of such source code, you
212may redistribute such embedded portions in such Object form without complying
213with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
214
215In addition, if you combine or link compiled forms of this Software with
216software that is licensed under the GPLv2 ("Combined Software") and if a
217court of competent jurisdiction determines that the patent provision (Section
2183), the indemnity provision (Section 9) or other Section of the License
219conflicts with the conditions of the GPLv2, you may retroactively and
220prospectively choose to deem waived or otherwise exclude such Section(s) of
221the License, but only in their entirety and only with respect to the Combined
222Software.
223
224==============================================================================
225Software from third parties included in the LLVM Project:
226==============================================================================
227The LLVM Project contains third party software which is under different license
228terms. All such code will be identified clearly using at least one of two
229mechanisms:
2301) It will be in a separate directory tree with its own `LICENSE.txt` or
231 `LICENSE` file at the top containing the specific license and restrictions
232 which apply to that software, or
2332) It will contain specific license and restriction terms at the top of every
234 file.
235
236==============================================================================
237Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
238==============================================================================
239
240The libc++abi library is dual licensed under both the University of Illinois
241"BSD-Like" license and the MIT license. As a user of this code you may choose
242to use it under either license. As a contributor, you agree to allow your code
243to be used under both.
244
245Full text of the relevant licenses is included below.
246
247==============================================================================
248
249University of Illinois/NCSA
250Open Source License
251
252Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
253
254All rights reserved.
255
256Developed by:
257
258 LLVM Team
259
260 University of Illinois at Urbana-Champaign
261
262 http://llvm.org
263
264Permission is hereby granted, free of charge, to any person obtaining a copy of
265this software and associated documentation files (the "Software"), to deal with
266the Software without restriction, including without limitation the rights to
267use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
268of the Software, and to permit persons to whom the Software is furnished to do
269so, subject to the following conditions:
270
271 * Redistributions of source code must retain the above copyright notice,
272 this list of conditions and the following disclaimers.
273
274 * Redistributions in binary form must reproduce the above copyright notice,
275 this list of conditions and the following disclaimers in the
276 documentation and/or other materials provided with the distribution.
277
278 * Neither the names of the LLVM Team, University of Illinois at
279 Urbana-Champaign, nor the names of its contributors may be used to
280 endorse or promote products derived from this Software without specific
281 prior written permission.
282
283THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
284IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
285FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
286CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
287LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
288OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
289SOFTWARE.
290
291==============================================================================
292
293Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
294
295Permission is hereby granted, free of charge, to any person obtaining a copy
296of this software and associated documentation files (the "Software"), to deal
297in the Software without restriction, including without limitation the rights
298to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
299copies of the Software, and to permit persons to whom the Software is
300furnished to do so, subject to the following conditions:
301
302The above copyright notice and this permission notice shall be included in
303all copies or substantial portions of the Software.
304
305THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
306IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
307FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
308AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
309LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
310OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
311THE SOFTWARE.
lib/libcxxabi/include/__cxxabi_config.h created+79
...@@ -0,0 +1,79 @@
1//===-------------------------- __cxxabi_config.h -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef ____CXXABI_CONFIG_H
10#define ____CXXABI_CONFIG_H
11
12#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
13 !defined(__ARM_DWARF_EH__)
14#define _LIBCXXABI_ARM_EHABI
15#endif
16
17#if !defined(__has_attribute)
18#define __has_attribute(_attribute_) 0
19#endif
20
21#if defined(_WIN32)
22 #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
23 #define _LIBCXXABI_HIDDEN
24 #define _LIBCXXABI_DATA_VIS
25 #define _LIBCXXABI_FUNC_VIS
26 #define _LIBCXXABI_TYPE_VIS
27 #elif defined(_LIBCXXABI_BUILDING_LIBRARY)
28 #define _LIBCXXABI_HIDDEN
29 #define _LIBCXXABI_DATA_VIS __declspec(dllexport)
30 #define _LIBCXXABI_FUNC_VIS __declspec(dllexport)
31 #define _LIBCXXABI_TYPE_VIS __declspec(dllexport)
32 #else
33 #define _LIBCXXABI_HIDDEN
34 #define _LIBCXXABI_DATA_VIS __declspec(dllimport)
35 #define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
36 #define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
37 #endif
38#else
39 #if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
40 #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
41 #define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default")))
42 #define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default")))
43 #if __has_attribute(__type_visibility__)
44 #define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default")))
45 #else
46 #define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default")))
47 #endif
48 #else
49 #define _LIBCXXABI_HIDDEN
50 #define _LIBCXXABI_DATA_VIS
51 #define _LIBCXXABI_FUNC_VIS
52 #define _LIBCXXABI_TYPE_VIS
53 #endif
54#endif
55
56#if defined(_WIN32)
57#define _LIBCXXABI_WEAK
58#else
59#define _LIBCXXABI_WEAK __attribute__((__weak__))
60#endif
61
62#if defined(__clang__)
63#define _LIBCXXABI_COMPILER_CLANG
64#elif defined(__GNUC__)
65#define _LIBCXXABI_COMPILER_GCC
66#endif
67
68#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG)
69#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi")))
70#else
71#define _LIBCXXABI_NO_CFI
72#endif
73
74// wasm32 follows the arm32 ABI convention of using 32-bit guard.
75#if defined(__arm__) || defined(__wasm32__)
76# define _LIBCXXABI_GUARD_ABI_ARM
77#endif
78
79#endif // ____CXXABI_CONFIG_H
lib/libcxxabi/include/cxxabi.h created+176
...@@ -0,0 +1,176 @@
1//===--------------------------- cxxabi.h ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef __CXXABI_H
10#define __CXXABI_H
11
12/*
13 * This header provides the interface to the C++ ABI as defined at:
14 * https://itanium-cxx-abi.github.io/cxx-abi/
15 */
16
17#include <stddef.h>
18#include <stdint.h>
19
20#include <__cxxabi_config.h>
21
22#define _LIBCPPABI_VERSION 1002
23#define _LIBCXXABI_NORETURN __attribute__((noreturn))
24
25#ifdef __cplusplus
26
27namespace std {
28#if defined(_WIN32)
29class _LIBCXXABI_TYPE_VIS type_info; // forward declaration
30#else
31class type_info; // forward declaration
32#endif
33}
34
35
36// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
37namespace __cxxabiv1 {
38extern "C" {
39
40// 2.4.2 Allocating the Exception Object
41extern _LIBCXXABI_FUNC_VIS void *
42__cxa_allocate_exception(size_t thrown_size) throw();
43extern _LIBCXXABI_FUNC_VIS void
44__cxa_free_exception(void *thrown_exception) throw();
45
46// 2.4.3 Throwing the Exception Object
47extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
48__cxa_throw(void *thrown_exception, std::type_info *tinfo,
49 void (*dest)(void *));
50
51// 2.5.3 Exception Handlers
52extern _LIBCXXABI_FUNC_VIS void *
53__cxa_get_exception_ptr(void *exceptionObject) throw();
54extern _LIBCXXABI_FUNC_VIS void *
55__cxa_begin_catch(void *exceptionObject) throw();
56extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch();
57#if defined(_LIBCXXABI_ARM_EHABI)
58extern _LIBCXXABI_FUNC_VIS bool
59__cxa_begin_cleanup(void *exceptionObject) throw();
60extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup();
61#endif
62extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type();
63
64// 2.5.4 Rethrowing Exceptions
65extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow();
66
67// 2.6 Auxiliary Runtime APIs
68extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void);
69extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
70extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
71__cxa_throw_bad_array_new_length(void);
72
73// 3.2.6 Pure Virtual Function API
74extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
75
76// 3.2.7 Deleted Virtual Function API
77extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
78
79// 3.3.2 One-time Construction API
80#if defined(_LIBCXXABI_GUARD_ABI_ARM)
81extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint32_t *);
82extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint32_t *);
83extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint32_t *);
84#else
85extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint64_t *);
86extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint64_t *);
87extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint64_t *);
88#endif
89
90// 3.3.3 Array Construction and Destruction API
91extern _LIBCXXABI_FUNC_VIS void *
92__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
93 void (*constructor)(void *), void (*destructor)(void *));
94
95extern _LIBCXXABI_FUNC_VIS void *
96__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
97 void (*constructor)(void *), void (*destructor)(void *),
98 void *(*alloc)(size_t), void (*dealloc)(void *));
99
100extern _LIBCXXABI_FUNC_VIS void *
101__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
102 void (*constructor)(void *), void (*destructor)(void *),
103 void *(*alloc)(size_t), void (*dealloc)(void *, size_t));
104
105extern _LIBCXXABI_FUNC_VIS void
106__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
107 void (*constructor)(void *), void (*destructor)(void *));
108
109extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
110 size_t element_count,
111 size_t element_size,
112 void (*destructor)(void *));
113
114extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
115 size_t element_count,
116 size_t element_size,
117 void (*destructor)(void *));
118
119extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
120 size_t element_size,
121 size_t padding_size,
122 void (*destructor)(void *));
123
124extern _LIBCXXABI_FUNC_VIS void
125__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
126 void (*destructor)(void *), void (*dealloc)(void *));
127
128extern _LIBCXXABI_FUNC_VIS void
129__cxa_vec_delete3(void *__array_address, size_t element_size,
130 size_t padding_size, void (*destructor)(void *),
131 void (*dealloc)(void *, size_t));
132
133extern _LIBCXXABI_FUNC_VIS void
134__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count,
135 size_t element_size, void (*constructor)(void *, void *),
136 void (*destructor)(void *));
137
138// 3.3.5.3 Runtime API
139extern _LIBCXXABI_FUNC_VIS int __cxa_atexit(void (*f)(void *), void *p,
140 void *d);
141extern _LIBCXXABI_FUNC_VIS int __cxa_finalize(void *);
142
143// 3.4 Demangler API
144extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name,
145 char *output_buffer,
146 size_t *length, int *status);
147
148// Apple additions to support C++ 0x exception_ptr class
149// These are primitives to wrap a smart pointer around an exception object
150extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw();
151extern _LIBCXXABI_FUNC_VIS void
152__cxa_rethrow_primary_exception(void *primary_exception);
153extern _LIBCXXABI_FUNC_VIS void
154__cxa_increment_exception_refcount(void *primary_exception) throw();
155extern _LIBCXXABI_FUNC_VIS void
156__cxa_decrement_exception_refcount(void *primary_exception) throw();
157
158// Apple extension to support std::uncaught_exception()
159extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw();
160extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw();
161
162#if defined(__linux__) || defined(__Fuchsia__)
163// Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI.
164// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
165extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *,
166 void *) throw();
167#endif
168
169} // extern "C"
170} // namespace __cxxabiv1
171
172namespace abi = __cxxabiv1;
173
174#endif // __cplusplus
175
176#endif // __CXXABI_H
lib/libcxxabi/src/abort_message.cpp created+77
...@@ -0,0 +1,77 @@
1//===------------------------- abort_message.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <stdarg.h>
12#include "abort_message.h"
13
14#ifdef __BIONIC__
15#include <android/api-level.h>
16#if __ANDROID_API__ >= 21
17#include <syslog.h>
18extern "C" void android_set_abort_message(const char* msg);
19#else
20#include <assert.h>
21#endif // __ANDROID_API__ >= 21
22#endif // __BIONIC__
23
24#ifdef __APPLE__
25# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
26# define HAVE_CRASHREPORTERCLIENT_H
27# include <CrashReporterClient.h>
28# endif
29#endif
30
31void abort_message(const char* format, ...)
32{
33 // write message to stderr
34#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL)
35#ifdef __APPLE__
36 fprintf(stderr, "libc++abi.dylib: ");
37#endif
38 va_list list;
39 va_start(list, format);
40 vfprintf(stderr, format, list);
41 va_end(list);
42 fprintf(stderr, "\n");
43#endif
44
45#if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H)
46 // record message in crash report
47 char* buffer;
48 va_list list2;
49 va_start(list2, format);
50 vasprintf(&buffer, format, list2);
51 va_end(list2);
52 CRSetCrashLogMessage(buffer);
53#elif defined(__BIONIC__)
54 char* buffer;
55 va_list list2;
56 va_start(list2, format);
57 vasprintf(&buffer, format, list2);
58 va_end(list2);
59
60#if __ANDROID_API__ >= 21
61 // Show error in tombstone.
62 android_set_abort_message(buffer);
63
64 // Show error in logcat.
65 openlog("libc++abi", 0, 0);
66 syslog(LOG_CRIT, "%s", buffer);
67 closelog();
68#else
69 // The good error reporting wasn't available in Android until L. Since we're
70 // about to abort anyway, just call __assert2, which will log _somewhere_
71 // (tombstone and/or logcat) in older releases.
72 __assert2(__FILE__, __LINE__, __func__, buffer);
73#endif // __ANDROID_API__ >= 21
74#endif // __BIONIC__
75
76 abort();
77}
lib/libcxxabi/src/abort_message.h created+26
...@@ -0,0 +1,26 @@
1//===-------------------------- abort_message.h-----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef __ABORT_MESSAGE_H_
10#define __ABORT_MESSAGE_H_
11
12#include "cxxabi.h"
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
19abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
20
21#ifdef __cplusplus
22}
23#endif
24
25#endif
26
lib/libcxxabi/src/cxa_aux_runtime.cpp created+43
...@@ -0,0 +1,43 @@
1//===------------------------ cxa_aux_runtime.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Auxiliary Runtime APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-aux
10//===----------------------------------------------------------------------===//
11
12#include "cxxabi.h"
13#include <new>
14#include <typeinfo>
15
16namespace __cxxabiv1 {
17extern "C" {
18_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) {
19#ifndef _LIBCXXABI_NO_EXCEPTIONS
20 throw std::bad_cast();
21#else
22 std::terminate();
23#endif
24}
25
26_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) {
27#ifndef _LIBCXXABI_NO_EXCEPTIONS
28 throw std::bad_typeid();
29#else
30 std::terminate();
31#endif
32}
33
34_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
35__cxa_throw_bad_array_new_length(void) {
36#ifndef _LIBCXXABI_NO_EXCEPTIONS
37 throw std::bad_array_new_length();
38#else
39 std::terminate();
40#endif
41}
42} // extern "C"
43} // abi
lib/libcxxabi/src/cxa_default_handlers.cpp created+124
...@@ -0,0 +1,124 @@
1//===------------------------- cxa_default_handlers.cpp -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the default terminate_handler and unexpected_handler.
9//===----------------------------------------------------------------------===//
10
11#include <exception>
12#include <stdlib.h>
13#include "abort_message.h"
14#include "cxxabi.h"
15#include "cxa_handlers.h"
16#include "cxa_exception.h"
17#include "private_typeinfo.h"
18#include "include/atomic_support.h"
19
20#if !defined(LIBCXXABI_SILENT_TERMINATE)
21
22_LIBCPP_SAFE_STATIC
23static const char* cause = "uncaught";
24
25__attribute__((noreturn))
26static void demangling_terminate_handler()
27{
28#ifndef _LIBCXXABI_NO_EXCEPTIONS
29 // If there might be an uncaught exception
30 using namespace __cxxabiv1;
31 __cxa_eh_globals* globals = __cxa_get_globals_fast();
32 if (globals)
33 {
34 __cxa_exception* exception_header = globals->caughtExceptions;
35 // If there is an uncaught exception
36 if (exception_header)
37 {
38 _Unwind_Exception* unwind_exception =
39 reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
40 if (__isOurExceptionClass(unwind_exception))
41 {
42 void* thrown_object =
43 __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
44 ((__cxa_dependent_exception*)exception_header)->primaryException :
45 exception_header + 1;
46 const __shim_type_info* thrown_type =
47 static_cast<const __shim_type_info*>(exception_header->exceptionType);
48 // Try to get demangled name of thrown_type
49 int status;
50 char buf[1024];
51 size_t len = sizeof(buf);
52 const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
53 if (status != 0)
54 name = thrown_type->name();
55 // If the uncaught exception can be caught with std::exception&
56 const __shim_type_info* catch_type =
57 static_cast<const __shim_type_info*>(&typeid(std::exception));
58 if (catch_type->can_catch(thrown_type, thrown_object))
59 {
60 // Include the what() message from the exception
61 const std::exception* e = static_cast<const std::exception*>(thrown_object);
62 abort_message("terminating with %s exception of type %s: %s",
63 cause, name, e->what());
64 }
65 else
66 // Else just note that we're terminating with an exception
67 abort_message("terminating with %s exception of type %s",
68 cause, name);
69 }
70 else
71 // Else we're terminating with a foreign exception
72 abort_message("terminating with %s foreign exception", cause);
73 }
74 }
75#endif
76 // Else just note that we're terminating
77 abort_message("terminating");
78}
79
80__attribute__((noreturn))
81static void demangling_unexpected_handler()
82{
83 cause = "unexpected";
84 std::terminate();
85}
86
87static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
88static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
89#else
90static constexpr std::terminate_handler default_terminate_handler = ::abort;
91static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
92#endif
93
94//
95// Global variables that hold the pointers to the current handler
96//
97_LIBCXXABI_DATA_VIS
98_LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
99
100_LIBCXXABI_DATA_VIS
101_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
102
103namespace std
104{
105
106unexpected_handler
107set_unexpected(unexpected_handler func) _NOEXCEPT
108{
109 if (func == 0)
110 func = default_unexpected_handler;
111 return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
112 _AO_Acq_Rel);
113}
114
115terminate_handler
116set_terminate(terminate_handler func) _NOEXCEPT
117{
118 if (func == 0)
119 func = default_terminate_handler;
120 return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
121 _AO_Acq_Rel);
122}
123
124}
lib/libcxxabi/src/cxa_demangle.cpp created+366
...@@ -0,0 +1,366 @@
1//===-------------------------- cxa_demangle.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// FIXME: (possibly) incomplete list of features that clang mangles that this
10// file does not yet support:
11// - C++ modules TS
12
13#include "demangle/ItaniumDemangle.h"
14#include "__cxxabi_config.h"
15#include <cassert>
16#include <cctype>
17#include <cstdio>
18#include <cstdlib>
19#include <cstring>
20#include <functional>
21#include <numeric>
22#include <utility>
23
24using namespace itanium_demangle;
25
26constexpr const char *itanium_demangle::FloatData<float>::spec;
27constexpr const char *itanium_demangle::FloatData<double>::spec;
28constexpr const char *itanium_demangle::FloatData<long double>::spec;
29
30// <discriminator> := _ <non-negative number> # when number < 10
31// := __ <non-negative number> _ # when number >= 10
32// extension := decimal-digit+ # at the end of string
33const char *itanium_demangle::parse_discriminator(const char *first,
34 const char *last) {
35 // parse but ignore discriminator
36 if (first != last) {
37 if (*first == '_') {
38 const char *t1 = first + 1;
39 if (t1 != last) {
40 if (std::isdigit(*t1))
41 first = t1 + 1;
42 else if (*t1 == '_') {
43 for (++t1; t1 != last && std::isdigit(*t1); ++t1)
44 ;
45 if (t1 != last && *t1 == '_')
46 first = t1 + 1;
47 }
48 }
49 } else if (std::isdigit(*first)) {
50 const char *t1 = first + 1;
51 for (; t1 != last && std::isdigit(*t1); ++t1)
52 ;
53 if (t1 == last)
54 first = last;
55 }
56 }
57 return first;
58}
59
60#ifndef NDEBUG
61namespace {
62struct DumpVisitor {
63 unsigned Depth = 0;
64 bool PendingNewline = false;
65
66 template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
67 return true;
68 }
69 static bool wantsNewline(NodeArray A) { return !A.empty(); }
70 static constexpr bool wantsNewline(...) { return false; }
71
72 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
73 for (bool B : {wantsNewline(Vs)...})
74 if (B)
75 return true;
76 return false;
77 }
78
79 void printStr(const char *S) { fprintf(stderr, "%s", S); }
80 void print(StringView SV) {
81 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
82 }
83 void print(const Node *N) {
84 if (N)
85 N->visit(std::ref(*this));
86 else
87 printStr("<null>");
88 }
89 void print(NodeArray A) {
90 ++Depth;
91 printStr("{");
92 bool First = true;
93 for (const Node *N : A) {
94 if (First)
95 print(N);
96 else
97 printWithComma(N);
98 First = false;
99 }
100 printStr("}");
101 --Depth;
102 }
103
104 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
105 void print(bool B) { printStr(B ? "true" : "false"); }
106
107 template <class T>
108 typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
109 fprintf(stderr, "%llu", (unsigned long long)N);
110 }
111
112 template <class T>
113 typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
114 fprintf(stderr, "%lld", (long long)N);
115 }
116
117 void print(ReferenceKind RK) {
118 switch (RK) {
119 case ReferenceKind::LValue:
120 return printStr("ReferenceKind::LValue");
121 case ReferenceKind::RValue:
122 return printStr("ReferenceKind::RValue");
123 }
124 }
125 void print(FunctionRefQual RQ) {
126 switch (RQ) {
127 case FunctionRefQual::FrefQualNone:
128 return printStr("FunctionRefQual::FrefQualNone");
129 case FunctionRefQual::FrefQualLValue:
130 return printStr("FunctionRefQual::FrefQualLValue");
131 case FunctionRefQual::FrefQualRValue:
132 return printStr("FunctionRefQual::FrefQualRValue");
133 }
134 }
135 void print(Qualifiers Qs) {
136 if (!Qs) return printStr("QualNone");
137 struct QualName { Qualifiers Q; const char *Name; } Names[] = {
138 {QualConst, "QualConst"},
139 {QualVolatile, "QualVolatile"},
140 {QualRestrict, "QualRestrict"},
141 };
142 for (QualName Name : Names) {
143 if (Qs & Name.Q) {
144 printStr(Name.Name);
145 Qs = Qualifiers(Qs & ~Name.Q);
146 if (Qs) printStr(" | ");
147 }
148 }
149 }
150 void print(SpecialSubKind SSK) {
151 switch (SSK) {
152 case SpecialSubKind::allocator:
153 return printStr("SpecialSubKind::allocator");
154 case SpecialSubKind::basic_string:
155 return printStr("SpecialSubKind::basic_string");
156 case SpecialSubKind::string:
157 return printStr("SpecialSubKind::string");
158 case SpecialSubKind::istream:
159 return printStr("SpecialSubKind::istream");
160 case SpecialSubKind::ostream:
161 return printStr("SpecialSubKind::ostream");
162 case SpecialSubKind::iostream:
163 return printStr("SpecialSubKind::iostream");
164 }
165 }
166 void print(TemplateParamKind TPK) {
167 switch (TPK) {
168 case TemplateParamKind::Type:
169 return printStr("TemplateParamKind::Type");
170 case TemplateParamKind::NonType:
171 return printStr("TemplateParamKind::NonType");
172 case TemplateParamKind::Template:
173 return printStr("TemplateParamKind::Template");
174 }
175 }
176
177 void newLine() {
178 printStr("\n");
179 for (unsigned I = 0; I != Depth; ++I)
180 printStr(" ");
181 PendingNewline = false;
182 }
183
184 template<typename T> void printWithPendingNewline(T V) {
185 print(V);
186 if (wantsNewline(V))
187 PendingNewline = true;
188 }
189
190 template<typename T> void printWithComma(T V) {
191 if (PendingNewline || wantsNewline(V)) {
192 printStr(",");
193 newLine();
194 } else {
195 printStr(", ");
196 }
197
198 printWithPendingNewline(V);
199 }
200
201 struct CtorArgPrinter {
202 DumpVisitor &Visitor;
203
204 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
205 if (Visitor.anyWantNewline(V, Vs...))
206 Visitor.newLine();
207 Visitor.printWithPendingNewline(V);
208 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
209 (void)PrintInOrder;
210 }
211 };
212
213 template<typename NodeT> void operator()(const NodeT *Node) {
214 Depth += 2;
215 fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
216 Node->match(CtorArgPrinter{*this});
217 fprintf(stderr, ")");
218 Depth -= 2;
219 }
220
221 void operator()(const ForwardTemplateReference *Node) {
222 Depth += 2;
223 fprintf(stderr, "ForwardTemplateReference(");
224 if (Node->Ref && !Node->Printing) {
225 Node->Printing = true;
226 CtorArgPrinter{*this}(Node->Ref);
227 Node->Printing = false;
228 } else {
229 CtorArgPrinter{*this}(Node->Index);
230 }
231 fprintf(stderr, ")");
232 Depth -= 2;
233 }
234};
235}
236
237void itanium_demangle::Node::dump() const {
238 DumpVisitor V;
239 visit(std::ref(V));
240 V.newLine();
241}
242#endif
243
244namespace {
245class BumpPointerAllocator {
246 struct BlockMeta {
247 BlockMeta* Next;
248 size_t Current;
249 };
250
251 static constexpr size_t AllocSize = 4096;
252 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
253
254 alignas(long double) char InitialBuffer[AllocSize];
255 BlockMeta* BlockList = nullptr;
256
257 void grow() {
258 char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
259 if (NewMeta == nullptr)
260 std::terminate();
261 BlockList = new (NewMeta) BlockMeta{BlockList, 0};
262 }
263
264 void* allocateMassive(size_t NBytes) {
265 NBytes += sizeof(BlockMeta);
266 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
267 if (NewMeta == nullptr)
268 std::terminate();
269 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
270 return static_cast<void*>(NewMeta + 1);
271 }
272
273public:
274 BumpPointerAllocator()
275 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
276
277 void* allocate(size_t N) {
278 N = (N + 15u) & ~15u;
279 if (N + BlockList->Current >= UsableAllocSize) {
280 if (N > UsableAllocSize)
281 return allocateMassive(N);
282 grow();
283 }
284 BlockList->Current += N;
285 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
286 BlockList->Current - N);
287 }
288
289 void reset() {
290 while (BlockList) {
291 BlockMeta* Tmp = BlockList;
292 BlockList = BlockList->Next;
293 if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
294 std::free(Tmp);
295 }
296 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
297 }
298
299 ~BumpPointerAllocator() { reset(); }
300};
301
302class DefaultAllocator {
303 BumpPointerAllocator Alloc;
304
305public:
306 void reset() { Alloc.reset(); }
307
308 template<typename T, typename ...Args> T *makeNode(Args &&...args) {
309 return new (Alloc.allocate(sizeof(T)))
310 T(std::forward<Args>(args)...);
311 }
312
313 void *allocateNodeArray(size_t sz) {
314 return Alloc.allocate(sizeof(Node *) * sz);
315 }
316};
317} // unnamed namespace
318
319//===----------------------------------------------------------------------===//
320// Code beyond this point should not be synchronized with LLVM.
321//===----------------------------------------------------------------------===//
322
323using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
324
325namespace {
326enum : int {
327 demangle_invalid_args = -3,
328 demangle_invalid_mangled_name = -2,
329 demangle_memory_alloc_failure = -1,
330 demangle_success = 0,
331};
332}
333
334namespace __cxxabiv1 {
335extern "C" _LIBCXXABI_FUNC_VIS char *
336__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
337 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
338 if (Status)
339 *Status = demangle_invalid_args;
340 return nullptr;
341 }
342
343 int InternalStatus = demangle_success;
344 Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
345 OutputStream S;
346
347 Node *AST = Parser.parse();
348
349 if (AST == nullptr)
350 InternalStatus = demangle_invalid_mangled_name;
351 else if (!initializeOutputStream(Buf, N, S, 1024))
352 InternalStatus = demangle_memory_alloc_failure;
353 else {
354 assert(Parser.ForwardTemplateRefs.empty());
355 AST->print(S);
356 S += '\0';
357 if (N != nullptr)
358 *N = S.getCurrentPosition();
359 Buf = S.getBuffer();
360 }
361
362 if (Status)
363 *Status = InternalStatus;
364 return InternalStatus == demangle_success ? Buf : nullptr;
365}
366} // __cxxabiv1
lib/libcxxabi/src/cxa_exception.cpp created+755
...@@ -0,0 +1,755 @@
1//===------------------------- cxa_exception.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Exception Handling APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
10//
11//===----------------------------------------------------------------------===//
12
13#include "cxxabi.h"
14
15#include <exception> // for std::terminate
16#include <string.h> // for memset
17#include "cxa_exception.h"
18#include "cxa_handlers.h"
19#include "fallback_malloc.h"
20#include "include/atomic_support.h"
21
22#if __has_feature(address_sanitizer)
23extern "C" void __asan_handle_no_return(void);
24#endif
25
26// +---------------------------+-----------------------------+---------------+
27// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
28// +---------------------------+-----------------------------+---------------+
29// ^
30// |
31// +-------------------------------------------------------+
32// |
33// +---------------------------+-----------------------------+
34// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
35// +---------------------------+-----------------------------+
36
37namespace __cxxabiv1 {
38
39// Utility routines
40static
41inline
42__cxa_exception*
43cxa_exception_from_thrown_object(void* thrown_object)
44{
45 return static_cast<__cxa_exception*>(thrown_object) - 1;
46}
47
48// Note: This is never called when exception_header is masquerading as a
49// __cxa_dependent_exception.
50static
51inline
52void*
53thrown_object_from_cxa_exception(__cxa_exception* exception_header)
54{
55 return static_cast<void*>(exception_header + 1);
56}
57
58// Get the exception object from the unwind pointer.
59// Relies on the structure layout, where the unwind pointer is right in
60// front of the user's exception object
61static
62inline
63__cxa_exception*
64cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
65{
66 return cxa_exception_from_thrown_object(unwind_exception + 1 );
67}
68
69// Round s up to next multiple of a.
70static inline
71size_t aligned_allocation_size(size_t s, size_t a) {
72 return (s + a - 1) & ~(a - 1);
73}
74
75static inline
76size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
77 return aligned_allocation_size(size + sizeof (__cxa_exception),
78 alignof(__cxa_exception));
79}
80
81void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) {
82 ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue));
83}
84
85
86static void setOurExceptionClass(_Unwind_Exception* unwind_exception) {
87 __setExceptionClass(unwind_exception, kOurExceptionClass);
88}
89
90static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
91 __setExceptionClass(unwind_exception, kOurDependentExceptionClass);
92}
93
94// Is it one of ours?
95uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) {
96 // On x86 and some ARM unwinders, unwind_exception->exception_class is
97 // a uint64_t. On other ARM unwinders, it is a char[8].
98 // See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
99 // So we just copy it into a uint64_t to be sure.
100 uint64_t exClass;
101 ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass));
102 return exClass;
103}
104
105bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
106 return (__getExceptionClass(unwind_exception) & get_vendor_and_language) ==
107 (kOurExceptionClass & get_vendor_and_language);
108}
109
110static bool isDependentException(_Unwind_Exception* unwind_exception) {
111 return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01;
112}
113
114// This does not need to be atomic
115static inline int incrementHandlerCount(__cxa_exception *exception) {
116 return ++exception->handlerCount;
117}
118
119// This does not need to be atomic
120static inline int decrementHandlerCount(__cxa_exception *exception) {
121 return --exception->handlerCount;
122}
123
124/*
125 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
126 stored in exc is called. Otherwise the exceptionDestructor stored in
127 exc is called, and then the memory for the exception is deallocated.
128
129 This is never called for a __cxa_dependent_exception.
130*/
131static
132void
133exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
134{
135 __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
136 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
137 std::__terminate(exception_header->terminateHandler);
138 // Just in case there exists a dependent exception that is pointing to this,
139 // check the reference count and only destroy this if that count goes to zero.
140 __cxa_decrement_exception_refcount(unwind_exception + 1);
141}
142
143static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
144// Section 2.5.3 says:
145// * For purposes of this ABI, several things are considered exception handlers:
146// ** A terminate() call due to a throw.
147// and
148// * Upon entry, Following initialization of the catch parameter,
149// a handler must call:
150// * void *__cxa_begin_catch(void *exceptionObject );
151 (void) __cxa_begin_catch(&exception_header->unwindHeader);
152 std::__terminate(exception_header->terminateHandler);
153}
154
155// Return the offset of the __cxa_exception header from the start of the
156// allocated buffer. If __cxa_exception's alignment is smaller than the maximum
157// useful alignment for the target machine, padding has to be inserted before
158// the header to ensure the thrown object that follows the header is
159// sufficiently aligned. This happens if _Unwind_exception isn't double-word
160// aligned (on Darwin, for example).
161static size_t get_cxa_exception_offset() {
162 struct S {
163 } __attribute__((aligned));
164
165 // Compute the maximum alignment for the target machine.
166 constexpr size_t alignment = alignof(S);
167 constexpr size_t excp_size = sizeof(__cxa_exception);
168 constexpr size_t aligned_size =
169 (excp_size + alignment - 1) / alignment * alignment;
170 constexpr size_t offset = aligned_size - excp_size;
171 static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment),
172 "offset is non-zero only if _Unwind_Exception isn't aligned");
173 return offset;
174}
175
176extern "C" {
177
178// Allocate a __cxa_exception object, and zero-fill it.
179// Reserve "thrown_size" bytes on the end for the user's exception
180// object. Zero-fill the object. If memory can't be allocated, call
181// std::terminate. Return a pointer to the memory to be used for the
182// user's exception object.
183void *__cxa_allocate_exception(size_t thrown_size) throw() {
184 size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
185
186 // Allocate extra space before the __cxa_exception header to ensure the
187 // start of the thrown object is sufficiently aligned.
188 size_t header_offset = get_cxa_exception_offset();
189 char *raw_buffer =
190 (char *)__aligned_malloc_with_fallback(header_offset + actual_size);
191 if (NULL == raw_buffer)
192 std::terminate();
193 __cxa_exception *exception_header =
194 static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
195 ::memset(exception_header, 0, actual_size);
196 return thrown_object_from_cxa_exception(exception_header);
197}
198
199
200// Free a __cxa_exception object allocated with __cxa_allocate_exception.
201void __cxa_free_exception(void *thrown_object) throw() {
202 // Compute the size of the padding before the header.
203 size_t header_offset = get_cxa_exception_offset();
204 char *raw_buffer =
205 ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset;
206 __aligned_free_with_fallback((void *)raw_buffer);
207}
208
209
210// This function shall allocate a __cxa_dependent_exception and
211// return a pointer to it. (Really to the object, not past its' end).
212// Otherwise, it will work like __cxa_allocate_exception.
213void * __cxa_allocate_dependent_exception () {
214 size_t actual_size = sizeof(__cxa_dependent_exception);
215 void *ptr = __aligned_malloc_with_fallback(actual_size);
216 if (NULL == ptr)
217 std::terminate();
218 ::memset(ptr, 0, actual_size);
219 return ptr;
220}
221
222
223// This function shall free a dependent_exception.
224// It does not affect the reference count of the primary exception.
225void __cxa_free_dependent_exception (void * dependent_exception) {
226 __aligned_free_with_fallback(dependent_exception);
227}
228
229
230// 2.4.3 Throwing the Exception Object
231/*
232After constructing the exception object with the throw argument value,
233the generated code calls the __cxa_throw runtime library routine. This
234routine never returns.
235
236The __cxa_throw routine will do the following:
237
238* Obtain the __cxa_exception header from the thrown exception object address,
239which can be computed as follows:
240 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
241* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
242* Save the tinfo and dest arguments in the __cxa_exception header.
243* Set the exception_class field in the unwind header. This is a 64-bit value
244representing the ASCII string "XXXXC++\0", where "XXXX" is a
245vendor-dependent string. That is, for implementations conforming to this
246ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
247* Increment the uncaught_exception flag.
248* Call _Unwind_RaiseException in the system unwind library, Its argument is the
249pointer to the thrown exception, which __cxa_throw itself received as an argument.
250__Unwind_RaiseException begins the process of stack unwinding, described
251in Section 2.5. In special cases, such as an inability to find a
252handler, _Unwind_RaiseException may return. In that case, __cxa_throw
253will call terminate, assuming that there was no handler for the
254exception.
255*/
256void
257__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) {
258 __cxa_eh_globals *globals = __cxa_get_globals();
259 __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
260
261 exception_header->unexpectedHandler = std::get_unexpected();
262 exception_header->terminateHandler = std::get_terminate();
263 exception_header->exceptionType = tinfo;
264 exception_header->exceptionDestructor = dest;
265 setOurExceptionClass(&exception_header->unwindHeader);
266 exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
267 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
268
269 exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
270
271#if __has_feature(address_sanitizer)
272 // Inform the ASan runtime that now might be a good time to clean stuff up.
273 __asan_handle_no_return();
274#endif
275
276#ifdef __USING_SJLJ_EXCEPTIONS__
277 _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
278#else
279 _Unwind_RaiseException(&exception_header->unwindHeader);
280#endif
281 // This only happens when there is no handler, or some unexpected unwinding
282 // error happens.
283 failed_throw(exception_header);
284}
285
286
287// 2.5.3 Exception Handlers
288/*
289The adjusted pointer is computed by the personality routine during phase 1
290 and saved in the exception header (either __cxa_exception or
291 __cxa_dependent_exception).
292
293 Requires: exception is native
294*/
295void *__cxa_get_exception_ptr(void *unwind_exception) throw() {
296#if defined(_LIBCXXABI_ARM_EHABI)
297 return reinterpret_cast<void*>(
298 static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
299#else
300 return cxa_exception_from_exception_unwind_exception(
301 static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr;
302#endif
303}
304
305#if defined(_LIBCXXABI_ARM_EHABI)
306/*
307The routine to be called before the cleanup. This will save __cxa_exception in
308__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
309*/
310bool __cxa_begin_cleanup(void *unwind_arg) throw() {
311 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
312 __cxa_eh_globals* globals = __cxa_get_globals();
313 __cxa_exception* exception_header =
314 cxa_exception_from_exception_unwind_exception(unwind_exception);
315
316 if (__isOurExceptionClass(unwind_exception))
317 {
318 if (0 == exception_header->propagationCount)
319 {
320 exception_header->nextPropagatingException = globals->propagatingExceptions;
321 globals->propagatingExceptions = exception_header;
322 }
323 ++exception_header->propagationCount;
324 }
325 else
326 {
327 // If the propagatingExceptions stack is not empty, since we can't
328 // chain the foreign exception, terminate it.
329 if (NULL != globals->propagatingExceptions)
330 std::terminate();
331 globals->propagatingExceptions = exception_header;
332 }
333 return true;
334}
335
336/*
337The routine to be called after the cleanup has been performed. It will get the
338propagating __cxa_exception from __cxa_eh_globals, and continue the stack
339unwinding with _Unwind_Resume.
340
341According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
342register, thus we have to write this function in assembly so that we can save
343{r1, r2, r3}. We don't have to save r0 because it is the return value and the
344first argument to _Unwind_Resume(). In addition, we are saving r4 in order to
345align the stack to 16 bytes, even though it is a callee-save register.
346*/
347__attribute__((used)) static _Unwind_Exception *
348__cxa_end_cleanup_impl()
349{
350 __cxa_eh_globals* globals = __cxa_get_globals();
351 __cxa_exception* exception_header = globals->propagatingExceptions;
352 if (NULL == exception_header)
353 {
354 // It seems that __cxa_begin_cleanup() is not called properly.
355 // We have no choice but terminate the program now.
356 std::terminate();
357 }
358
359 if (__isOurExceptionClass(&exception_header->unwindHeader))
360 {
361 --exception_header->propagationCount;
362 if (0 == exception_header->propagationCount)
363 {
364 globals->propagatingExceptions = exception_header->nextPropagatingException;
365 exception_header->nextPropagatingException = NULL;
366 }
367 }
368 else
369 {
370 globals->propagatingExceptions = NULL;
371 }
372 return &exception_header->unwindHeader;
373}
374
375asm (
376 " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
377 " .globl __cxa_end_cleanup\n"
378 " .type __cxa_end_cleanup,%function\n"
379 "__cxa_end_cleanup:\n"
380 " push {r1, r2, r3, r4}\n"
381 " bl __cxa_end_cleanup_impl\n"
382 " pop {r1, r2, r3, r4}\n"
383 " bl _Unwind_Resume\n"
384 " bl abort\n"
385 " .popsection"
386);
387#endif // defined(_LIBCXXABI_ARM_EHABI)
388
389/*
390This routine can catch foreign or native exceptions. If native, the exception
391can be a primary or dependent variety. This routine may remain blissfully
392ignorant of whether the native exception is primary or dependent.
393
394If the exception is native:
395* Increment's the exception's handler count.
396* Push the exception on the stack of currently-caught exceptions if it is not
397 already there (from a rethrow).
398* Decrements the uncaught_exception count.
399* Returns the adjusted pointer to the exception object, which is stored in
400 the __cxa_exception by the personality routine.
401
402If the exception is foreign, this means it did not originate from one of throw
403routines. The foreign exception does not necessarily have a __cxa_exception
404header. However we can catch it here with a catch (...), or with a call
405to terminate or unexpected during unwinding.
406* Do not try to increment the exception's handler count, we don't know where
407 it is.
408* Push the exception on the stack of currently-caught exceptions only if the
409 stack is empty. The foreign exception has no way to link to the current
410 top of stack. If the stack is not empty, call terminate. Even with an
411 empty stack, this is hacked in by pushing a pointer to an imaginary
412 __cxa_exception block in front of the foreign exception. It would be better
413 if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
414 doesn't. It has a stack of __cxa_exception (which has a next* in it).
415* Do not decrement the uncaught_exception count because we didn't increment it
416 in __cxa_throw (or one of our rethrow functions).
417* If we haven't terminated, assume the exception object is just past the
418 _Unwind_Exception and return a pointer to that.
419*/
420void*
421__cxa_begin_catch(void* unwind_arg) throw()
422{
423 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
424 bool native_exception = __isOurExceptionClass(unwind_exception);
425 __cxa_eh_globals* globals = __cxa_get_globals();
426 // exception_header is a hackish offset from a foreign exception, but it
427 // works as long as we're careful not to try to access any __cxa_exception
428 // parts.
429 __cxa_exception* exception_header =
430 cxa_exception_from_exception_unwind_exception
431 (
432 static_cast<_Unwind_Exception*>(unwind_exception)
433 );
434 if (native_exception)
435 {
436 // Increment the handler count, removing the flag about being rethrown
437 exception_header->handlerCount = exception_header->handlerCount < 0 ?
438 -exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
439 // place the exception on the top of the stack if it's not already
440 // there by a previous rethrow
441 if (exception_header != globals->caughtExceptions)
442 {
443 exception_header->nextException = globals->caughtExceptions;
444 globals->caughtExceptions = exception_header;
445 }
446 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
447#if defined(_LIBCXXABI_ARM_EHABI)
448 return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
449#else
450 return exception_header->adjustedPtr;
451#endif
452 }
453 // Else this is a foreign exception
454 // If the caughtExceptions stack is not empty, terminate
455 if (globals->caughtExceptions != 0)
456 std::terminate();
457 // Push the foreign exception on to the stack
458 globals->caughtExceptions = exception_header;
459 return unwind_exception + 1;
460}
461
462
463/*
464Upon exit for any reason, a handler must call:
465 void __cxa_end_catch ();
466
467This routine can be called for either a native or foreign exception.
468For a native exception:
469* Locates the most recently caught exception and decrements its handler count.
470* Removes the exception from the caught exception stack, if the handler count goes to zero.
471* If the handler count goes down to zero, and the exception was not re-thrown
472 by throw, it locates the primary exception (which may be the same as the one
473 it's handling) and decrements its reference count. If that reference count
474 goes to zero, the function destroys the exception. In any case, if the current
475 exception is a dependent exception, it destroys that.
476
477For a foreign exception:
478* If it has been rethrown, there is nothing to do.
479* Otherwise delete the exception and pop the catch stack to empty.
480*/
481void __cxa_end_catch() {
482 static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
483 "sizeof(__cxa_exception) must be equal to "
484 "sizeof(__cxa_dependent_exception)");
485 static_assert(__builtin_offsetof(__cxa_exception, referenceCount) ==
486 __builtin_offsetof(__cxa_dependent_exception,
487 primaryException),
488 "the layout of __cxa_exception must match the layout of "
489 "__cxa_dependent_exception");
490 static_assert(__builtin_offsetof(__cxa_exception, handlerCount) ==
491 __builtin_offsetof(__cxa_dependent_exception, handlerCount),
492 "the layout of __cxa_exception must match the layout of "
493 "__cxa_dependent_exception");
494 __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
495 __cxa_exception* exception_header = globals->caughtExceptions;
496 // If we've rethrown a foreign exception, then globals->caughtExceptions
497 // will have been made an empty stack by __cxa_rethrow() and there is
498 // nothing more to be done. Do nothing!
499 if (NULL != exception_header)
500 {
501 bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
502 if (native_exception)
503 {
504 // This is a native exception
505 if (exception_header->handlerCount < 0)
506 {
507 // The exception has been rethrown by __cxa_rethrow, so don't delete it
508 if (0 == incrementHandlerCount(exception_header))
509 {
510 // Remove from the chain of uncaught exceptions
511 globals->caughtExceptions = exception_header->nextException;
512 // but don't destroy
513 }
514 // Keep handlerCount negative in case there are nested catch's
515 // that need to be told that this exception is rethrown. Don't
516 // erase this rethrow flag until the exception is recaught.
517 }
518 else
519 {
520 // The native exception has not been rethrown
521 if (0 == decrementHandlerCount(exception_header))
522 {
523 // Remove from the chain of uncaught exceptions
524 globals->caughtExceptions = exception_header->nextException;
525 // Destroy this exception, being careful to distinguish
526 // between dependent and primary exceptions
527 if (isDependentException(&exception_header->unwindHeader))
528 {
529 // Reset exception_header to primaryException and deallocate the dependent exception
530 __cxa_dependent_exception* dep_exception_header =
531 reinterpret_cast<__cxa_dependent_exception*>(exception_header);
532 exception_header =
533 cxa_exception_from_thrown_object(dep_exception_header->primaryException);
534 __cxa_free_dependent_exception(dep_exception_header);
535 }
536 // Destroy the primary exception only if its referenceCount goes to 0
537 // (this decrement must be atomic)
538 __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
539 }
540 }
541 }
542 else
543 {
544 // The foreign exception has not been rethrown. Pop the stack
545 // and delete it. If there are nested catch's and they try
546 // to touch a foreign exception in any way, that is undefined
547 // behavior. They likely can't since the only way to catch
548 // a foreign exception is with catch (...)!
549 _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
550 globals->caughtExceptions = 0;
551 }
552 }
553}
554
555// Note: exception_header may be masquerading as a __cxa_dependent_exception
556// and that's ok. exceptionType is there too.
557// However watch out for foreign exceptions. Return null for them.
558std::type_info *__cxa_current_exception_type() {
559// get the current exception
560 __cxa_eh_globals *globals = __cxa_get_globals_fast();
561 if (NULL == globals)
562 return NULL; // If there have never been any exceptions, there are none now.
563 __cxa_exception *exception_header = globals->caughtExceptions;
564 if (NULL == exception_header)
565 return NULL; // No current exception
566 if (!__isOurExceptionClass(&exception_header->unwindHeader))
567 return NULL;
568 return exception_header->exceptionType;
569}
570
571// 2.5.4 Rethrowing Exceptions
572/* This routine can rethrow native or foreign exceptions.
573If the exception is native:
574* marks the exception object on top of the caughtExceptions stack
575 (in an implementation-defined way) as being rethrown.
576* If the caughtExceptions stack is empty, it calls terminate()
577 (see [C++FDIS] [except.throw], 15.1.8).
578* It then calls _Unwind_RaiseException which should not return
579 (terminate if it does).
580 Note: exception_header may be masquerading as a __cxa_dependent_exception
581 and that's ok.
582*/
583void __cxa_rethrow() {
584 __cxa_eh_globals* globals = __cxa_get_globals();
585 __cxa_exception* exception_header = globals->caughtExceptions;
586 if (NULL == exception_header)
587 std::terminate(); // throw; called outside of a exception handler
588 bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader);
589 if (native_exception)
590 {
591 // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
592 exception_header->handlerCount = -exception_header->handlerCount;
593 globals->uncaughtExceptions += 1;
594 // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
595 }
596 else // this is a foreign exception
597 {
598 // The only way to communicate to __cxa_end_catch that we've rethrown
599 // a foreign exception, so don't delete us, is to pop the stack here
600 // which must be empty afterwards. Then __cxa_end_catch will do
601 // nothing
602 globals->caughtExceptions = 0;
603 }
604#ifdef __USING_SJLJ_EXCEPTIONS__
605 _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
606#else
607 _Unwind_RaiseException(&exception_header->unwindHeader);
608#endif
609
610 // If we get here, some kind of unwinding error has occurred.
611 // There is some weird code generation bug happening with
612 // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
613 // If we call failed_throw here. Turns up with -O2 or higher, and -Os.
614 __cxa_begin_catch(&exception_header->unwindHeader);
615 if (native_exception)
616 std::__terminate(exception_header->terminateHandler);
617 // Foreign exception: can't get exception_header->terminateHandler
618 std::terminate();
619}
620
621/*
622 If thrown_object is not null, atomically increment the referenceCount field
623 of the __cxa_exception header associated with the thrown object referred to
624 by thrown_object.
625
626 Requires: If thrown_object is not NULL, it is a native exception.
627*/
628void
629__cxa_increment_exception_refcount(void *thrown_object) throw() {
630 if (thrown_object != NULL )
631 {
632 __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
633 std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
634 }
635}
636
637/*
638 If thrown_object is not null, atomically decrement the referenceCount field
639 of the __cxa_exception header associated with the thrown object referred to
640 by thrown_object. If the referenceCount drops to zero, destroy and
641 deallocate the exception.
642
643 Requires: If thrown_object is not NULL, it is a native exception.
644*/
645_LIBCXXABI_NO_CFI
646void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
647 if (thrown_object != NULL )
648 {
649 __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
650 if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
651 {
652 if (NULL != exception_header->exceptionDestructor)
653 exception_header->exceptionDestructor(thrown_object);
654 __cxa_free_exception(thrown_object);
655 }
656 }
657}
658
659/*
660 Returns a pointer to the thrown object (if any) at the top of the
661 caughtExceptions stack. Atomically increment the exception's referenceCount.
662 If there is no such thrown object or if the thrown object is foreign,
663 returns null.
664
665 We can use __cxa_get_globals_fast here to get the globals because if there have
666 been no exceptions thrown, ever, on this thread, we can return NULL without
667 the need to allocate the exception-handling globals.
668*/
669void *__cxa_current_primary_exception() throw() {
670// get the current exception
671 __cxa_eh_globals* globals = __cxa_get_globals_fast();
672 if (NULL == globals)
673 return NULL; // If there are no globals, there is no exception
674 __cxa_exception* exception_header = globals->caughtExceptions;
675 if (NULL == exception_header)
676 return NULL; // No current exception
677 if (!__isOurExceptionClass(&exception_header->unwindHeader))
678 return NULL; // Can't capture a foreign exception (no way to refcount it)
679 if (isDependentException(&exception_header->unwindHeader)) {
680 __cxa_dependent_exception* dep_exception_header =
681 reinterpret_cast<__cxa_dependent_exception*>(exception_header);
682 exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
683 }
684 void* thrown_object = thrown_object_from_cxa_exception(exception_header);
685 __cxa_increment_exception_refcount(thrown_object);
686 return thrown_object;
687}
688
689/*
690 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
691 stored in exc is called. Otherwise the referenceCount stored in the
692 primary exception is decremented, destroying the primary if necessary.
693 Finally the dependent exception is destroyed.
694*/
695static
696void
697dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
698{
699 __cxa_dependent_exception* dep_exception_header =
700 reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
701 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
702 std::__terminate(dep_exception_header->terminateHandler);
703 __cxa_decrement_exception_refcount(dep_exception_header->primaryException);
704 __cxa_free_dependent_exception(dep_exception_header);
705}
706
707/*
708 If thrown_object is not null, allocate, initialize and throw a dependent
709 exception.
710*/
711void
712__cxa_rethrow_primary_exception(void* thrown_object)
713{
714 if ( thrown_object != NULL )
715 {
716 // thrown_object guaranteed to be native because
717 // __cxa_current_primary_exception returns NULL for foreign exceptions
718 __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
719 __cxa_dependent_exception* dep_exception_header =
720 static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
721 dep_exception_header->primaryException = thrown_object;
722 __cxa_increment_exception_refcount(thrown_object);
723 dep_exception_header->exceptionType = exception_header->exceptionType;
724 dep_exception_header->unexpectedHandler = std::get_unexpected();
725 dep_exception_header->terminateHandler = std::get_terminate();
726 setDependentExceptionClass(&dep_exception_header->unwindHeader);
727 __cxa_get_globals()->uncaughtExceptions += 1;
728 dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
729#ifdef __USING_SJLJ_EXCEPTIONS__
730 _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
731#else
732 _Unwind_RaiseException(&dep_exception_header->unwindHeader);
733#endif
734 // Some sort of unwinding error. Note that terminate is a handler.
735 __cxa_begin_catch(&dep_exception_header->unwindHeader);
736 }
737 // If we return client will call terminate()
738}
739
740bool
741__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; }
742
743unsigned int
744__cxa_uncaught_exceptions() throw()
745{
746 // This does not report foreign exceptions in flight
747 __cxa_eh_globals* globals = __cxa_get_globals_fast();
748 if (globals == 0)
749 return 0;
750 return globals->uncaughtExceptions;
751}
752
753} // extern "C"
754
755} // abi
lib/libcxxabi/src/cxa_exception.h created+164
...@@ -0,0 +1,164 @@
1//===------------------------- cxa_exception.h ----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Exception Handling APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef _CXA_EXCEPTION_H
14#define _CXA_EXCEPTION_H
15
16#include <exception> // for std::unexpected_handler and std::terminate_handler
17#include "cxxabi.h"
18#include "unwind.h"
19
20namespace __cxxabiv1 {
21
22static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
23static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
24static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++
25
26_LIBCXXABI_HIDDEN uint64_t __getExceptionClass (const _Unwind_Exception*);
27_LIBCXXABI_HIDDEN void __setExceptionClass ( _Unwind_Exception*, uint64_t);
28_LIBCXXABI_HIDDEN bool __isOurExceptionClass(const _Unwind_Exception*);
29
30struct _LIBCXXABI_HIDDEN __cxa_exception {
31#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
32 // Now _Unwind_Exception is marked with __attribute__((aligned)),
33 // which implies __cxa_exception is also aligned. Insert padding
34 // in the beginning of the struct, rather than before unwindHeader.
35 void *reserve;
36
37 // This is a new field to support C++ 0x exception_ptr.
38 // For binary compatibility it is at the start of this
39 // struct which is prepended to the object thrown in
40 // __cxa_allocate_exception.
41 size_t referenceCount;
42#endif
43
44 // Manage the exception object itself.
45 std::type_info *exceptionType;
46 void (*exceptionDestructor)(void *);
47 std::unexpected_handler unexpectedHandler;
48 std::terminate_handler terminateHandler;
49
50 __cxa_exception *nextException;
51
52 int handlerCount;
53
54#if defined(_LIBCXXABI_ARM_EHABI)
55 __cxa_exception* nextPropagatingException;
56 int propagationCount;
57#else
58 int handlerSwitchValue;
59 const unsigned char *actionRecord;
60 const unsigned char *languageSpecificData;
61 void *catchTemp;
62 void *adjustedPtr;
63#endif
64
65#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
66 // This is a new field to support C++ 0x exception_ptr.
67 // For binary compatibility it is placed where the compiler
68 // previously adding padded to 64-bit align unwindHeader.
69 size_t referenceCount;
70#endif
71 _Unwind_Exception unwindHeader;
72};
73
74// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
75// The layout of this structure MUST match the layout of __cxa_exception, with
76// primaryException instead of referenceCount.
77struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
78#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
79 void* reserve; // padding.
80 void* primaryException;
81#endif
82
83 std::type_info *exceptionType;
84 void (*exceptionDestructor)(void *);
85 std::unexpected_handler unexpectedHandler;
86 std::terminate_handler terminateHandler;
87
88 __cxa_exception *nextException;
89
90 int handlerCount;
91
92#if defined(_LIBCXXABI_ARM_EHABI)
93 __cxa_exception* nextPropagatingException;
94 int propagationCount;
95#else
96 int handlerSwitchValue;
97 const unsigned char *actionRecord;
98 const unsigned char *languageSpecificData;
99 void * catchTemp;
100 void *adjustedPtr;
101#endif
102
103#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
104 void* primaryException;
105#endif
106 _Unwind_Exception unwindHeader;
107};
108
109// Verify the negative offsets of different fields.
110static_assert(sizeof(_Unwind_Exception) +
111 offsetof(__cxa_exception, unwindHeader) ==
112 sizeof(__cxa_exception),
113 "unwindHeader has wrong negative offsets");
114static_assert(sizeof(_Unwind_Exception) +
115 offsetof(__cxa_dependent_exception, unwindHeader) ==
116 sizeof(__cxa_dependent_exception),
117 "unwindHeader has wrong negative offsets");
118
119#if defined(_LIBCXXABI_ARM_EHABI)
120static_assert(offsetof(__cxa_exception, propagationCount) +
121 sizeof(_Unwind_Exception) + sizeof(void*) ==
122 sizeof(__cxa_exception),
123 "propagationCount has wrong negative offset");
124static_assert(offsetof(__cxa_dependent_exception, propagationCount) +
125 sizeof(_Unwind_Exception) + sizeof(void*) ==
126 sizeof(__cxa_dependent_exception),
127 "propagationCount has wrong negative offset");
128#elif defined(__LP64__) || defined(_WIN64)
129static_assert(offsetof(__cxa_exception, adjustedPtr) +
130 sizeof(_Unwind_Exception) + sizeof(void*) ==
131 sizeof(__cxa_exception),
132 "adjustedPtr has wrong negative offset");
133static_assert(offsetof(__cxa_dependent_exception, adjustedPtr) +
134 sizeof(_Unwind_Exception) + sizeof(void*) ==
135 sizeof(__cxa_dependent_exception),
136 "adjustedPtr has wrong negative offset");
137#else
138static_assert(offsetof(__cxa_exception, referenceCount) +
139 sizeof(_Unwind_Exception) + sizeof(void*) ==
140 sizeof(__cxa_exception),
141 "referenceCount has wrong negative offset");
142static_assert(offsetof(__cxa_dependent_exception, primaryException) +
143 sizeof(_Unwind_Exception) + sizeof(void*) ==
144 sizeof(__cxa_dependent_exception),
145 "primaryException has wrong negative offset");
146#endif
147
148struct _LIBCXXABI_HIDDEN __cxa_eh_globals {
149 __cxa_exception * caughtExceptions;
150 unsigned int uncaughtExceptions;
151#if defined(_LIBCXXABI_ARM_EHABI)
152 __cxa_exception* propagatingExceptions;
153#endif
154};
155
156extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals ();
157extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast ();
158
159extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception ();
160extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception);
161
162} // namespace __cxxabiv1
163
164#endif // _CXA_EXCEPTION_H
lib/libcxxabi/src/cxa_exception_storage.cpp created+105
...@@ -0,0 +1,105 @@
1//===--------------------- cxa_exception_storage.cpp ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the storage for the "Caught Exception Stack"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack
10//
11//===----------------------------------------------------------------------===//
12
13#include "cxa_exception.h"
14
15#include <__threading_support>
16
17#if defined(_LIBCXXABI_HAS_NO_THREADS)
18
19namespace __cxxabiv1 {
20extern "C" {
21 static __cxa_eh_globals eh_globals;
22 __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
23 __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
24 }
25}
26
27#elif defined(HAS_THREAD_LOCAL)
28
29namespace __cxxabiv1 {
30
31namespace {
32 __cxa_eh_globals * __globals () {
33 static thread_local __cxa_eh_globals eh_globals;
34 return &eh_globals;
35 }
36 }
37
38extern "C" {
39 __cxa_eh_globals * __cxa_get_globals () { return __globals (); }
40 __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); }
41 }
42}
43
44#else
45
46#include "abort_message.h"
47#include "fallback_malloc.h"
48
49#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
50#pragma comment(lib, "pthread")
51#endif
52
53// In general, we treat all threading errors as fatal.
54// We cannot call std::terminate() because that will in turn
55// call __cxa_get_globals() and cause infinite recursion.
56
57namespace __cxxabiv1 {
58namespace {
59 std::__libcpp_tls_key key_;
60 std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
61
62 void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) {
63 __free_with_fallback ( p );
64 if ( 0 != std::__libcpp_tls_set ( key_, NULL ) )
65 abort_message("cannot zero out thread value for __cxa_get_globals()");
66 }
67
68 void construct_ () {
69 if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) )
70 abort_message("cannot create thread specific key for __cxa_get_globals()");
71 }
72}
73
74extern "C" {
75 __cxa_eh_globals * __cxa_get_globals () {
76 // Try to get the globals for this thread
77 __cxa_eh_globals* retVal = __cxa_get_globals_fast ();
78
79 // If this is the first time we've been asked for these globals, create them
80 if ( NULL == retVal ) {
81 retVal = static_cast<__cxa_eh_globals*>
82 (__calloc_with_fallback (1, sizeof (__cxa_eh_globals)));
83 if ( NULL == retVal )
84 abort_message("cannot allocate __cxa_eh_globals");
85 if ( 0 != std::__libcpp_tls_set ( key_, retVal ) )
86 abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
87 }
88 return retVal;
89 }
90
91 // Note that this implementation will reliably return NULL if not
92 // preceded by a call to __cxa_get_globals(). This is an extension
93 // to the Itanium ABI and is taken advantage of in several places in
94 // libc++abi.
95 __cxa_eh_globals * __cxa_get_globals_fast () {
96 // First time through, create the key.
97 if (0 != std::__libcpp_execute_once(&flag_, construct_))
98 abort_message("execute once failure in __cxa_get_globals_fast()");
99// static int init = construct_();
100 return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
101 }
102
103}
104}
105#endif
lib/libcxxabi/src/cxa_guard.cpp created+53
...@@ -0,0 +1,53 @@
1//===---------------------------- cxa_guard.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "__cxxabi_config.h"
10#include "cxxabi.h"
11
12// Tell the implementation that we're building the actual implementation
13// (and not testing it)
14#define BUILDING_CXA_GUARD
15#include "cxa_guard_impl.h"
16
17/*
18 This implementation must be careful to not call code external to this file
19 which will turn around and try to call __cxa_guard_acquire reentrantly.
20 For this reason, the headers of this file are as restricted as possible.
21 Previous implementations of this code for __APPLE__ have used
22 std::__libcpp_mutex_lock and the abort_message utility without problem. This
23 implementation also uses std::__libcpp_condvar_wait which has tested
24 to not be a problem.
25*/
26
27namespace __cxxabiv1 {
28
29#if defined(_LIBCXXABI_GUARD_ABI_ARM)
30using guard_type = uint32_t;
31#else
32using guard_type = uint64_t;
33#endif
34
35extern "C"
36{
37_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) {
38 SelectedImplementation imp(raw_guard_object);
39 return static_cast<int>(imp.cxa_guard_acquire());
40}
41
42_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) {
43 SelectedImplementation imp(raw_guard_object);
44 imp.cxa_guard_release();
45}
46
47_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
48 SelectedImplementation imp(raw_guard_object);
49 imp.cxa_guard_abort();
50}
51} // extern "C"
52
53} // __cxxabiv1
lib/libcxxabi/src/cxa_guard_impl.h created+567
...@@ -0,0 +1,567 @@
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
9#define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
10
11/* cxa_guard_impl.h - Implements the C++ runtime support for function local
12 * static guards.
13 * The layout of the guard object is the same across ARM and Itanium.
14 *
15 * The first "guard byte" (which is checked by the compiler) is set only upon
16 * the completion of cxa release.
17 *
18 * The second "init byte" does the rest of the bookkeeping. It tracks if
19 * initialization is complete or pending, and if there are waiting threads.
20 *
21 * If the guard variable is 64-bits and the platforms supplies a 32-bit thread
22 * identifier, it is used to detect recursive initialization. The thread ID of
23 * the thread currently performing initialization is stored in the second word.
24 *
25 * Guard Object Layout:
26 * -------------------------------------------------------------------------
27 * |a: guard byte | a+1: init byte | a+2 : unused ... | a+4: thread-id ... |
28 * ------------------------------------------------------------------------
29 *
30 * Access Protocol:
31 * For each implementation the guard byte is checked and set before accessing
32 * the init byte.
33 *
34 * Overall Design:
35 * The implementation was designed to allow each implementation to be tested
36 * independent of the C++ runtime or platform support.
37 *
38 */
39
40#include "__cxxabi_config.h"
41#include "include/atomic_support.h"
42#include <unistd.h>
43#include <sys/types.h>
44#if defined(__has_include)
45# if __has_include(<sys/syscall.h>)
46# include <sys/syscall.h>
47# endif
48#endif
49
50#include <stdlib.h>
51#include <__threading_support>
52#ifndef _LIBCXXABI_HAS_NO_THREADS
53#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
54#pragma comment(lib, "pthread")
55#endif
56#endif
57
58// To make testing possible, this header is included from both cxa_guard.cpp
59// and a number of tests.
60//
61// For this reason we place everything in an anonymous namespace -- even though
62// we're in a header. We want the actual implementation and the tests to have
63// unique definitions of the types in this header (since the tests may depend
64// on function local statics).
65//
66// To enforce this either `BUILDING_CXA_GUARD` or `TESTING_CXA_GUARD` must be
67// defined when including this file. Only `src/cxa_guard.cpp` should define
68// the former.
69#ifdef BUILDING_CXA_GUARD
70# include "abort_message.h"
71# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
72#elif defined(TESTING_CXA_GUARD)
73# define ABORT_WITH_MESSAGE(...) ::abort()
74#else
75# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
76#endif
77
78#if __has_feature(thread_sanitizer)
79extern "C" void __tsan_acquire(void*);
80extern "C" void __tsan_release(void*);
81#else
82#define __tsan_acquire(addr) ((void)0)
83#define __tsan_release(addr) ((void)0)
84#endif
85
86namespace __cxxabiv1 {
87// Use an anonymous namespace to ensure that the tests and actual implementation
88// have unique definitions of these symbols.
89namespace {
90
91//===----------------------------------------------------------------------===//
92// Misc Utilities
93//===----------------------------------------------------------------------===//
94
95template <class T, T(*Init)()>
96struct LazyValue {
97 LazyValue() : is_init(false) {}
98
99 T& get() {
100 if (!is_init) {
101 value = Init();
102 is_init = true;
103 }
104 return value;
105 }
106 private:
107 T value;
108 bool is_init = false;
109};
110
111//===----------------------------------------------------------------------===//
112// PlatformGetThreadID
113//===----------------------------------------------------------------------===//
114
115#if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
116uint32_t PlatformThreadID() {
117 static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
118 return static_cast<uint32_t>(
119 pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
120}
121#elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
122uint32_t PlatformThreadID() {
123 static_assert(sizeof(pid_t) == sizeof(uint32_t), "");
124 return static_cast<uint32_t>(syscall(SYS_gettid));
125}
126#else
127constexpr uint32_t (*PlatformThreadID)() = nullptr;
128#endif
129
130
131constexpr bool PlatformSupportsThreadID() {
132#ifdef __clang__
133#pragma clang diagnostic push
134#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
135#endif
136 return +PlatformThreadID != nullptr;
137#ifdef __clang__
138#pragma clang diagnostic pop
139#endif
140}
141
142//===----------------------------------------------------------------------===//
143// GuardBase
144//===----------------------------------------------------------------------===//
145
146enum class AcquireResult {
147 INIT_IS_DONE,
148 INIT_IS_PENDING,
149};
150constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
151constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
152
153static constexpr uint8_t UNSET = 0;
154static constexpr uint8_t COMPLETE_BIT = (1 << 0);
155static constexpr uint8_t PENDING_BIT = (1 << 1);
156static constexpr uint8_t WAITING_BIT = (1 << 2);
157
158template <class Derived>
159struct GuardObject {
160 GuardObject() = delete;
161 GuardObject(GuardObject const&) = delete;
162 GuardObject& operator=(GuardObject const&) = delete;
163
164 explicit GuardObject(uint32_t* g)
165 : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
166 init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
167 thread_id_address(nullptr) {}
168
169 explicit GuardObject(uint64_t* g)
170 : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
171 init_byte_address(reinterpret_cast<uint8_t*>(g) + 1),
172 thread_id_address(reinterpret_cast<uint32_t*>(g) + 1) {}
173
174public:
175 /// Implements __cxa_guard_acquire
176 AcquireResult cxa_guard_acquire() {
177 AtomicInt<uint8_t> guard_byte(guard_byte_address);
178 if (guard_byte.load(std::_AO_Acquire) != UNSET)
179 return INIT_IS_DONE;
180 return derived()->acquire_init_byte();
181 }
182
183 /// Implements __cxa_guard_release
184 void cxa_guard_release() {
185 AtomicInt<uint8_t> guard_byte(guard_byte_address);
186 // Store complete first, so that when release wakes other folks, they see
187 // it as having been completed.
188 guard_byte.store(COMPLETE_BIT, std::_AO_Release);
189 derived()->release_init_byte();
190 }
191
192 /// Implements __cxa_guard_abort
193 void cxa_guard_abort() { derived()->abort_init_byte(); }
194
195public:
196 /// base_address - the address of the original guard object.
197 void* const base_address;
198 /// The address of the guord byte at offset 0.
199 uint8_t* const guard_byte_address;
200 /// The address of the byte used by the implementation during initialization.
201 uint8_t* const init_byte_address;
202 /// An optional address storing an identifier for the thread performing initialization.
203 /// It's used to detect recursive initialization.
204 uint32_t* const thread_id_address;
205
206private:
207 Derived* derived() { return static_cast<Derived*>(this); }
208};
209
210//===----------------------------------------------------------------------===//
211// Single Threaded Implementation
212//===----------------------------------------------------------------------===//
213
214struct InitByteNoThreads : GuardObject<InitByteNoThreads> {
215 using GuardObject::GuardObject;
216
217 AcquireResult acquire_init_byte() {
218 if (*init_byte_address == COMPLETE_BIT)
219 return INIT_IS_DONE;
220 if (*init_byte_address & PENDING_BIT)
221 ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
222 *init_byte_address = PENDING_BIT;
223 return INIT_IS_PENDING;
224 }
225
226 void release_init_byte() { *init_byte_address = COMPLETE_BIT; }
227 void abort_init_byte() { *init_byte_address = UNSET; }
228};
229
230
231//===----------------------------------------------------------------------===//
232// Global Mutex Implementation
233//===----------------------------------------------------------------------===//
234
235struct LibcppMutex;
236struct LibcppCondVar;
237
238#ifndef _LIBCXXABI_HAS_NO_THREADS
239struct LibcppMutex {
240 LibcppMutex() = default;
241 LibcppMutex(LibcppMutex const&) = delete;
242 LibcppMutex& operator=(LibcppMutex const&) = delete;
243
244 bool lock() { return std::__libcpp_mutex_lock(&mutex); }
245 bool unlock() { return std::__libcpp_mutex_unlock(&mutex); }
246
247private:
248 friend struct LibcppCondVar;
249 std::__libcpp_mutex_t mutex = _LIBCPP_MUTEX_INITIALIZER;
250};
251
252struct LibcppCondVar {
253 LibcppCondVar() = default;
254 LibcppCondVar(LibcppCondVar const&) = delete;
255 LibcppCondVar& operator=(LibcppCondVar const&) = delete;
256
257 bool wait(LibcppMutex& mut) {
258 return std::__libcpp_condvar_wait(&cond, &mut.mutex);
259 }
260 bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
261
262private:
263 std::__libcpp_condvar_t cond = _LIBCPP_CONDVAR_INITIALIZER;
264};
265#else
266struct LibcppMutex {};
267struct LibcppCondVar {};
268#endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
269
270
271template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
272 uint32_t (*GetThreadID)() = PlatformThreadID>
273struct InitByteGlobalMutex
274 : GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond,
275 GetThreadID>> {
276
277 using BaseT = typename InitByteGlobalMutex::GuardObject;
278 using BaseT::BaseT;
279
280 explicit InitByteGlobalMutex(uint32_t *g)
281 : BaseT(g), has_thread_id_support(false) {}
282 explicit InitByteGlobalMutex(uint64_t *g)
283 : BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {}
284
285public:
286 AcquireResult acquire_init_byte() {
287 LockGuard g("__cxa_guard_acquire");
288 // Check for possible recursive initialization.
289 if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
290 if (*thread_id_address == current_thread_id.get())
291 ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
292 }
293
294 // Wait until the pending bit is not set.
295 while (*init_byte_address & PENDING_BIT) {
296 *init_byte_address |= WAITING_BIT;
297 global_cond.wait(global_mutex);
298 }
299
300 if (*init_byte_address == COMPLETE_BIT)
301 return INIT_IS_DONE;
302
303 if (has_thread_id_support)
304 *thread_id_address = current_thread_id.get();
305
306 *init_byte_address = PENDING_BIT;
307 return INIT_IS_PENDING;
308 }
309
310 void release_init_byte() {
311 bool has_waiting;
312 {
313 LockGuard g("__cxa_guard_release");
314 has_waiting = *init_byte_address & WAITING_BIT;
315 *init_byte_address = COMPLETE_BIT;
316 }
317 if (has_waiting) {
318 if (global_cond.broadcast()) {
319 ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_release");
320 }
321 }
322 }
323
324 void abort_init_byte() {
325 bool has_waiting;
326 {
327 LockGuard g("__cxa_guard_abort");
328 if (has_thread_id_support)
329 *thread_id_address = 0;
330 has_waiting = *init_byte_address & WAITING_BIT;
331 *init_byte_address = UNSET;
332 }
333 if (has_waiting) {
334 if (global_cond.broadcast()) {
335 ABORT_WITH_MESSAGE("%s failed to broadcast", "__cxa_guard_abort");
336 }
337 }
338 }
339
340private:
341 using BaseT::init_byte_address;
342 using BaseT::thread_id_address;
343 const bool has_thread_id_support;
344 LazyValue<uint32_t, GetThreadID> current_thread_id;
345
346private:
347 struct LockGuard {
348 LockGuard() = delete;
349 LockGuard(LockGuard const&) = delete;
350 LockGuard& operator=(LockGuard const&) = delete;
351
352 explicit LockGuard(const char* calling_func)
353 : calling_func(calling_func) {
354 if (global_mutex.lock())
355 ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func);
356 }
357
358 ~LockGuard() {
359 if (global_mutex.unlock())
360 ABORT_WITH_MESSAGE("%s failed to release mutex", calling_func);
361 }
362
363 private:
364 const char* const calling_func;
365 };
366};
367
368//===----------------------------------------------------------------------===//
369// Futex Implementation
370//===----------------------------------------------------------------------===//
371
372#if defined(SYS_futex)
373void PlatformFutexWait(int* addr, int expect) {
374 constexpr int WAIT = 0;
375 syscall(SYS_futex, addr, WAIT, expect, 0);
376 __tsan_acquire(addr);
377}
378void PlatformFutexWake(int* addr) {
379 constexpr int WAKE = 1;
380 __tsan_release(addr);
381 syscall(SYS_futex, addr, WAKE, INT_MAX);
382}
383#else
384constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
385constexpr void (*PlatformFutexWake)(int*) = nullptr;
386#endif
387
388constexpr bool PlatformSupportsFutex() {
389#ifdef __clang__
390#pragma clang diagnostic push
391#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
392#endif
393 return +PlatformFutexWait != nullptr;
394#ifdef __clang__
395#pragma clang diagnostic pop
396#endif
397}
398
399/// InitByteFutex - Manages initialization using atomics and the futex syscall
400/// for waiting and waking.
401template <void (*Wait)(int*, int) = PlatformFutexWait,
402 void (*Wake)(int*) = PlatformFutexWake,
403 uint32_t (*GetThreadIDArg)() = PlatformThreadID>
404struct InitByteFutex : GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>> {
405 using BaseT = typename InitByteFutex::GuardObject;
406
407 /// ARM Constructor
408 explicit InitByteFutex(uint32_t *g) : BaseT(g),
409 init_byte(this->init_byte_address),
410 has_thread_id_support(this->thread_id_address && GetThreadIDArg),
411 thread_id(this->thread_id_address) {}
412
413 /// Itanium Constructor
414 explicit InitByteFutex(uint64_t *g) : BaseT(g),
415 init_byte(this->init_byte_address),
416 has_thread_id_support(this->thread_id_address && GetThreadIDArg),
417 thread_id(this->thread_id_address) {}
418
419public:
420 AcquireResult acquire_init_byte() {
421 while (true) {
422 uint8_t last_val = UNSET;
423 if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel,
424 std::_AO_Acquire)) {
425 if (has_thread_id_support) {
426 thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
427 }
428 return INIT_IS_PENDING;
429 }
430
431 if (last_val == COMPLETE_BIT)
432 return INIT_IS_DONE;
433
434 if (last_val & PENDING_BIT) {
435
436 // Check for recursive initialization
437 if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
438 ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
439 }
440
441 if ((last_val & WAITING_BIT) == 0) {
442 // This compare exchange can fail for several reasons
443 // (1) another thread finished the whole thing before we got here
444 // (2) another thread set the waiting bit we were trying to thread
445 // (3) another thread had an exception and failed to finish
446 if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT,
447 std::_AO_Acq_Rel, std::_AO_Release)) {
448 // (1) success, via someone else's work!
449 if (last_val == COMPLETE_BIT)
450 return INIT_IS_DONE;
451
452 // (3) someone else, bailed on doing the work, retry from the start!
453 if (last_val == UNSET)
454 continue;
455
456 // (2) the waiting bit got set, so we are happy to keep waiting
457 }
458 }
459 wait_on_initialization();
460 }
461 }
462 }
463
464 void release_init_byte() {
465 uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
466 if (old & WAITING_BIT)
467 wake_all();
468 }
469
470 void abort_init_byte() {
471 if (has_thread_id_support)
472 thread_id.store(0, std::_AO_Relaxed);
473
474 uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel);
475 if (old & WAITING_BIT)
476 wake_all();
477 }
478
479private:
480 /// Use the futex to wait on the current guard variable. Futex expects a
481 /// 32-bit 4-byte aligned address as the first argument, so we have to use use
482 /// the base address of the guard variable (not the init byte).
483 void wait_on_initialization() {
484 Wait(static_cast<int*>(this->base_address),
485 expected_value_for_futex(PENDING_BIT | WAITING_BIT));
486 }
487 void wake_all() { Wake(static_cast<int*>(this->base_address)); }
488
489private:
490 AtomicInt<uint8_t> init_byte;
491
492 const bool has_thread_id_support;
493 // Unsafe to use unless has_thread_id_support
494 AtomicInt<uint32_t> thread_id;
495 LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
496
497 /// Create the expected integer value for futex `wait(int* addr, int expected)`.
498 /// We pass the base address as the first argument, So this function creates
499 /// an zero-initialized integer with `b` copied at the correct offset.
500 static int expected_value_for_futex(uint8_t b) {
501 int dest_val = 0;
502 std::memcpy(reinterpret_cast<char*>(&dest_val) + 1, &b, 1);
503 return dest_val;
504 }
505
506 static_assert(Wait != nullptr && Wake != nullptr, "");
507};
508
509//===----------------------------------------------------------------------===//
510//
511//===----------------------------------------------------------------------===//
512
513template <class T>
514struct GlobalStatic {
515 static T instance;
516};
517template <class T>
518_LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
519
520enum class Implementation {
521 NoThreads,
522 GlobalLock,
523 Futex
524};
525
526template <Implementation Impl>
527struct SelectImplementation;
528
529template <>
530struct SelectImplementation<Implementation::NoThreads> {
531 using type = InitByteNoThreads;
532};
533
534template <>
535struct SelectImplementation<Implementation::GlobalLock> {
536 using type = InitByteGlobalMutex<
537 LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
538 GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
539};
540
541template <>
542struct SelectImplementation<Implementation::Futex> {
543 using type =
544 InitByteFutex<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
545};
546
547// TODO(EricWF): We should prefer the futex implementation when available. But
548// it should be done in a separate step from adding the implementation.
549constexpr Implementation CurrentImplementation =
550#if defined(_LIBCXXABI_HAS_NO_THREADS)
551 Implementation::NoThreads;
552#elif defined(_LIBCXXABI_USE_FUTEX)
553 Implementation::Futex;
554#else
555 Implementation::GlobalLock;
556#endif
557
558static_assert(CurrentImplementation != Implementation::Futex
559 || PlatformSupportsFutex(), "Futex selected but not supported");
560
561using SelectedImplementation =
562 SelectImplementation<CurrentImplementation>::type;
563
564} // end namespace
565} // end namespace __cxxabiv1
566
567#endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
lib/libcxxabi/src/cxa_handlers.cpp created+111
...@@ -0,0 +1,111 @@
1//===------------------------- cxa_handlers.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the functionality associated with the terminate_handler,
9// unexpected_handler, and new_handler.
10//===----------------------------------------------------------------------===//
11
12#include <stdexcept>
13#include <new>
14#include <exception>
15#include "abort_message.h"
16#include "cxxabi.h"
17#include "cxa_handlers.h"
18#include "cxa_exception.h"
19#include "private_typeinfo.h"
20#include "include/atomic_support.h"
21
22namespace std
23{
24
25unexpected_handler
26get_unexpected() _NOEXCEPT
27{
28 return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire);
29}
30
31void
32__unexpected(unexpected_handler func)
33{
34 func();
35 // unexpected handler should not return
36 abort_message("unexpected_handler unexpectedly returned");
37}
38
39__attribute__((noreturn))
40void
41unexpected()
42{
43 __unexpected(get_unexpected());
44}
45
46terminate_handler
47get_terminate() _NOEXCEPT
48{
49 return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire);
50}
51
52void
53__terminate(terminate_handler func) _NOEXCEPT
54{
55#ifndef _LIBCXXABI_NO_EXCEPTIONS
56 try
57 {
58#endif // _LIBCXXABI_NO_EXCEPTIONS
59 func();
60 // handler should not return
61 abort_message("terminate_handler unexpectedly returned");
62#ifndef _LIBCXXABI_NO_EXCEPTIONS
63 }
64 catch (...)
65 {
66 // handler should not throw exception
67 abort_message("terminate_handler unexpectedly threw an exception");
68 }
69#endif // _LIBCXXABI_NO_EXCEPTIONS
70}
71
72__attribute__((noreturn))
73void
74terminate() _NOEXCEPT
75{
76#ifndef _LIBCXXABI_NO_EXCEPTIONS
77 // If there might be an uncaught exception
78 using namespace __cxxabiv1;
79 __cxa_eh_globals* globals = __cxa_get_globals_fast();
80 if (globals)
81 {
82 __cxa_exception* exception_header = globals->caughtExceptions;
83 if (exception_header)
84 {
85 _Unwind_Exception* unwind_exception =
86 reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
87 if (__isOurExceptionClass(unwind_exception))
88 __terminate(exception_header->terminateHandler);
89 }
90 }
91#endif
92 __terminate(get_terminate());
93}
94
95extern "C" {
96new_handler __cxa_new_handler = 0;
97}
98
99new_handler
100set_new_handler(new_handler handler) _NOEXCEPT
101{
102 return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
103}
104
105new_handler
106get_new_handler() _NOEXCEPT
107{
108 return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire);
109}
110
111} // std
lib/libcxxabi/src/cxa_handlers.h created+55
...@@ -0,0 +1,55 @@
1//===------------------------- cxa_handlers.h -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the functionality associated with the terminate_handler,
9// unexpected_handler, and new_handler.
10//===----------------------------------------------------------------------===//
11
12#ifndef _CXA_HANDLERS_H
13#define _CXA_HANDLERS_H
14
15#include <__cxxabi_config.h>
16
17#include <exception>
18
19namespace std
20{
21
22_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
23void
24__unexpected(unexpected_handler func);
25
26_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN
27void
28__terminate(terminate_handler func) _NOEXCEPT;
29
30} // std
31
32extern "C"
33{
34
35_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)();
36_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)();
37_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)();
38
39/*
40
41 At some point in the future these three symbols will become
42 C++11 atomic variables:
43
44 extern std::atomic<std::terminate_handler> __cxa_terminate_handler;
45 extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler;
46 extern std::atomic<std::new_handler> __cxa_new_handler;
47
48 This change will not impact their ABI. But it will allow for a
49 portable performance optimization.
50
51*/
52
53} // extern "C"
54
55#endif // _CXA_HANDLERS_H
lib/libcxxabi/src/cxa_noexception.cpp created+59
...@@ -0,0 +1,59 @@
1//===------------------------- cxa_exception.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Exception Handling APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
10//
11//===----------------------------------------------------------------------===//
12
13// Support functions for the no-exceptions libc++ library
14
15#include "cxxabi.h"
16
17#include <exception> // for std::terminate
18#include "cxa_exception.h"
19#include "cxa_handlers.h"
20
21namespace __cxxabiv1 {
22
23extern "C" {
24
25void
26__cxa_increment_exception_refcount(void *thrown_object) throw() {
27 if (thrown_object != nullptr)
28 std::terminate();
29}
30
31void
32__cxa_decrement_exception_refcount(void *thrown_object) throw() {
33 if (thrown_object != nullptr)
34 std::terminate();
35}
36
37
38void *__cxa_current_primary_exception() throw() { return nullptr; }
39
40void
41__cxa_rethrow_primary_exception(void* thrown_object) {
42 if (thrown_object != nullptr)
43 std::terminate();
44}
45
46bool
47__cxa_uncaught_exception() throw() { return false; }
48
49unsigned int
50__cxa_uncaught_exceptions() throw() { return 0; }
51
52} // extern "C"
53
54// provide dummy implementations for the 'no exceptions' case.
55uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; }
56void __setExceptionClass ( _Unwind_Exception*, uint64_t) {}
57bool __isOurExceptionClass(const _Unwind_Exception*) { return false; }
58
59} // abi
lib/libcxxabi/src/cxa_personality.cpp created+1324
...@@ -0,0 +1,1324 @@
1//===------------------------- cxa_exception.cpp --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Exception Handling APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
10// http://www.intel.com/design/itanium/downloads/245358.htm
11//
12//===----------------------------------------------------------------------===//
13
14#include <assert.h>
15#include <stdlib.h>
16#include <string.h>
17#include <typeinfo>
18
19#include "__cxxabi_config.h"
20#include "cxa_exception.h"
21#include "cxa_handlers.h"
22#include "private_typeinfo.h"
23#include "unwind.h"
24
25#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
26#include <windows.h>
27#include <winnt.h>
28
29extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
30 void *, PCONTEXT,
31 PDISPATCHER_CONTEXT,
32 _Unwind_Personality_Fn);
33#endif
34
35/*
36 Exception Header Layout:
37
38+---------------------------+-----------------------------+---------------+
39| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
40+---------------------------+-----------------------------+---------------+
41 ^
42 |
43 +-------------------------------------------------------+
44 |
45+---------------------------+-----------------------------+
46| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
47+---------------------------+-----------------------------+
48
49 Exception Handling Table Layout:
50
51+-----------------+--------+
52| lpStartEncoding | (char) |
53+---------+-------+--------+---------------+-----------------------+
54| lpStart | (encoded with lpStartEncoding) | defaults to funcStart |
55+---------+-----+--------+-----------------+---------------+-------+
56| ttypeEncoding | (char) | Encoding of the type_info table |
57+---------------+-+------+----+----------------------------+----------------+
58| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null |
59+-----------------++--------+-+----------------------------+----------------+
60| callSiteEncoding | (char) | Encoding for Call Site Table |
61+------------------+--+-----+-----+------------------------+--------------------------+
62| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
63+---------------------+-----------+---------------------------------------------------+
64#ifndef __USING_SJLJ_EXCEPTIONS__
65+---------------------+-----------+------------------------------------------------+
66| Beginning of Call Site Table The current ip lies within the |
67| ... (start, length) range of one of these |
68| call sites. There may be action needed. |
69| +-------------+---------------------------------+------------------------------+ |
70| | start | (encoded with callSiteEncoding) | offset relative to funcStart | |
71| | length | (encoded with callSiteEncoding) | length of code fragment | |
72| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | |
73| | actionEntry | (ULEB128) | Action Table Index 1-based | |
74| | | | actionEntry == 0 -> cleanup | |
75| +-------------+---------------------------------+------------------------------+ |
76| ... |
77+----------------------------------------------------------------------------------+
78#else // __USING_SJLJ_EXCEPTIONS__
79+---------------------+-----------+------------------------------------------------+
80| Beginning of Call Site Table The current ip is a 1-based index into |
81| ... this table. Or it is -1 meaning no |
82| action is needed. Or it is 0 meaning |
83| terminate. |
84| +-------------+---------------------------------+------------------------------+ |
85| | landingPad | (ULEB128) | offset relative to lpStart | |
86| | actionEntry | (ULEB128) | Action Table Index 1-based | |
87| | | | actionEntry == 0 -> cleanup | |
88| +-------------+---------------------------------+------------------------------+ |
89| ... |
90+----------------------------------------------------------------------------------+
91#endif // __USING_SJLJ_EXCEPTIONS__
92+---------------------------------------------------------------------+
93| Beginning of Action Table ttypeIndex == 0 : cleanup |
94| ... ttypeIndex > 0 : catch |
95| ttypeIndex < 0 : exception spec |
96| +--------------+-----------+--------------------------------------+ |
97| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | |
98| | actionOffset | (SLEB128) | Offset into next Action Table entry | |
99| +--------------+-----------+--------------------------------------+ |
100| ... |
101+---------------------------------------------------------------------+-----------------+
102| type_info Table, but classInfoOffset does *not* point here! |
103| +----------------+------------------------------------------------+-----------------+ |
104| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | |
105| +----------------+------------------------------------------------+-----------------+ |
106| ... |
107| +----------------+------------------------------------------------+-----------------+ |
108| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | |
109| +----------------+------------------------------------------------+-----------------+ |
110| +---------------------------------------+-----------+------------------------------+ |
111| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | |
112| | ... | (ULEB128) | | |
113| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | |
114| | 0 | (ULEB128) | | |
115| +---------------------------------------+------------------------------------------+ |
116| ... |
117| +---------------------------------------+------------------------------------------+ |
118| | 0 | (ULEB128) | throw() | |
119| +---------------------------------------+------------------------------------------+ |
120| ... |
121| +---------------------------------------+------------------------------------------+ |
122| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | |
123| | ... | (ULEB128) | | |
124| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | |
125| | 0 | (ULEB128) | | |
126| +---------------------------------------+------------------------------------------+ |
127+---------------------------------------------------------------------------------------+
128
129Notes:
130
131* ttypeIndex in the Action Table, and in the exception spec table, is an index,
132 not a byte count, if positive. It is a negative index offset of
133 classInfoOffset and the sizeof entry depends on ttypeEncoding.
134 But if ttypeIndex is negative, it is a positive 1-based byte offset into the
135 type_info Table.
136 And if ttypeIndex is zero, it refers to a catch (...).
137
138* landingPad can be 0, this implies there is nothing to be done.
139
140* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done
141 @landingPad.
142
143* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in
144 the Action Table with ttypeIndex == 0.
145*/
146
147namespace __cxxabiv1
148{
149
150namespace
151{
152
153template <class AsType>
154uintptr_t readPointerHelper(const uint8_t*& p) {
155 AsType value;
156 memcpy(&value, p, sizeof(AsType));
157 p += sizeof(AsType);
158 return static_cast<uintptr_t>(value);
159}
160
161} // end namespace
162
163extern "C"
164{
165
166// private API
167
168// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp
169
170// DWARF Constants
171enum
172{
173 DW_EH_PE_absptr = 0x00,
174 DW_EH_PE_uleb128 = 0x01,
175 DW_EH_PE_udata2 = 0x02,
176 DW_EH_PE_udata4 = 0x03,
177 DW_EH_PE_udata8 = 0x04,
178 DW_EH_PE_sleb128 = 0x09,
179 DW_EH_PE_sdata2 = 0x0A,
180 DW_EH_PE_sdata4 = 0x0B,
181 DW_EH_PE_sdata8 = 0x0C,
182 DW_EH_PE_pcrel = 0x10,
183 DW_EH_PE_textrel = 0x20,
184 DW_EH_PE_datarel = 0x30,
185 DW_EH_PE_funcrel = 0x40,
186 DW_EH_PE_aligned = 0x50,
187 DW_EH_PE_indirect = 0x80,
188 DW_EH_PE_omit = 0xFF
189};
190
191/// Read a uleb128 encoded value and advance pointer
192/// See Variable Length Data Appendix C in:
193/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
194/// @param data reference variable holding memory pointer to decode from
195/// @returns decoded value
196static
197uintptr_t
198readULEB128(const uint8_t** data)
199{
200 uintptr_t result = 0;
201 uintptr_t shift = 0;
202 unsigned char byte;
203 const uint8_t *p = *data;
204 do
205 {
206 byte = *p++;
207 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
208 shift += 7;
209 } while (byte & 0x80);
210 *data = p;
211 return result;
212}
213
214/// Read a sleb128 encoded value and advance pointer
215/// See Variable Length Data Appendix C in:
216/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
217/// @param data reference variable holding memory pointer to decode from
218/// @returns decoded value
219static
220intptr_t
221readSLEB128(const uint8_t** data)
222{
223 uintptr_t result = 0;
224 uintptr_t shift = 0;
225 unsigned char byte;
226 const uint8_t *p = *data;
227 do
228 {
229 byte = *p++;
230 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
231 shift += 7;
232 } while (byte & 0x80);
233 *data = p;
234 if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
235 result |= static_cast<uintptr_t>(~0) << shift;
236 return static_cast<intptr_t>(result);
237}
238
239/// Read a pointer encoded value and advance pointer
240/// See Variable Length Data in:
241/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
242/// @param data reference variable holding memory pointer to decode from
243/// @param encoding dwarf encoding type
244/// @returns decoded value
245static
246uintptr_t
247readEncodedPointer(const uint8_t** data, uint8_t encoding)
248{
249 uintptr_t result = 0;
250 if (encoding == DW_EH_PE_omit)
251 return result;
252 const uint8_t* p = *data;
253 // first get value
254 switch (encoding & 0x0F)
255 {
256 case DW_EH_PE_absptr:
257 result = readPointerHelper<uintptr_t>(p);
258 break;
259 case DW_EH_PE_uleb128:
260 result = readULEB128(&p);
261 break;
262 case DW_EH_PE_sleb128:
263 result = static_cast<uintptr_t>(readSLEB128(&p));
264 break;
265 case DW_EH_PE_udata2:
266 result = readPointerHelper<uint16_t>(p);
267 break;
268 case DW_EH_PE_udata4:
269 result = readPointerHelper<uint32_t>(p);
270 break;
271 case DW_EH_PE_udata8:
272 result = readPointerHelper<uint64_t>(p);
273 break;
274 case DW_EH_PE_sdata2:
275 result = readPointerHelper<int16_t>(p);
276 break;
277 case DW_EH_PE_sdata4:
278 result = readPointerHelper<int32_t>(p);
279 break;
280 case DW_EH_PE_sdata8:
281 result = readPointerHelper<int64_t>(p);
282 break;
283 default:
284 // not supported
285 abort();
286 break;
287 }
288 // then add relative offset
289 switch (encoding & 0x70)
290 {
291 case DW_EH_PE_absptr:
292 // do nothing
293 break;
294 case DW_EH_PE_pcrel:
295 if (result)
296 result += (uintptr_t)(*data);
297 break;
298 case DW_EH_PE_textrel:
299 case DW_EH_PE_datarel:
300 case DW_EH_PE_funcrel:
301 case DW_EH_PE_aligned:
302 default:
303 // not supported
304 abort();
305 break;
306 }
307 // then apply indirection
308 if (result && (encoding & DW_EH_PE_indirect))
309 result = *((uintptr_t*)result);
310 *data = p;
311 return result;
312}
313
314static
315void
316call_terminate(bool native_exception, _Unwind_Exception* unwind_exception)
317{
318 __cxa_begin_catch(unwind_exception);
319 if (native_exception)
320 {
321 // Use the stored terminate_handler if possible
322 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
323 std::__terminate(exception_header->terminateHandler);
324 }
325 std::terminate();
326}
327
328#if defined(_LIBCXXABI_ARM_EHABI)
329static const void* read_target2_value(const void* ptr)
330{
331 uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr);
332 if (!offset)
333 return 0;
334 // "ARM EABI provides a TARGET2 relocation to describe these typeinfo
335 // pointers. The reason being it allows their precise semantics to be
336 // deferred to the linker. For bare-metal they turn into absolute
337 // relocations. For linux they turn into GOT-REL relocations."
338 // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html
339#if defined(LIBCXXABI_BAREMETAL)
340 return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(ptr) +
341 offset);
342#else
343 return *reinterpret_cast<const void **>(reinterpret_cast<uintptr_t>(ptr) +
344 offset);
345#endif
346}
347
348static const __shim_type_info*
349get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
350 uint8_t ttypeEncoding, bool native_exception,
351 _Unwind_Exception* unwind_exception)
352{
353 if (classInfo == 0)
354 {
355 // this should not happen. Indicates corrupted eh_table.
356 call_terminate(native_exception, unwind_exception);
357 }
358
359 assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6
360 (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal
361 (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux
362 "Unexpected TTypeEncoding");
363 (void)ttypeEncoding;
364
365 const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t);
366 return reinterpret_cast<const __shim_type_info *>(
367 read_target2_value(ttypePtr));
368}
369#else // !defined(_LIBCXXABI_ARM_EHABI)
370static
371const __shim_type_info*
372get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
373 uint8_t ttypeEncoding, bool native_exception,
374 _Unwind_Exception* unwind_exception)
375{
376 if (classInfo == 0)
377 {
378 // this should not happen. Indicates corrupted eh_table.
379 call_terminate(native_exception, unwind_exception);
380 }
381 switch (ttypeEncoding & 0x0F)
382 {
383 case DW_EH_PE_absptr:
384 ttypeIndex *= sizeof(void*);
385 break;
386 case DW_EH_PE_udata2:
387 case DW_EH_PE_sdata2:
388 ttypeIndex *= 2;
389 break;
390 case DW_EH_PE_udata4:
391 case DW_EH_PE_sdata4:
392 ttypeIndex *= 4;
393 break;
394 case DW_EH_PE_udata8:
395 case DW_EH_PE_sdata8:
396 ttypeIndex *= 8;
397 break;
398 default:
399 // this should not happen. Indicates corrupted eh_table.
400 call_terminate(native_exception, unwind_exception);
401 }
402 classInfo -= ttypeIndex;
403 return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);
404}
405#endif // !defined(_LIBCXXABI_ARM_EHABI)
406
407/*
408 This is checking a thrown exception type, excpType, against a possibly empty
409 list of catchType's which make up an exception spec.
410
411 An exception spec acts like a catch handler, but in reverse. This "catch
412 handler" will catch an excpType if and only if none of the catchType's in
413 the list will catch a excpType. If any catchType in the list can catch an
414 excpType, then this exception spec does not catch the excpType.
415*/
416#if defined(_LIBCXXABI_ARM_EHABI)
417static
418bool
419exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
420 uint8_t ttypeEncoding, const __shim_type_info* excpType,
421 void* adjustedPtr, _Unwind_Exception* unwind_exception)
422{
423 if (classInfo == 0)
424 {
425 // this should not happen. Indicates corrupted eh_table.
426 call_terminate(false, unwind_exception);
427 }
428
429 assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6
430 (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal
431 (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux
432 "Unexpected TTypeEncoding");
433 (void)ttypeEncoding;
434
435 // specIndex is negative of 1-based byte offset into classInfo;
436 specIndex = -specIndex;
437 --specIndex;
438 const void** temp = reinterpret_cast<const void**>(
439 reinterpret_cast<uintptr_t>(classInfo) +
440 static_cast<uintptr_t>(specIndex) * sizeof(uintptr_t));
441 // If any type in the spec list can catch excpType, return false, else return true
442 // adjustments to adjustedPtr are ignored.
443 while (true)
444 {
445 // ARM EHABI exception specification table (filter table) consists of
446 // several pointers which will directly point to the type info object
447 // (instead of ttypeIndex). The table will be terminated with 0.
448 const void** ttypePtr = temp++;
449 if (*ttypePtr == 0)
450 break;
451 // We can get the __shim_type_info simply by performing a
452 // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info.
453 const __shim_type_info* catchType =
454 static_cast<const __shim_type_info*>(read_target2_value(ttypePtr));
455 void* tempPtr = adjustedPtr;
456 if (catchType->can_catch(excpType, tempPtr))
457 return false;
458 }
459 return true;
460}
461#else
462static
463bool
464exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
465 uint8_t ttypeEncoding, const __shim_type_info* excpType,
466 void* adjustedPtr, _Unwind_Exception* unwind_exception)
467{
468 if (classInfo == 0)
469 {
470 // this should not happen. Indicates corrupted eh_table.
471 call_terminate(false, unwind_exception);
472 }
473 // specIndex is negative of 1-based byte offset into classInfo;
474 specIndex = -specIndex;
475 --specIndex;
476 const uint8_t* temp = classInfo + specIndex;
477 // If any type in the spec list can catch excpType, return false, else return true
478 // adjustments to adjustedPtr are ignored.
479 while (true)
480 {
481 uint64_t ttypeIndex = readULEB128(&temp);
482 if (ttypeIndex == 0)
483 break;
484 const __shim_type_info* catchType = get_shim_type_info(ttypeIndex,
485 classInfo,
486 ttypeEncoding,
487 true,
488 unwind_exception);
489 void* tempPtr = adjustedPtr;
490 if (catchType->can_catch(excpType, tempPtr))
491 return false;
492 }
493 return true;
494}
495#endif
496
497static
498void*
499get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
500{
501 // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1
502 // Regardless, this library is prohibited from touching a foreign exception
503 void* adjustedPtr = unwind_exception + 1;
504 if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass)
505 adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException;
506 return adjustedPtr;
507}
508
509namespace
510{
511
512struct scan_results
513{
514 int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
515 const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance.
516 const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected
517 uintptr_t landingPad; // null -> nothing found, else something found
518 void* adjustedPtr; // Used in cxa_exception.cpp
519 _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR,
520 // _URC_FATAL_PHASE2_ERROR,
521 // _URC_CONTINUE_UNWIND,
522 // _URC_HANDLER_FOUND
523};
524
525} // unnamed namespace
526
527static
528void
529set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
530 const scan_results& results)
531{
532#if defined(__USING_SJLJ_EXCEPTIONS__)
533#define __builtin_eh_return_data_regno(regno) regno
534#endif
535 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
536 reinterpret_cast<uintptr_t>(unwind_exception));
537 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
538 static_cast<uintptr_t>(results.ttypeIndex));
539 _Unwind_SetIP(context, results.landingPad);
540}
541
542/*
543 There are 3 types of scans needed:
544
545 1. Scan for handler with native or foreign exception. If handler found,
546 save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.
547 May also report an error on invalid input.
548 May terminate for invalid exception table.
549 _UA_SEARCH_PHASE
550
551 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND,
552 or call terminate.
553 _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception
554
555 3. Scan for cleanups. If a handler is found and this isn't forced unwind,
556 then terminate, otherwise ignore the handler and keep looking for cleanup.
557 If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.
558 May also report an error on invalid input.
559 May terminate for invalid exception table.
560 _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME
561*/
562
563static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
564 bool native_exception,
565 _Unwind_Exception *unwind_exception,
566 _Unwind_Context *context) {
567 // Initialize results to found nothing but an error
568 results.ttypeIndex = 0;
569 results.actionRecord = 0;
570 results.languageSpecificData = 0;
571 results.landingPad = 0;
572 results.adjustedPtr = 0;
573 results.reason = _URC_FATAL_PHASE1_ERROR;
574 // Check for consistent actions
575 if (actions & _UA_SEARCH_PHASE)
576 {
577 // Do Phase 1
578 if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND))
579 {
580 // None of these flags should be set during Phase 1
581 // Client error
582 results.reason = _URC_FATAL_PHASE1_ERROR;
583 return;
584 }
585 }
586 else if (actions & _UA_CLEANUP_PHASE)
587 {
588 if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND))
589 {
590 // _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
591 // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
592 // Client error
593 results.reason = _URC_FATAL_PHASE2_ERROR;
594 return;
595 }
596 }
597 else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set
598 {
599 // One of these should be set.
600 // Client error
601 results.reason = _URC_FATAL_PHASE1_ERROR;
602 return;
603 }
604 // Start scan by getting exception table address
605 const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);
606 if (lsda == 0)
607 {
608 // There is no exception table
609 results.reason = _URC_CONTINUE_UNWIND;
610 return;
611 }
612 results.languageSpecificData = lsda;
613 // Get the current instruction pointer and offset it before next
614 // instruction in the current frame which threw the exception.
615 uintptr_t ip = _Unwind_GetIP(context) - 1;
616 // Get beginning current frame's code (as defined by the
617 // emitted dwarf code)
618 uintptr_t funcStart = _Unwind_GetRegionStart(context);
619#ifdef __USING_SJLJ_EXCEPTIONS__
620 if (ip == uintptr_t(-1))
621 {
622 // no action
623 results.reason = _URC_CONTINUE_UNWIND;
624 return;
625 }
626 else if (ip == 0)
627 call_terminate(native_exception, unwind_exception);
628 // ip is 1-based index into call site table
629#else // !__USING_SJLJ_EXCEPTIONS__
630 uintptr_t ipOffset = ip - funcStart;
631#endif // !defined(_USING_SLJL_EXCEPTIONS__)
632 const uint8_t* classInfo = NULL;
633 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
634 // dwarf emission
635 // Parse LSDA header.
636 uint8_t lpStartEncoding = *lsda++;
637 const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
638 if (lpStart == 0)
639 lpStart = (const uint8_t*)funcStart;
640 uint8_t ttypeEncoding = *lsda++;
641 if (ttypeEncoding != DW_EH_PE_omit)
642 {
643 // Calculate type info locations in emitted dwarf code which
644 // were flagged by type info arguments to llvm.eh.selector
645 // intrinsic
646 uintptr_t classInfoOffset = readULEB128(&lsda);
647 classInfo = lsda + classInfoOffset;
648 }
649 // Walk call-site table looking for range that
650 // includes current PC.
651 uint8_t callSiteEncoding = *lsda++;
652#ifdef __USING_SJLJ_EXCEPTIONS__
653 (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used
654#endif
655 uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
656 const uint8_t* callSiteTableStart = lsda;
657 const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
658 const uint8_t* actionTableStart = callSiteTableEnd;
659 const uint8_t* callSitePtr = callSiteTableStart;
660 while (callSitePtr < callSiteTableEnd)
661 {
662 // There is one entry per call site.
663#ifndef __USING_SJLJ_EXCEPTIONS__
664 // The call sites are non-overlapping in [start, start+length)
665 // The call sites are ordered in increasing value of start
666 uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
667 uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
668 uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
669 uintptr_t actionEntry = readULEB128(&callSitePtr);
670 if ((start <= ipOffset) && (ipOffset < (start + length)))
671#else // __USING_SJLJ_EXCEPTIONS__
672 // ip is 1-based index into this table
673 uintptr_t landingPad = readULEB128(&callSitePtr);
674 uintptr_t actionEntry = readULEB128(&callSitePtr);
675 if (--ip == 0)
676#endif // __USING_SJLJ_EXCEPTIONS__
677 {
678 // Found the call site containing ip.
679#ifndef __USING_SJLJ_EXCEPTIONS__
680 if (landingPad == 0)
681 {
682 // No handler here
683 results.reason = _URC_CONTINUE_UNWIND;
684 return;
685 }
686 landingPad = (uintptr_t)lpStart + landingPad;
687#else // __USING_SJLJ_EXCEPTIONS__
688 ++landingPad;
689#endif // __USING_SJLJ_EXCEPTIONS__
690 if (actionEntry == 0)
691 {
692 // Found a cleanup
693 // If this is a type 1 or type 2 search, there are no handlers
694 // If this is a type 3 search, you want to install the cleanup.
695 if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
696 {
697 results.ttypeIndex = 0; // Redundant but clarifying
698 results.landingPad = landingPad;
699 results.reason = _URC_HANDLER_FOUND;
700 return;
701 }
702 // No handler here
703 results.reason = _URC_CONTINUE_UNWIND;
704 return;
705 }
706 // Convert 1-based byte offset into
707 const uint8_t* action = actionTableStart + (actionEntry - 1);
708 // Scan action entries until you find a matching handler, cleanup, or the end of action list
709 while (true)
710 {
711 const uint8_t* actionRecord = action;
712 int64_t ttypeIndex = readSLEB128(&action);
713 if (ttypeIndex > 0)
714 {
715 // Found a catch, does it actually catch?
716 // First check for catch (...)
717 const __shim_type_info* catchType =
718 get_shim_type_info(static_cast<uint64_t>(ttypeIndex),
719 classInfo, ttypeEncoding,
720 native_exception, unwind_exception);
721 if (catchType == 0)
722 {
723 // Found catch (...) catches everything, including foreign exceptions
724 // If this is a type 1 search save state and return _URC_HANDLER_FOUND
725 // If this is a type 2 search save state and return _URC_HANDLER_FOUND
726 // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
727 // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
728 if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
729 {
730 // Save state and return _URC_HANDLER_FOUND
731 results.ttypeIndex = ttypeIndex;
732 results.actionRecord = actionRecord;
733 results.landingPad = landingPad;
734 results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
735 results.reason = _URC_HANDLER_FOUND;
736 return;
737 }
738 else if (!(actions & _UA_FORCE_UNWIND))
739 {
740 // It looks like the exception table has changed
741 // on us. Likely stack corruption!
742 call_terminate(native_exception, unwind_exception);
743 }
744 }
745 // Else this is a catch (T) clause and will never
746 // catch a foreign exception
747 else if (native_exception)
748 {
749 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
750 void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
751 const __shim_type_info* excpType =
752 static_cast<const __shim_type_info*>(exception_header->exceptionType);
753 if (adjustedPtr == 0 || excpType == 0)
754 {
755 // Something very bad happened
756 call_terminate(native_exception, unwind_exception);
757 }
758 if (catchType->can_catch(excpType, adjustedPtr))
759 {
760 // Found a matching handler
761 // If this is a type 1 search save state and return _URC_HANDLER_FOUND
762 // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
763 // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
764 if (actions & _UA_SEARCH_PHASE)
765 {
766 // Save state and return _URC_HANDLER_FOUND
767 results.ttypeIndex = ttypeIndex;
768 results.actionRecord = actionRecord;
769 results.landingPad = landingPad;
770 results.adjustedPtr = adjustedPtr;
771 results.reason = _URC_HANDLER_FOUND;
772 return;
773 }
774 else if (!(actions & _UA_FORCE_UNWIND))
775 {
776 // It looks like the exception table has changed
777 // on us. Likely stack corruption!
778 call_terminate(native_exception, unwind_exception);
779 }
780 }
781 }
782 // Scan next action ...
783 }
784 else if (ttypeIndex < 0)
785 {
786 // Found an exception spec. If this is a foreign exception,
787 // it is always caught.
788 if (native_exception)
789 {
790 // Does the exception spec catch this native exception?
791 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
792 void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
793 const __shim_type_info* excpType =
794 static_cast<const __shim_type_info*>(exception_header->exceptionType);
795 if (adjustedPtr == 0 || excpType == 0)
796 {
797 // Something very bad happened
798 call_terminate(native_exception, unwind_exception);
799 }
800 if (exception_spec_can_catch(ttypeIndex, classInfo,
801 ttypeEncoding, excpType,
802 adjustedPtr, unwind_exception))
803 {
804 // native exception caught by exception spec
805 // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
806 // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
807 // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
808 if (actions & _UA_SEARCH_PHASE)
809 {
810 // Save state and return _URC_HANDLER_FOUND
811 results.ttypeIndex = ttypeIndex;
812 results.actionRecord = actionRecord;
813 results.landingPad = landingPad;
814 results.adjustedPtr = adjustedPtr;
815 results.reason = _URC_HANDLER_FOUND;
816 return;
817 }
818 else if (!(actions & _UA_FORCE_UNWIND))
819 {
820 // It looks like the exception table has changed
821 // on us. Likely stack corruption!
822 call_terminate(native_exception, unwind_exception);
823 }
824 }
825 }
826 else
827 {
828 // foreign exception caught by exception spec
829 // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
830 // If this is a type 2 search, save state and return _URC_HANDLER_FOUND
831 // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
832 // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
833 if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
834 {
835 // Save state and return _URC_HANDLER_FOUND
836 results.ttypeIndex = ttypeIndex;
837 results.actionRecord = actionRecord;
838 results.landingPad = landingPad;
839 results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
840 results.reason = _URC_HANDLER_FOUND;
841 return;
842 }
843 else if (!(actions & _UA_FORCE_UNWIND))
844 {
845 // It looks like the exception table has changed
846 // on us. Likely stack corruption!
847 call_terminate(native_exception, unwind_exception);
848 }
849 }
850 // Scan next action ...
851 }
852 else // ttypeIndex == 0
853 {
854 // Found a cleanup
855 // If this is a type 1 search, ignore it and continue scan
856 // If this is a type 2 search, ignore it and continue scan
857 // If this is a type 3 search, save state and return _URC_HANDLER_FOUND
858 if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
859 {
860 // Save state and return _URC_HANDLER_FOUND
861 results.ttypeIndex = ttypeIndex;
862 results.actionRecord = actionRecord;
863 results.landingPad = landingPad;
864 results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
865 results.reason = _URC_HANDLER_FOUND;
866 return;
867 }
868 }
869 const uint8_t* temp = action;
870 int64_t actionOffset = readSLEB128(&temp);
871 if (actionOffset == 0)
872 {
873 // End of action list, no matching handler or cleanup found
874 results.reason = _URC_CONTINUE_UNWIND;
875 return;
876 }
877 // Go to next action
878 action += actionOffset;
879 } // there is no break out of this loop, only return
880 }
881#ifndef __USING_SJLJ_EXCEPTIONS__
882 else if (ipOffset < start)
883 {
884 // There is no call site for this ip
885 // Something bad has happened. We should never get here.
886 // Possible stack corruption.
887 call_terminate(native_exception, unwind_exception);
888 }
889#endif // !__USING_SJLJ_EXCEPTIONS__
890 } // there might be some tricky cases which break out of this loop
891
892 // It is possible that no eh table entry specify how to handle
893 // this exception. By spec, terminate it immediately.
894 call_terminate(native_exception, unwind_exception);
895}
896
897// public API
898
899/*
900The personality function branches on actions like so:
901
902_UA_SEARCH_PHASE
903
904 If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's
905 an error from above, return _URC_FATAL_PHASE1_ERROR.
906
907 Scan for anything that could stop unwinding:
908
909 1. A catch clause that will catch this exception
910 (will never catch foreign).
911 2. A catch (...) (will always catch foreign).
912 3. An exception spec that will catch this exception
913 (will always catch foreign).
914 If a handler is found
915 If not foreign
916 Save state in header
917 return _URC_HANDLER_FOUND
918 Else a handler not found
919 return _URC_CONTINUE_UNWIND
920
921_UA_CLEANUP_PHASE
922
923 If _UA_HANDLER_FRAME
924 If _UA_FORCE_UNWIND
925 How did this happen? return _URC_FATAL_PHASE2_ERROR
926 If foreign
927 Do _UA_SEARCH_PHASE to recover state
928 else
929 Recover state from header
930 Transfer control to landing pad. return _URC_INSTALL_CONTEXT
931
932 Else
933
934 This branch handles both normal C++ non-catching handlers (cleanups)
935 and forced unwinding.
936 Scan for anything that can not stop unwinding:
937
938 1. A cleanup.
939
940 If a cleanup is found
941 transfer control to it. return _URC_INSTALL_CONTEXT
942 Else a cleanup is not found: return _URC_CONTINUE_UNWIND
943*/
944
945#if !defined(_LIBCXXABI_ARM_EHABI)
946#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
947static _Unwind_Reason_Code __gxx_personality_imp
948#else
949_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
950#ifdef __USING_SJLJ_EXCEPTIONS__
951__gxx_personality_sj0
952#else
953__gxx_personality_v0
954#endif
955#endif
956 (int version, _Unwind_Action actions, uint64_t exceptionClass,
957 _Unwind_Exception* unwind_exception, _Unwind_Context* context)
958{
959 if (version != 1 || unwind_exception == 0 || context == 0)
960 return _URC_FATAL_PHASE1_ERROR;
961
962 bool native_exception = (exceptionClass & get_vendor_and_language) ==
963 (kOurExceptionClass & get_vendor_and_language);
964 scan_results results;
965 if (actions & _UA_SEARCH_PHASE)
966 {
967 // Phase 1 search: All we're looking for in phase 1 is a handler that
968 // halts unwinding
969 scan_eh_tab(results, actions, native_exception, unwind_exception, context);
970 if (results.reason == _URC_HANDLER_FOUND)
971 {
972 // Found one. Can we cache the results somewhere to optimize phase 2?
973 if (native_exception)
974 {
975 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
976 exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
977 exception_header->actionRecord = results.actionRecord;
978 exception_header->languageSpecificData = results.languageSpecificData;
979 exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad);
980 exception_header->adjustedPtr = results.adjustedPtr;
981 }
982 return _URC_HANDLER_FOUND;
983 }
984 // Did not find a catching-handler. Return the results of the scan
985 // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR
986 // if we were called improperly).
987 return results.reason;
988 }
989 if (actions & _UA_CLEANUP_PHASE)
990 {
991 // Phase 2 search:
992 // Did we find a catching handler in phase 1?
993 if (actions & _UA_HANDLER_FRAME)
994 {
995 // Yes, phase 1 said we have a catching handler here.
996 // Did we cache the results of the scan?
997 if (native_exception)
998 {
999 // Yes, reload the results from the cache.
1000 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
1001 results.ttypeIndex = exception_header->handlerSwitchValue;
1002 results.actionRecord = exception_header->actionRecord;
1003 results.languageSpecificData = exception_header->languageSpecificData;
1004 results.landingPad = reinterpret_cast<uintptr_t>(exception_header->catchTemp);
1005 results.adjustedPtr = exception_header->adjustedPtr;
1006 }
1007 else
1008 {
1009 // No, do the scan again to reload the results.
1010 scan_eh_tab(results, actions, native_exception, unwind_exception, context);
1011 // Phase 1 told us we would find a handler. Now in Phase 2 we
1012 // didn't find a handler. The eh table should not be changing!
1013 if (results.reason != _URC_HANDLER_FOUND)
1014 call_terminate(native_exception, unwind_exception);
1015 }
1016 // Jump to the handler
1017 set_registers(unwind_exception, context, results);
1018 return _URC_INSTALL_CONTEXT;
1019 }
1020 // Either we didn't do a phase 1 search (due to forced unwinding), or
1021 // phase 1 reported no catching-handlers.
1022 // Search for a (non-catching) cleanup
1023 scan_eh_tab(results, actions, native_exception, unwind_exception, context);
1024 if (results.reason == _URC_HANDLER_FOUND)
1025 {
1026 // Found a non-catching handler. Jump to it:
1027 set_registers(unwind_exception, context, results);
1028 return _URC_INSTALL_CONTEXT;
1029 }
1030 // Did not find a cleanup. Return the results of the scan
1031 // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR
1032 // if we were called improperly).
1033 return results.reason;
1034 }
1035 // We were called improperly: neither a phase 1 or phase 2 search
1036 return _URC_FATAL_PHASE1_ERROR;
1037}
1038
1039#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
1040extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION
1041__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
1042 PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
1043{
1044 return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
1045 __gxx_personality_imp);
1046}
1047#endif
1048
1049#else
1050
1051extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,
1052 _Unwind_Context*);
1053
1054// Helper function to unwind one frame.
1055// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the
1056// personality routine should update the virtual register set (VRS) according to the
1057// corresponding frame unwinding instructions (ARM EHABI 9.3.)
1058static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
1059 _Unwind_Context* context)
1060{
1061 if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK)
1062 return _URC_FAILURE;
1063 return _URC_CONTINUE_UNWIND;
1064}
1065
1066// ARM register names
1067#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
1068static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block
1069#endif
1070static const uint32_t REG_SP = 13;
1071
1072static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception,
1073 const scan_results& results)
1074{
1075 unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr;
1076 unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord;
1077 unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData;
1078 unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad;
1079 unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex;
1080}
1081
1082static void load_results_from_barrier_cache(scan_results& results,
1083 const _Unwind_Exception* unwind_exception)
1084{
1085 results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0];
1086 results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1];
1087 results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
1088 results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3];
1089 results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
1090}
1091
1092extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
1093__gxx_personality_v0(_Unwind_State state,
1094 _Unwind_Exception* unwind_exception,
1095 _Unwind_Context* context)
1096{
1097 if (unwind_exception == 0 || context == 0)
1098 return _URC_FATAL_PHASE1_ERROR;
1099
1100 bool native_exception = __isOurExceptionClass(unwind_exception);
1101
1102#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
1103 // Copy the address of _Unwind_Control_Block to r12 so that
1104 // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can
1105 // return correct address.
1106 _Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception));
1107#endif
1108
1109 // Check the undocumented force unwinding behavior
1110 bool is_force_unwinding = state & _US_FORCE_UNWIND;
1111 state &= ~_US_FORCE_UNWIND;
1112
1113 scan_results results;
1114 switch (state) {
1115 case _US_VIRTUAL_UNWIND_FRAME:
1116 if (is_force_unwinding)
1117 return continue_unwind(unwind_exception, context);
1118
1119 // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding
1120 scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context);
1121 if (results.reason == _URC_HANDLER_FOUND)
1122 {
1123 unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP);
1124 if (native_exception)
1125 save_results_to_barrier_cache(unwind_exception, results);
1126 return _URC_HANDLER_FOUND;
1127 }
1128 // Did not find the catch handler
1129 if (results.reason == _URC_CONTINUE_UNWIND)
1130 return continue_unwind(unwind_exception, context);
1131 return results.reason;
1132
1133 case _US_UNWIND_FRAME_STARTING:
1134 // TODO: Support force unwinding in the phase 2 search.
1135 // NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind()
1136 // will call this personality function with (_US_FORCE_UNWIND |
1137 // _US_UNWIND_FRAME_STARTING).
1138
1139 // Phase 2 search
1140 if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP))
1141 {
1142 // Found a catching handler in phase 1
1143 if (native_exception)
1144 {
1145 // Load the result from the native exception barrier cache.
1146 load_results_from_barrier_cache(results, unwind_exception);
1147 results.reason = _URC_HANDLER_FOUND;
1148 }
1149 else
1150 {
1151 // Search for the catching handler again for the foreign exception.
1152 scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME),
1153 native_exception, unwind_exception, context);
1154 if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one
1155 call_terminate(native_exception, unwind_exception);
1156 }
1157
1158 // Install the context for the catching handler
1159 set_registers(unwind_exception, context, results);
1160 return _URC_INSTALL_CONTEXT;
1161 }
1162
1163 // Either we didn't do a phase 1 search (due to forced unwinding), or
1164 // phase 1 reported no catching-handlers.
1165 // Search for a (non-catching) cleanup
1166 scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context);
1167 if (results.reason == _URC_HANDLER_FOUND)
1168 {
1169 // Found a non-catching handler
1170
1171 // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some
1172 // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from
1173 // __cxa_get_globals().
1174 __cxa_begin_cleanup(unwind_exception);
1175
1176 // Install the context for the cleanup handler
1177 set_registers(unwind_exception, context, results);
1178 return _URC_INSTALL_CONTEXT;
1179 }
1180
1181 // Did not find any handler
1182 if (results.reason == _URC_CONTINUE_UNWIND)
1183 return continue_unwind(unwind_exception, context);
1184 return results.reason;
1185
1186 case _US_UNWIND_FRAME_RESUME:
1187 return continue_unwind(unwind_exception, context);
1188 }
1189
1190 // We were called improperly: neither a phase 1 or phase 2 search
1191 return _URC_FATAL_PHASE1_ERROR;
1192}
1193#endif
1194
1195
1196__attribute__((noreturn))
1197_LIBCXXABI_FUNC_VIS void
1198__cxa_call_unexpected(void* arg)
1199{
1200 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
1201 if (unwind_exception == 0)
1202 call_terminate(false, unwind_exception);
1203 __cxa_begin_catch(unwind_exception);
1204 bool native_old_exception = __isOurExceptionClass(unwind_exception);
1205 std::unexpected_handler u_handler;
1206 std::terminate_handler t_handler;
1207 __cxa_exception* old_exception_header = 0;
1208 int64_t ttypeIndex;
1209 const uint8_t* lsda;
1210 if (native_old_exception)
1211 {
1212 old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
1213 t_handler = old_exception_header->terminateHandler;
1214 u_handler = old_exception_header->unexpectedHandler;
1215 // If std::__unexpected(u_handler) rethrows the same exception,
1216 // these values get overwritten by the rethrow. So save them now:
1217#if defined(_LIBCXXABI_ARM_EHABI)
1218 ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
1219 lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
1220#else
1221 ttypeIndex = old_exception_header->handlerSwitchValue;
1222 lsda = old_exception_header->languageSpecificData;
1223#endif
1224 }
1225 else
1226 {
1227 t_handler = std::get_terminate();
1228 u_handler = std::get_unexpected();
1229 }
1230 try
1231 {
1232 std::__unexpected(u_handler);
1233 }
1234 catch (...)
1235 {
1236 // If the old exception is foreign, then all we can do is terminate.
1237 // We have no way to recover the needed old exception spec. There's
1238 // no way to pass that information here. And the personality routine
1239 // can't call us directly and do anything but terminate() if we throw
1240 // from here.
1241 if (native_old_exception)
1242 {
1243 // Have:
1244 // old_exception_header->languageSpecificData
1245 // old_exception_header->actionRecord
1246 // Need
1247 // const uint8_t* classInfo
1248 // uint8_t ttypeEncoding
1249 uint8_t lpStartEncoding = *lsda++;
1250 const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
1251 (void)lpStart; // purposefully unused. Just needed to increment lsda.
1252 uint8_t ttypeEncoding = *lsda++;
1253 if (ttypeEncoding == DW_EH_PE_omit)
1254 std::__terminate(t_handler);
1255 uintptr_t classInfoOffset = readULEB128(&lsda);
1256 const uint8_t* classInfo = lsda + classInfoOffset;
1257 // Is this new exception catchable by the exception spec at ttypeIndex?
1258 // The answer is obviously yes if the new and old exceptions are the same exception
1259 // If no
1260 // throw;
1261 __cxa_eh_globals* globals = __cxa_get_globals_fast();
1262 __cxa_exception* new_exception_header = globals->caughtExceptions;
1263 if (new_exception_header == 0)
1264 // This shouldn't be able to happen!
1265 std::__terminate(t_handler);
1266 bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader);
1267 void* adjustedPtr;
1268 if (native_new_exception && (new_exception_header != old_exception_header))
1269 {
1270 const __shim_type_info* excpType =
1271 static_cast<const __shim_type_info*>(new_exception_header->exceptionType);
1272 adjustedPtr =
1273 __getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ?
1274 ((__cxa_dependent_exception*)new_exception_header)->primaryException :
1275 new_exception_header + 1;
1276 if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
1277 excpType, adjustedPtr, unwind_exception))
1278 {
1279 // We need to __cxa_end_catch, but for the old exception,
1280 // not the new one. This is a little tricky ...
1281 // Disguise new_exception_header as a rethrown exception, but
1282 // don't actually rethrow it. This means you can temporarily
1283 // end the catch clause enclosing new_exception_header without
1284 // __cxa_end_catch destroying new_exception_header.
1285 new_exception_header->handlerCount = -new_exception_header->handlerCount;
1286 globals->uncaughtExceptions += 1;
1287 // Call __cxa_end_catch for new_exception_header
1288 __cxa_end_catch();
1289 // Call __cxa_end_catch for old_exception_header
1290 __cxa_end_catch();
1291 // Renter this catch clause with new_exception_header
1292 __cxa_begin_catch(&new_exception_header->unwindHeader);
1293 // Rethrow new_exception_header
1294 throw;
1295 }
1296 }
1297 // Will a std::bad_exception be catchable by the exception spec at
1298 // ttypeIndex?
1299 // If no
1300 // throw std::bad_exception();
1301 const __shim_type_info* excpType =
1302 static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
1303 std::bad_exception be;
1304 adjustedPtr = &be;
1305 if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
1306 excpType, adjustedPtr, unwind_exception))
1307 {
1308 // We need to __cxa_end_catch for both the old exception and the
1309 // new exception. Technically we should do it in that order.
1310 // But it is expedient to do it in the opposite order:
1311 // Call __cxa_end_catch for new_exception_header
1312 __cxa_end_catch();
1313 // Throw std::bad_exception will __cxa_end_catch for
1314 // old_exception_header
1315 throw be;
1316 }
1317 }
1318 }
1319 std::__terminate(t_handler);
1320}
1321
1322} // extern "C"
1323
1324} // __cxxabiv1
lib/libcxxabi/src/cxa_thread_atexit.cpp created+145
...@@ -0,0 +1,145 @@
1//===----------------------- cxa_thread_atexit.cpp ------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "abort_message.h"
10#include "cxxabi.h"
11#include <__threading_support>
12#ifndef _LIBCXXABI_HAS_NO_THREADS
13#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
14#pragma comment(lib, "pthread")
15#endif
16#endif
17
18#include <stdlib.h>
19
20namespace __cxxabiv1 {
21
22 using Dtor = void(*)(void*);
23
24 extern "C"
25#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
26 // A weak symbol is used to detect this function's presence in the C library
27 // at runtime, even if libc++ is built against an older libc
28 _LIBCXXABI_WEAK
29#endif
30 int __cxa_thread_atexit_impl(Dtor, void*, void*);
31
32#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL
33
34namespace {
35 // This implementation is used if the C library does not provide
36 // __cxa_thread_atexit_impl() for us. It has a number of limitations that are
37 // difficult to impossible to address without ..._impl():
38 //
39 // - dso_symbol is ignored. This means that a shared library may be unloaded
40 // (via dlclose()) before its thread_local destructors have run.
41 //
42 // - thread_local destructors for the main thread are run by the destructor of
43 // a static object. This is later than expected; they should run before the
44 // destructors of any objects with static storage duration.
45 //
46 // - thread_local destructors on non-main threads run on the first iteration
47 // through the __libccpp_tls_key destructors.
48 // std::notify_all_at_thread_exit() and similar functions must be careful to
49 // wait until the second iteration to provide their intended ordering
50 // guarantees.
51 //
52 // Another limitation, though one shared with ..._impl(), is that any
53 // thread_locals that are first initialized after non-thread_local global
54 // destructors begin to run will not be destroyed. [basic.start.term] states
55 // that all thread_local destructors are sequenced before the destruction of
56 // objects with static storage duration, resulting in a contradiction if a
57 // thread_local is constructed after that point. Thus we consider such
58 // programs ill-formed, and don't bother to run those destructors. (If the
59 // program terminates abnormally after such a thread_local is constructed,
60 // the destructor is not expected to run and thus there is no contradiction.
61 // So construction still has to work.)
62
63 struct DtorList {
64 Dtor dtor;
65 void* obj;
66 DtorList* next;
67 };
68
69 // The linked list of thread-local destructors to run
70 __thread DtorList* dtors = nullptr;
71 // True if the destructors are currently scheduled to run on this thread
72 __thread bool dtors_alive = false;
73 // Used to trigger destructors on thread exit; value is ignored
74 std::__libcpp_tls_key dtors_key;
75
76 void run_dtors(void*) {
77 while (auto head = dtors) {
78 dtors = head->next;
79 head->dtor(head->obj);
80 ::free(head);
81 }
82
83 dtors_alive = false;
84 }
85
86 struct DtorsManager {
87 DtorsManager() {
88 // There is intentionally no matching std::__libcpp_tls_delete call, as
89 // __cxa_thread_atexit() may be called arbitrarily late (for example, from
90 // global destructors or atexit() handlers).
91 if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) {
92 abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()");
93 }
94 }
95
96 ~DtorsManager() {
97 // std::__libcpp_tls_key destructors do not run on threads that call exit()
98 // (including when the main thread returns from main()), so we explicitly
99 // call the destructor here. This runs at exit time (potentially earlier
100 // if libc++abi is dlclose()'d). Any thread_locals initialized after this
101 // point will not be destroyed.
102 run_dtors(nullptr);
103 }
104 };
105} // namespace
106
107#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
108
109extern "C" {
110
111 _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
112#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL
113 return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
114#else
115 if (__cxa_thread_atexit_impl) {
116 return __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
117 } else {
118 // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for
119 // one-time initialization and __cxa_atexit() for destruction)
120 static DtorsManager manager;
121
122 if (!dtors_alive) {
123 if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) {
124 return -1;
125 }
126 dtors_alive = true;
127 }
128
129 auto head = static_cast<DtorList*>(::malloc(sizeof(DtorList)));
130 if (!head) {
131 return -1;
132 }
133
134 head->dtor = dtor;
135 head->obj = obj;
136 head->next = dtors;
137 dtors = head;
138
139 return 0;
140 }
141#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
142 }
143
144} // extern "C"
145} // namespace __cxxabiv1
lib/libcxxabi/src/cxa_unexpected.cpp created+22
...@@ -0,0 +1,22 @@
1//===------------------------- cxa_unexpected.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <exception>
10#include "cxxabi.h"
11#include "cxa_exception.h"
12
13namespace __cxxabiv1
14{
15
16extern "C"
17{
18
19}
20
21} // namespace __cxxabiv1
22
lib/libcxxabi/src/cxa_vector.cpp created+421
...@@ -0,0 +1,421 @@
1//===-------------------------- cxa_vector.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// This file implements the "Array Construction and Destruction APIs"
9// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
10//
11//===----------------------------------------------------------------------===//
12
13#include "cxxabi.h"
14#include "__cxxabi_config.h"
15
16#include <exception> // for std::terminate
17#include <new> // for std::bad_array_new_length
18
19#include "abort_message.h"
20
21#ifndef __has_builtin
22#define __has_builtin(x) 0
23#endif
24
25namespace __cxxabiv1 {
26
27#if 0
28#pragma mark --Helper routines and classes --
29#endif
30
31namespace {
32 inline static size_t __get_element_count ( void *p ) {
33 return static_cast <size_t *> (p)[-1];
34 }
35
36 inline static void __set_element_count ( void *p, size_t element_count ) {
37 static_cast <size_t *> (p)[-1] = element_count;
38 }
39
40
41// A pair of classes to simplify exception handling and control flow.
42// They get passed a block of memory in the constructor, and unless the
43// 'release' method is called, they deallocate the memory in the destructor.
44// Preferred usage is to allocate some memory, attach it to one of these objects,
45// and then, when all the operations to set up the memory block have succeeded,
46// call 'release'. If any of the setup operations fail, or an exception is
47// thrown, then the block is automatically deallocated.
48//
49// The only difference between these two classes is the signature for the
50// deallocation function (to match new2/new3 and delete2/delete3.
51 class st_heap_block2 {
52 public:
53 typedef void (*dealloc_f)(void *);
54
55 st_heap_block2 ( dealloc_f dealloc, void *ptr )
56 : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
57 ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
58 void release () { enabled_ = false; }
59
60 private:
61 dealloc_f dealloc_;
62 void *ptr_;
63 bool enabled_;
64 };
65
66 class st_heap_block3 {
67 public:
68 typedef void (*dealloc_f)(void *, size_t);
69
70 st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
71 : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
72 ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
73 void release () { enabled_ = false; }
74
75 private:
76 dealloc_f dealloc_;
77 void *ptr_;
78 size_t size_;
79 bool enabled_;
80 };
81
82 class st_cxa_cleanup {
83 public:
84 typedef void (*destruct_f)(void *);
85
86 st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
87 : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
88 destructor_ ( destructor ), enabled_ ( true ) {}
89 ~st_cxa_cleanup () {
90 if ( enabled_ )
91 __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
92 }
93
94 void release () { enabled_ = false; }
95
96 private:
97 void *ptr_;
98 size_t &idx_;
99 size_t element_size_;
100 destruct_f destructor_;
101 bool enabled_;
102 };
103
104 class st_terminate {
105 public:
106 st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
107 ~st_terminate () { if ( enabled_ ) std::terminate (); }
108 void release () { enabled_ = false; }
109 private:
110 bool enabled_ ;
111 };
112}
113
114#if 0
115#pragma mark --Externally visible routines--
116#endif
117
118namespace {
119_LIBCXXABI_NORETURN
120void throw_bad_array_new_length() {
121#ifndef _LIBCXXABI_NO_EXCEPTIONS
122 throw std::bad_array_new_length();
123#else
124 abort_message("__cxa_vec_new failed to allocate memory");
125#endif
126}
127
128bool mul_overflow(size_t x, size_t y, size_t *res) {
129#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
130 || defined(_LIBCXXABI_COMPILER_GCC)
131 return __builtin_mul_overflow(x, y, res);
132#else
133 *res = x * y;
134 return x && ((*res / x) != y);
135#endif
136}
137
138bool add_overflow(size_t x, size_t y, size_t *res) {
139#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
140 || defined(_LIBCXXABI_COMPILER_GCC)
141 return __builtin_add_overflow(x, y, res);
142#else
143 *res = x + y;
144 return *res < y;
145#endif
146}
147
148size_t calculate_allocation_size_or_throw(size_t element_count,
149 size_t element_size,
150 size_t padding_size) {
151 size_t element_heap_size;
152 if (mul_overflow(element_count, element_size, &element_heap_size))
153 throw_bad_array_new_length();
154
155 size_t allocation_size;
156 if (add_overflow(element_heap_size, padding_size, &allocation_size))
157 throw_bad_array_new_length();
158
159 return allocation_size;
160}
161
162} // namespace
163
164extern "C" {
165
166// Equivalent to
167//
168// __cxa_vec_new2(element_count, element_size, padding_size, constructor,
169// destructor, &::operator new[], &::operator delete[])
170_LIBCXXABI_FUNC_VIS void *
171__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size,
172 void (*constructor)(void *), void (*destructor)(void *)) {
173 return __cxa_vec_new2 ( element_count, element_size, padding_size,
174 constructor, destructor, &::operator new [], &::operator delete [] );
175}
176
177
178// Given the number and size of elements for an array and the non-negative
179// size of prefix padding for a cookie, allocate space (using alloc) for
180// the array preceded by the specified padding, initialize the cookie if
181// the padding is non-zero, and call the given constructor on each element.
182// Return the address of the array proper, after the padding.
183//
184// If alloc throws an exception, rethrow the exception. If alloc returns
185// NULL, return NULL. If the constructor throws an exception, call
186// destructor for any already constructed elements, and rethrow the
187// exception. If the destructor throws an exception, call std::terminate.
188//
189// The constructor may be NULL, in which case it must not be called. If the
190// padding_size is zero, the destructor may be NULL; in that case it must
191// not be called.
192//
193// Neither alloc nor dealloc may be NULL.
194_LIBCXXABI_FUNC_VIS void *
195__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size,
196 void (*constructor)(void *), void (*destructor)(void *),
197 void *(*alloc)(size_t), void (*dealloc)(void *)) {
198 const size_t heap_size = calculate_allocation_size_or_throw(
199 element_count, element_size, padding_size);
200 char* const heap_block = static_cast<char*>(alloc(heap_size));
201 char* vec_base = heap_block;
202
203 if (NULL != vec_base) {
204 st_heap_block2 heap(dealloc, heap_block);
205
206 // put the padding before the array elements
207 if ( 0 != padding_size ) {
208 vec_base += padding_size;
209 __set_element_count ( vec_base, element_count );
210 }
211
212 // Construct the elements
213 __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
214 heap.release (); // We're good!
215 }
216
217 return vec_base;
218}
219
220
221// Same as __cxa_vec_new2 except that the deallocation function takes both
222// the object address and its size.
223_LIBCXXABI_FUNC_VIS void *
224__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size,
225 void (*constructor)(void *), void (*destructor)(void *),
226 void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) {
227 const size_t heap_size = calculate_allocation_size_or_throw(
228 element_count, element_size, padding_size);
229 char* const heap_block = static_cast<char*>(alloc(heap_size));
230 char* vec_base = heap_block;
231
232 if (NULL != vec_base) {
233 st_heap_block3 heap(dealloc, heap_block, heap_size);
234
235 // put the padding before the array elements
236 if ( 0 != padding_size ) {
237 vec_base += padding_size;
238 __set_element_count ( vec_base, element_count );
239 }
240
241 // Construct the elements
242 __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
243 heap.release (); // We're good!
244 }
245
246 return vec_base;
247}
248
249
250// Given the (data) addresses of a destination and a source array, an
251// element count and an element size, call the given copy constructor to
252// copy each element from the source array to the destination array. The
253// copy constructor's arguments are the destination address and source
254// address, respectively. If an exception occurs, call the given destructor
255// (if non-NULL) on each copied element and rethrow. If the destructor
256// throws an exception, call terminate(). The constructor and or destructor
257// pointers may be NULL. If either is NULL, no action is taken when it
258// would have been called.
259
260_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array,
261 size_t element_count,
262 size_t element_size,
263 void (*constructor)(void *, void *),
264 void (*destructor)(void *)) {
265 if ( NULL != constructor ) {
266 size_t idx = 0;
267 char *src_ptr = static_cast<char *>(src_array);
268 char *dest_ptr = static_cast<char *>(dest_array);
269 st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
270
271 for ( idx = 0; idx < element_count;
272 ++idx, src_ptr += element_size, dest_ptr += element_size )
273 constructor ( dest_ptr, src_ptr );
274 cleanup.release (); // We're good!
275 }
276}
277
278
279// Given the (data) address of an array, not including any cookie padding,
280// and the number and size of its elements, call the given constructor on
281// each element. If the constructor throws an exception, call the given
282// destructor for any already-constructed elements, and rethrow the
283// exception. If the destructor throws an exception, call terminate(). The
284// constructor and/or destructor pointers may be NULL. If either is NULL,
285// no action is taken when it would have been called.
286_LIBCXXABI_FUNC_VIS void
287__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size,
288 void (*constructor)(void *), void (*destructor)(void *)) {
289 if ( NULL != constructor ) {
290 size_t idx;
291 char *ptr = static_cast <char *> ( array_address );
292 st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
293
294 // Construct the elements
295 for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
296 constructor ( ptr );
297 cleanup.release (); // We're good!
298 }
299}
300
301// Given the (data) address of an array, the number of elements, and the
302// size of its elements, call the given destructor on each element. If the
303// destructor throws an exception, rethrow after destroying the remaining
304// elements if possible. If the destructor throws a second exception, call
305// terminate(). The destructor pointer may be NULL, in which case this
306// routine does nothing.
307_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address,
308 size_t element_count,
309 size_t element_size,
310 void (*destructor)(void *)) {
311 if ( NULL != destructor ) {
312 char *ptr = static_cast <char *> (array_address);
313 size_t idx = element_count;
314 st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
315 {
316 st_terminate exception_guard (__cxa_uncaught_exception ());
317 ptr += element_count * element_size; // one past the last element
318
319 while ( idx-- > 0 ) {
320 ptr -= element_size;
321 destructor ( ptr );
322 }
323 exception_guard.release (); // We're good !
324 }
325 cleanup.release (); // We're still good!
326 }
327}
328
329// Given the (data) address of an array, the number of elements, and the
330// size of its elements, call the given destructor on each element. If the
331// destructor throws an exception, call terminate(). The destructor pointer
332// may be NULL, in which case this routine does nothing.
333_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address,
334 size_t element_count,
335 size_t element_size,
336 void (*destructor)(void *)) {
337 if ( NULL != destructor ) {
338 char *ptr = static_cast <char *> (array_address);
339 size_t idx = element_count;
340 st_terminate exception_guard;
341
342 ptr += element_count * element_size; // one past the last element
343 while ( idx-- > 0 ) {
344 ptr -= element_size;
345 destructor ( ptr );
346 }
347 exception_guard.release (); // We're done!
348 }
349}
350
351
352// If the array_address is NULL, return immediately. Otherwise, given the
353// (data) address of an array, the non-negative size of prefix padding for
354// the cookie, and the size of its elements, call the given destructor on
355// each element, using the cookie to determine the number of elements, and
356// then delete the space by calling ::operator delete[](void *). If the
357// destructor throws an exception, rethrow after (a) destroying the
358// remaining elements, and (b) deallocating the storage. If the destructor
359// throws a second exception, call terminate(). If padding_size is 0, the
360// destructor pointer must be NULL. If the destructor pointer is NULL, no
361// destructor call is to be made.
362//
363// The intent of this function is to permit an implementation to call this
364// function when confronted with an expression of the form delete[] p in
365// the source code, provided that the default deallocation function can be
366// used. Therefore, the semantics of this function are consistent with
367// those required by the standard. The requirement that the deallocation
368// function be called even if the destructor throws an exception derives
369// from the resolution to DR 353 to the C++ standard, which was adopted in
370// April, 2003.
371_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address,
372 size_t element_size,
373 size_t padding_size,
374 void (*destructor)(void *)) {
375 __cxa_vec_delete2 ( array_address, element_size, padding_size,
376 destructor, &::operator delete [] );
377}
378
379// Same as __cxa_vec_delete, except that the given function is used for
380// deallocation instead of the default delete function. If dealloc throws
381// an exception, the result is undefined. The dealloc pointer may not be
382// NULL.
383_LIBCXXABI_FUNC_VIS void
384__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size,
385 void (*destructor)(void *), void (*dealloc)(void *)) {
386 if ( NULL != array_address ) {
387 char *vec_base = static_cast <char *> (array_address);
388 char *heap_block = vec_base - padding_size;
389 st_heap_block2 heap ( dealloc, heap_block );
390
391 if ( 0 != padding_size && NULL != destructor ) // call the destructors
392 __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
393 element_size, destructor );
394 }
395}
396
397
398// Same as __cxa_vec_delete, except that the given function is used for
399// deallocation instead of the default delete function. The deallocation
400// function takes both the object address and its size. If dealloc throws
401// an exception, the result is undefined. The dealloc pointer may not be
402// NULL.
403_LIBCXXABI_FUNC_VIS void
404__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
405 void (*destructor)(void *), void (*dealloc)(void *, size_t)) {
406 if ( NULL != array_address ) {
407 char *vec_base = static_cast <char *> (array_address);
408 char *heap_block = vec_base - padding_size;
409 const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
410 const size_t heap_block_size = element_size * element_count + padding_size;
411 st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
412
413 if ( 0 != padding_size && NULL != destructor ) // call the destructors
414 __cxa_vec_dtor ( array_address, element_count, element_size, destructor );
415 }
416}
417
418
419} // extern "C"
420
421} // abi
lib/libcxxabi/src/cxa_virtual.cpp created+24
...@@ -0,0 +1,24 @@
1//===-------------------------- cxa_virtual.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "cxxabi.h"
10#include "abort_message.h"
11
12namespace __cxxabiv1 {
13extern "C" {
14_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
15void __cxa_pure_virtual(void) {
16 abort_message("Pure virtual function called!");
17}
18
19_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN
20void __cxa_deleted_virtual(void) {
21 abort_message("Deleted virtual function called!");
22}
23} // extern "C"
24} // abi
lib/libcxxabi/src/demangle/.clang-format created+2
...@@ -0,0 +1,2 @@
1BasedOnStyle: LLVM
2
lib/libcxxabi/src/demangle/DemangleConfig.h created+97
...@@ -0,0 +1,97 @@
1//===--- DemangleConfig.h --------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// This file is contains a subset of macros copied from
8// llvm/include/llvm/Demangle/DemangleConfig.h
9//===----------------------------------------------------------------------===//
10
11#ifndef LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
12#define LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
13
14#include <ciso646>
15
16#ifdef _MSC_VER
17// snprintf is implemented in VS 2015
18#if _MSC_VER < 1900
19#define snprintf _snprintf_s
20#endif
21#endif
22
23#ifndef __has_feature
24#define __has_feature(x) 0
25#endif
26
27#ifndef __has_cpp_attribute
28#define __has_cpp_attribute(x) 0
29#endif
30
31#ifndef __has_attribute
32#define __has_attribute(x) 0
33#endif
34
35#ifndef __has_builtin
36#define __has_builtin(x) 0
37#endif
38
39#ifndef DEMANGLE_GNUC_PREREQ
40#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
41#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
42 ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
43 ((maj) << 20) + ((min) << 10) + (patch))
44#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
45#define DEMANGLE_GNUC_PREREQ(maj, min, patch) \
46 ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
47#else
48#define DEMANGLE_GNUC_PREREQ(maj, min, patch) 0
49#endif
50#endif
51
52#if __has_attribute(used) || DEMANGLE_GNUC_PREREQ(3, 1, 0)
53#define DEMANGLE_ATTRIBUTE_USED __attribute__((__used__))
54#else
55#define DEMANGLE_ATTRIBUTE_USED
56#endif
57
58#if __has_builtin(__builtin_unreachable) || DEMANGLE_GNUC_PREREQ(4, 5, 0)
59#define DEMANGLE_UNREACHABLE __builtin_unreachable()
60#elif defined(_MSC_VER)
61#define DEMANGLE_UNREACHABLE __assume(false)
62#else
63#define DEMANGLE_UNREACHABLE
64#endif
65
66#if __has_attribute(noinline) || DEMANGLE_GNUC_PREREQ(3, 4, 0)
67#define DEMANGLE_ATTRIBUTE_NOINLINE __attribute__((noinline))
68#elif defined(_MSC_VER)
69#define DEMANGLE_ATTRIBUTE_NOINLINE __declspec(noinline)
70#else
71#define DEMANGLE_ATTRIBUTE_NOINLINE
72#endif
73
74#if !defined(NDEBUG)
75#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE DEMANGLE_ATTRIBUTE_USED
76#else
77#define DEMANGLE_DUMP_METHOD DEMANGLE_ATTRIBUTE_NOINLINE
78#endif
79
80#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
81#define DEMANGLE_FALLTHROUGH [[fallthrough]]
82#elif __has_cpp_attribute(gnu::fallthrough)
83#define DEMANGLE_FALLTHROUGH [[gnu::fallthrough]]
84#elif !__cplusplus
85// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
86// error when __has_cpp_attribute is given a scoped attribute in C mode.
87#define DEMANGLE_FALLTHROUGH
88#elif __has_cpp_attribute(clang::fallthrough)
89#define DEMANGLE_FALLTHROUGH [[clang::fallthrough]]
90#else
91#define DEMANGLE_FALLTHROUGH
92#endif
93
94#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
95#define DEMANGLE_NAMESPACE_END } }
96
97#endif // LIBCXXABI_DEMANGLE_DEMANGLE_CONFIG_H
lib/libcxxabi/src/demangle/ItaniumDemangle.h created+5545
...@@ -0,0 +1,5545 @@
1//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Generic itanium demangler library. This file has two byte-per-byte identical
10// copies in the source tree, one in libcxxabi, and the other in llvm.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef DEMANGLE_ITANIUMDEMANGLE_H
15#define DEMANGLE_ITANIUMDEMANGLE_H
16
17// FIXME: (possibly) incomplete list of features that clang mangles that this
18// file does not yet support:
19// - C++ modules TS
20
21#include "DemangleConfig.h"
22#include "StringView.h"
23#include "Utility.h"
24#include <cassert>
25#include <cctype>
26#include <cstdio>
27#include <cstdlib>
28#include <cstring>
29#include <numeric>
30#include <utility>
31
32#define FOR_EACH_NODE_KIND(X) \
33 X(NodeArrayNode) \
34 X(DotSuffix) \
35 X(VendorExtQualType) \
36 X(QualType) \
37 X(ConversionOperatorType) \
38 X(PostfixQualifiedType) \
39 X(ElaboratedTypeSpefType) \
40 X(NameType) \
41 X(AbiTagAttr) \
42 X(EnableIfAttr) \
43 X(ObjCProtoName) \
44 X(PointerType) \
45 X(ReferenceType) \
46 X(PointerToMemberType) \
47 X(ArrayType) \
48 X(FunctionType) \
49 X(NoexceptSpec) \
50 X(DynamicExceptionSpec) \
51 X(FunctionEncoding) \
52 X(LiteralOperator) \
53 X(SpecialName) \
54 X(CtorVtableSpecialName) \
55 X(QualifiedName) \
56 X(NestedName) \
57 X(LocalName) \
58 X(VectorType) \
59 X(PixelVectorType) \
60 X(SyntheticTemplateParamName) \
61 X(TypeTemplateParamDecl) \
62 X(NonTypeTemplateParamDecl) \
63 X(TemplateTemplateParamDecl) \
64 X(TemplateParamPackDecl) \
65 X(ParameterPack) \
66 X(TemplateArgumentPack) \
67 X(ParameterPackExpansion) \
68 X(TemplateArgs) \
69 X(ForwardTemplateReference) \
70 X(NameWithTemplateArgs) \
71 X(GlobalQualifiedName) \
72 X(StdQualifiedName) \
73 X(ExpandedSpecialSubstitution) \
74 X(SpecialSubstitution) \
75 X(CtorDtorName) \
76 X(DtorName) \
77 X(UnnamedTypeName) \
78 X(ClosureTypeName) \
79 X(StructuredBindingName) \
80 X(BinaryExpr) \
81 X(ArraySubscriptExpr) \
82 X(PostfixExpr) \
83 X(ConditionalExpr) \
84 X(MemberExpr) \
85 X(EnclosingExpr) \
86 X(CastExpr) \
87 X(SizeofParamPackExpr) \
88 X(CallExpr) \
89 X(NewExpr) \
90 X(DeleteExpr) \
91 X(PrefixExpr) \
92 X(FunctionParam) \
93 X(ConversionExpr) \
94 X(InitListExpr) \
95 X(FoldExpr) \
96 X(ThrowExpr) \
97 X(UUIDOfExpr) \
98 X(BoolExpr) \
99 X(StringLiteral) \
100 X(LambdaExpr) \
101 X(IntegerCastExpr) \
102 X(IntegerLiteral) \
103 X(FloatLiteral) \
104 X(DoubleLiteral) \
105 X(LongDoubleLiteral) \
106 X(BracedExpr) \
107 X(BracedRangeExpr)
108
109DEMANGLE_NAMESPACE_BEGIN
110
111// Base class of all AST nodes. The AST is built by the parser, then is
112// traversed by the printLeft/Right functions to produce a demangled string.
113class Node {
114public:
115 enum Kind : unsigned char {
116#define ENUMERATOR(NodeKind) K ## NodeKind,
117 FOR_EACH_NODE_KIND(ENUMERATOR)
118#undef ENUMERATOR
119 };
120
121 /// Three-way bool to track a cached value. Unknown is possible if this node
122 /// has an unexpanded parameter pack below it that may affect this cache.
123 enum class Cache : unsigned char { Yes, No, Unknown, };
124
125private:
126 Kind K;
127
128 // FIXME: Make these protected.
129public:
130 /// Tracks if this node has a component on its right side, in which case we
131 /// need to call printRight.
132 Cache RHSComponentCache;
133
134 /// Track if this node is a (possibly qualified) array type. This can affect
135 /// how we format the output string.
136 Cache ArrayCache;
137
138 /// Track if this node is a (possibly qualified) function type. This can
139 /// affect how we format the output string.
140 Cache FunctionCache;
141
142public:
143 Node(Kind K_, Cache RHSComponentCache_ = Cache::No,
144 Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)
145 : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
146 FunctionCache(FunctionCache_) {}
147
148 /// Visit the most-derived object corresponding to this object.
149 template<typename Fn> void visit(Fn F) const;
150
151 // The following function is provided by all derived classes:
152 //
153 // Call F with arguments that, when passed to the constructor of this node,
154 // would construct an equivalent node.
155 //template<typename Fn> void match(Fn F) const;
156
157 bool hasRHSComponent(OutputStream &S) const {
158 if (RHSComponentCache != Cache::Unknown)
159 return RHSComponentCache == Cache::Yes;
160 return hasRHSComponentSlow(S);
161 }
162
163 bool hasArray(OutputStream &S) const {
164 if (ArrayCache != Cache::Unknown)
165 return ArrayCache == Cache::Yes;
166 return hasArraySlow(S);
167 }
168
169 bool hasFunction(OutputStream &S) const {
170 if (FunctionCache != Cache::Unknown)
171 return FunctionCache == Cache::Yes;
172 return hasFunctionSlow(S);
173 }
174
175 Kind getKind() const { return K; }
176
177 virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
178 virtual bool hasArraySlow(OutputStream &) const { return false; }
179 virtual bool hasFunctionSlow(OutputStream &) const { return false; }
180
181 // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
182 // get at a node that actually represents some concrete syntax.
183 virtual const Node *getSyntaxNode(OutputStream &) const {
184 return this;
185 }
186
187 void print(OutputStream &S) const {
188 printLeft(S);
189 if (RHSComponentCache != Cache::No)
190 printRight(S);
191 }
192
193 // Print the "left" side of this Node into OutputStream.
194 virtual void printLeft(OutputStream &) const = 0;
195
196 // Print the "right". This distinction is necessary to represent C++ types
197 // that appear on the RHS of their subtype, such as arrays or functions.
198 // Since most types don't have such a component, provide a default
199 // implementation.
200 virtual void printRight(OutputStream &) const {}
201
202 virtual StringView getBaseName() const { return StringView(); }
203
204 // Silence compiler warnings, this dtor will never be called.
205 virtual ~Node() = default;
206
207#ifndef NDEBUG
208 DEMANGLE_DUMP_METHOD void dump() const;
209#endif
210};
211
212class NodeArray {
213 Node **Elements;
214 size_t NumElements;
215
216public:
217 NodeArray() : Elements(nullptr), NumElements(0) {}
218 NodeArray(Node **Elements_, size_t NumElements_)
219 : Elements(Elements_), NumElements(NumElements_) {}
220
221 bool empty() const { return NumElements == 0; }
222 size_t size() const { return NumElements; }
223
224 Node **begin() const { return Elements; }
225 Node **end() const { return Elements + NumElements; }
226
227 Node *operator[](size_t Idx) const { return Elements[Idx]; }
228
229 void printWithComma(OutputStream &S) const {
230 bool FirstElement = true;
231 for (size_t Idx = 0; Idx != NumElements; ++Idx) {
232 size_t BeforeComma = S.getCurrentPosition();
233 if (!FirstElement)
234 S += ", ";
235 size_t AfterComma = S.getCurrentPosition();
236 Elements[Idx]->print(S);
237
238 // Elements[Idx] is an empty parameter pack expansion, we should erase the
239 // comma we just printed.
240 if (AfterComma == S.getCurrentPosition()) {
241 S.setCurrentPosition(BeforeComma);
242 continue;
243 }
244
245 FirstElement = false;
246 }
247 }
248};
249
250struct NodeArrayNode : Node {
251 NodeArray Array;
252 NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {}
253
254 template<typename Fn> void match(Fn F) const { F(Array); }
255
256 void printLeft(OutputStream &S) const override {
257 Array.printWithComma(S);
258 }
259};
260
261class DotSuffix final : public Node {
262 const Node *Prefix;
263 const StringView Suffix;
264
265public:
266 DotSuffix(const Node *Prefix_, StringView Suffix_)
267 : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {}
268
269 template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }
270
271 void printLeft(OutputStream &s) const override {
272 Prefix->print(s);
273 s += " (";
274 s += Suffix;
275 s += ")";
276 }
277};
278
279class VendorExtQualType final : public Node {
280 const Node *Ty;
281 StringView Ext;
282
283public:
284 VendorExtQualType(const Node *Ty_, StringView Ext_)
285 : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}
286
287 template<typename Fn> void match(Fn F) const { F(Ty, Ext); }
288
289 void printLeft(OutputStream &S) const override {
290 Ty->print(S);
291 S += " ";
292 S += Ext;
293 }
294};
295
296enum FunctionRefQual : unsigned char {
297 FrefQualNone,
298 FrefQualLValue,
299 FrefQualRValue,
300};
301
302enum Qualifiers {
303 QualNone = 0,
304 QualConst = 0x1,
305 QualVolatile = 0x2,
306 QualRestrict = 0x4,
307};
308
309inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) {
310 return Q1 = static_cast<Qualifiers>(Q1 | Q2);
311}
312
313class QualType final : public Node {
314protected:
315 const Qualifiers Quals;
316 const Node *Child;
317
318 void printQuals(OutputStream &S) const {
319 if (Quals & QualConst)
320 S += " const";
321 if (Quals & QualVolatile)
322 S += " volatile";
323 if (Quals & QualRestrict)
324 S += " restrict";
325 }
326
327public:
328 QualType(const Node *Child_, Qualifiers Quals_)
329 : Node(KQualType, Child_->RHSComponentCache,
330 Child_->ArrayCache, Child_->FunctionCache),
331 Quals(Quals_), Child(Child_) {}
332
333 template<typename Fn> void match(Fn F) const { F(Child, Quals); }
334
335 bool hasRHSComponentSlow(OutputStream &S) const override {
336 return Child->hasRHSComponent(S);
337 }
338 bool hasArraySlow(OutputStream &S) const override {
339 return Child->hasArray(S);
340 }
341 bool hasFunctionSlow(OutputStream &S) const override {
342 return Child->hasFunction(S);
343 }
344
345 void printLeft(OutputStream &S) const override {
346 Child->printLeft(S);
347 printQuals(S);
348 }
349
350 void printRight(OutputStream &S) const override { Child->printRight(S); }
351};
352
353class ConversionOperatorType final : public Node {
354 const Node *Ty;
355
356public:
357 ConversionOperatorType(const Node *Ty_)
358 : Node(KConversionOperatorType), Ty(Ty_) {}
359
360 template<typename Fn> void match(Fn F) const { F(Ty); }
361
362 void printLeft(OutputStream &S) const override {
363 S += "operator ";
364 Ty->print(S);
365 }
366};
367
368class PostfixQualifiedType final : public Node {
369 const Node *Ty;
370 const StringView Postfix;
371
372public:
373 PostfixQualifiedType(Node *Ty_, StringView Postfix_)
374 : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
375
376 template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
377
378 void printLeft(OutputStream &s) const override {
379 Ty->printLeft(s);
380 s += Postfix;
381 }
382};
383
384class NameType final : public Node {
385 const StringView Name;
386
387public:
388 NameType(StringView Name_) : Node(KNameType), Name(Name_) {}
389
390 template<typename Fn> void match(Fn F) const { F(Name); }
391
392 StringView getName() const { return Name; }
393 StringView getBaseName() const override { return Name; }
394
395 void printLeft(OutputStream &s) const override { s += Name; }
396};
397
398class ElaboratedTypeSpefType : public Node {
399 StringView Kind;
400 Node *Child;
401public:
402 ElaboratedTypeSpefType(StringView Kind_, Node *Child_)
403 : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}
404
405 template<typename Fn> void match(Fn F) const { F(Kind, Child); }
406
407 void printLeft(OutputStream &S) const override {
408 S += Kind;
409 S += ' ';
410 Child->print(S);
411 }
412};
413
414struct AbiTagAttr : Node {
415 Node *Base;
416 StringView Tag;
417
418 AbiTagAttr(Node* Base_, StringView Tag_)
419 : Node(KAbiTagAttr, Base_->RHSComponentCache,
420 Base_->ArrayCache, Base_->FunctionCache),
421 Base(Base_), Tag(Tag_) {}
422
423 template<typename Fn> void match(Fn F) const { F(Base, Tag); }
424
425 void printLeft(OutputStream &S) const override {
426 Base->printLeft(S);
427 S += "[abi:";
428 S += Tag;
429 S += "]";
430 }
431};
432
433class EnableIfAttr : public Node {
434 NodeArray Conditions;
435public:
436 EnableIfAttr(NodeArray Conditions_)
437 : Node(KEnableIfAttr), Conditions(Conditions_) {}
438
439 template<typename Fn> void match(Fn F) const { F(Conditions); }
440
441 void printLeft(OutputStream &S) const override {
442 S += " [enable_if:";
443 Conditions.printWithComma(S);
444 S += ']';
445 }
446};
447
448class ObjCProtoName : public Node {
449 const Node *Ty;
450 StringView Protocol;
451
452 friend class PointerType;
453
454public:
455 ObjCProtoName(const Node *Ty_, StringView Protocol_)
456 : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
457
458 template<typename Fn> void match(Fn F) const { F(Ty, Protocol); }
459
460 bool isObjCObject() const {
461 return Ty->getKind() == KNameType &&
462 static_cast<const NameType *>(Ty)->getName() == "objc_object";
463 }
464
465 void printLeft(OutputStream &S) const override {
466 Ty->print(S);
467 S += "<";
468 S += Protocol;
469 S += ">";
470 }
471};
472
473class PointerType final : public Node {
474 const Node *Pointee;
475
476public:
477 PointerType(const Node *Pointee_)
478 : Node(KPointerType, Pointee_->RHSComponentCache),
479 Pointee(Pointee_) {}
480
481 template<typename Fn> void match(Fn F) const { F(Pointee); }
482
483 bool hasRHSComponentSlow(OutputStream &S) const override {
484 return Pointee->hasRHSComponent(S);
485 }
486
487 void printLeft(OutputStream &s) const override {
488 // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
489 if (Pointee->getKind() != KObjCProtoName ||
490 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
491 Pointee->printLeft(s);
492 if (Pointee->hasArray(s))
493 s += " ";
494 if (Pointee->hasArray(s) || Pointee->hasFunction(s))
495 s += "(";
496 s += "*";
497 } else {
498 const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
499 s += "id<";
500 s += objcProto->Protocol;
501 s += ">";
502 }
503 }
504
505 void printRight(OutputStream &s) const override {
506 if (Pointee->getKind() != KObjCProtoName ||
507 !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
508 if (Pointee->hasArray(s) || Pointee->hasFunction(s))
509 s += ")";
510 Pointee->printRight(s);
511 }
512 }
513};
514
515enum class ReferenceKind {
516 LValue,
517 RValue,
518};
519
520// Represents either a LValue or an RValue reference type.
521class ReferenceType : public Node {
522 const Node *Pointee;
523 ReferenceKind RK;
524
525 mutable bool Printing = false;
526
527 // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
528 // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
529 // other combination collapses to a lvalue ref.
530 std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const {
531 auto SoFar = std::make_pair(RK, Pointee);
532 for (;;) {
533 const Node *SN = SoFar.second->getSyntaxNode(S);
534 if (SN->getKind() != KReferenceType)
535 break;
536 auto *RT = static_cast<const ReferenceType *>(SN);
537 SoFar.second = RT->Pointee;
538 SoFar.first = std::min(SoFar.first, RT->RK);
539 }
540 return SoFar;
541 }
542
543public:
544 ReferenceType(const Node *Pointee_, ReferenceKind RK_)
545 : Node(KReferenceType, Pointee_->RHSComponentCache),
546 Pointee(Pointee_), RK(RK_) {}
547
548 template<typename Fn> void match(Fn F) const { F(Pointee, RK); }
549
550 bool hasRHSComponentSlow(OutputStream &S) const override {
551 return Pointee->hasRHSComponent(S);
552 }
553
554 void printLeft(OutputStream &s) const override {
555 if (Printing)
556 return;
557 SwapAndRestore<bool> SavePrinting(Printing, true);
558 std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
559 Collapsed.second->printLeft(s);
560 if (Collapsed.second->hasArray(s))
561 s += " ";
562 if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
563 s += "(";
564
565 s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
566 }
567 void printRight(OutputStream &s) const override {
568 if (Printing)
569 return;
570 SwapAndRestore<bool> SavePrinting(Printing, true);
571 std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
572 if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
573 s += ")";
574 Collapsed.second->printRight(s);
575 }
576};
577
578class PointerToMemberType final : public Node {
579 const Node *ClassType;
580 const Node *MemberType;
581
582public:
583 PointerToMemberType(const Node *ClassType_, const Node *MemberType_)
584 : Node(KPointerToMemberType, MemberType_->RHSComponentCache),
585 ClassType(ClassType_), MemberType(MemberType_) {}
586
587 template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }
588
589 bool hasRHSComponentSlow(OutputStream &S) const override {
590 return MemberType->hasRHSComponent(S);
591 }
592
593 void printLeft(OutputStream &s) const override {
594 MemberType->printLeft(s);
595 if (MemberType->hasArray(s) || MemberType->hasFunction(s))
596 s += "(";
597 else
598 s += " ";
599 ClassType->print(s);
600 s += "::*";
601 }
602
603 void printRight(OutputStream &s) const override {
604 if (MemberType->hasArray(s) || MemberType->hasFunction(s))
605 s += ")";
606 MemberType->printRight(s);
607 }
608};
609
610class ArrayType final : public Node {
611 const Node *Base;
612 Node *Dimension;
613
614public:
615 ArrayType(const Node *Base_, Node *Dimension_)
616 : Node(KArrayType,
617 /*RHSComponentCache=*/Cache::Yes,
618 /*ArrayCache=*/Cache::Yes),
619 Base(Base_), Dimension(Dimension_) {}
620
621 template<typename Fn> void match(Fn F) const { F(Base, Dimension); }
622
623 bool hasRHSComponentSlow(OutputStream &) const override { return true; }
624 bool hasArraySlow(OutputStream &) const override { return true; }
625
626 void printLeft(OutputStream &S) const override { Base->printLeft(S); }
627
628 void printRight(OutputStream &S) const override {
629 if (S.back() != ']')
630 S += " ";
631 S += "[";
632 if (Dimension)
633 Dimension->print(S);
634 S += "]";
635 Base->printRight(S);
636 }
637};
638
639class FunctionType final : public Node {
640 const Node *Ret;
641 NodeArray Params;
642 Qualifiers CVQuals;
643 FunctionRefQual RefQual;
644 const Node *ExceptionSpec;
645
646public:
647 FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,
648 FunctionRefQual RefQual_, const Node *ExceptionSpec_)
649 : Node(KFunctionType,
650 /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
651 /*FunctionCache=*/Cache::Yes),
652 Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),
653 ExceptionSpec(ExceptionSpec_) {}
654
655 template<typename Fn> void match(Fn F) const {
656 F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
657 }
658
659 bool hasRHSComponentSlow(OutputStream &) const override { return true; }
660 bool hasFunctionSlow(OutputStream &) const override { return true; }
661
662 // Handle C++'s ... quirky decl grammar by using the left & right
663 // distinction. Consider:
664 // int (*f(float))(char) {}
665 // f is a function that takes a float and returns a pointer to a function
666 // that takes a char and returns an int. If we're trying to print f, start
667 // by printing out the return types's left, then print our parameters, then
668 // finally print right of the return type.
669 void printLeft(OutputStream &S) const override {
670 Ret->printLeft(S);
671 S += " ";
672 }
673
674 void printRight(OutputStream &S) const override {
675 S += "(";
676 Params.printWithComma(S);
677 S += ")";
678 Ret->printRight(S);
679
680 if (CVQuals & QualConst)
681 S += " const";
682 if (CVQuals & QualVolatile)
683 S += " volatile";
684 if (CVQuals & QualRestrict)
685 S += " restrict";
686
687 if (RefQual == FrefQualLValue)
688 S += " &";
689 else if (RefQual == FrefQualRValue)
690 S += " &&";
691
692 if (ExceptionSpec != nullptr) {
693 S += ' ';
694 ExceptionSpec->print(S);
695 }
696 }
697};
698
699class NoexceptSpec : public Node {
700 const Node *E;
701public:
702 NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {}
703
704 template<typename Fn> void match(Fn F) const { F(E); }
705
706 void printLeft(OutputStream &S) const override {
707 S += "noexcept(";
708 E->print(S);
709 S += ")";
710 }
711};
712
713class DynamicExceptionSpec : public Node {
714 NodeArray Types;
715public:
716 DynamicExceptionSpec(NodeArray Types_)
717 : Node(KDynamicExceptionSpec), Types(Types_) {}
718
719 template<typename Fn> void match(Fn F) const { F(Types); }
720
721 void printLeft(OutputStream &S) const override {
722 S += "throw(";
723 Types.printWithComma(S);
724 S += ')';
725 }
726};
727
728class FunctionEncoding final : public Node {
729 const Node *Ret;
730 const Node *Name;
731 NodeArray Params;
732 const Node *Attrs;
733 Qualifiers CVQuals;
734 FunctionRefQual RefQual;
735
736public:
737 FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
738 const Node *Attrs_, Qualifiers CVQuals_,
739 FunctionRefQual RefQual_)
740 : Node(KFunctionEncoding,
741 /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
742 /*FunctionCache=*/Cache::Yes),
743 Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
744 CVQuals(CVQuals_), RefQual(RefQual_) {}
745
746 template<typename Fn> void match(Fn F) const {
747 F(Ret, Name, Params, Attrs, CVQuals, RefQual);
748 }
749
750 Qualifiers getCVQuals() const { return CVQuals; }
751 FunctionRefQual getRefQual() const { return RefQual; }
752 NodeArray getParams() const { return Params; }
753 const Node *getReturnType() const { return Ret; }
754
755 bool hasRHSComponentSlow(OutputStream &) const override { return true; }
756 bool hasFunctionSlow(OutputStream &) const override { return true; }
757
758 const Node *getName() const { return Name; }
759
760 void printLeft(OutputStream &S) const override {
761 if (Ret) {
762 Ret->printLeft(S);
763 if (!Ret->hasRHSComponent(S))
764 S += " ";
765 }
766 Name->print(S);
767 }
768
769 void printRight(OutputStream &S) const override {
770 S += "(";
771 Params.printWithComma(S);
772 S += ")";
773 if (Ret)
774 Ret->printRight(S);
775
776 if (CVQuals & QualConst)
777 S += " const";
778 if (CVQuals & QualVolatile)
779 S += " volatile";
780 if (CVQuals & QualRestrict)
781 S += " restrict";
782
783 if (RefQual == FrefQualLValue)
784 S += " &";
785 else if (RefQual == FrefQualRValue)
786 S += " &&";
787
788 if (Attrs != nullptr)
789 Attrs->print(S);
790 }
791};
792
793class LiteralOperator : public Node {
794 const Node *OpName;
795
796public:
797 LiteralOperator(const Node *OpName_)
798 : Node(KLiteralOperator), OpName(OpName_) {}
799
800 template<typename Fn> void match(Fn F) const { F(OpName); }
801
802 void printLeft(OutputStream &S) const override {
803 S += "operator\"\" ";
804 OpName->print(S);
805 }
806};
807
808class SpecialName final : public Node {
809 const StringView Special;
810 const Node *Child;
811
812public:
813 SpecialName(StringView Special_, const Node *Child_)
814 : Node(KSpecialName), Special(Special_), Child(Child_) {}
815
816 template<typename Fn> void match(Fn F) const { F(Special, Child); }
817
818 void printLeft(OutputStream &S) const override {
819 S += Special;
820 Child->print(S);
821 }
822};
823
824class CtorVtableSpecialName final : public Node {
825 const Node *FirstType;
826 const Node *SecondType;
827
828public:
829 CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_)
830 : Node(KCtorVtableSpecialName),
831 FirstType(FirstType_), SecondType(SecondType_) {}
832
833 template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }
834
835 void printLeft(OutputStream &S) const override {
836 S += "construction vtable for ";
837 FirstType->print(S);
838 S += "-in-";
839 SecondType->print(S);
840 }
841};
842
843struct NestedName : Node {
844 Node *Qual;
845 Node *Name;
846
847 NestedName(Node *Qual_, Node *Name_)
848 : Node(KNestedName), Qual(Qual_), Name(Name_) {}
849
850 template<typename Fn> void match(Fn F) const { F(Qual, Name); }
851
852 StringView getBaseName() const override { return Name->getBaseName(); }
853
854 void printLeft(OutputStream &S) const override {
855 Qual->print(S);
856 S += "::";
857 Name->print(S);
858 }
859};
860
861struct LocalName : Node {
862 Node *Encoding;
863 Node *Entity;
864
865 LocalName(Node *Encoding_, Node *Entity_)
866 : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {}
867
868 template<typename Fn> void match(Fn F) const { F(Encoding, Entity); }
869
870 void printLeft(OutputStream &S) const override {
871 Encoding->print(S);
872 S += "::";
873 Entity->print(S);
874 }
875};
876
877class QualifiedName final : public Node {
878 // qualifier::name
879 const Node *Qualifier;
880 const Node *Name;
881
882public:
883 QualifiedName(const Node *Qualifier_, const Node *Name_)
884 : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
885
886 template<typename Fn> void match(Fn F) const { F(Qualifier, Name); }
887
888 StringView getBaseName() const override { return Name->getBaseName(); }
889
890 void printLeft(OutputStream &S) const override {
891 Qualifier->print(S);
892 S += "::";
893 Name->print(S);
894 }
895};
896
897class VectorType final : public Node {
898 const Node *BaseType;
899 const Node *Dimension;
900
901public:
902 VectorType(const Node *BaseType_, Node *Dimension_)
903 : Node(KVectorType), BaseType(BaseType_),
904 Dimension(Dimension_) {}
905
906 template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
907
908 void printLeft(OutputStream &S) const override {
909 BaseType->print(S);
910 S += " vector[";
911 if (Dimension)
912 Dimension->print(S);
913 S += "]";
914 }
915};
916
917class PixelVectorType final : public Node {
918 const Node *Dimension;
919
920public:
921 PixelVectorType(const Node *Dimension_)
922 : Node(KPixelVectorType), Dimension(Dimension_) {}
923
924 template<typename Fn> void match(Fn F) const { F(Dimension); }
925
926 void printLeft(OutputStream &S) const override {
927 // FIXME: This should demangle as "vector pixel".
928 S += "pixel vector[";
929 Dimension->print(S);
930 S += "]";
931 }
932};
933
934enum class TemplateParamKind { Type, NonType, Template };
935
936/// An invented name for a template parameter for which we don't have a
937/// corresponding template argument.
938///
939/// This node is created when parsing the <lambda-sig> for a lambda with
940/// explicit template arguments, which might be referenced in the parameter
941/// types appearing later in the <lambda-sig>.
942class SyntheticTemplateParamName final : public Node {
943 TemplateParamKind Kind;
944 unsigned Index;
945
946public:
947 SyntheticTemplateParamName(TemplateParamKind Kind_, unsigned Index_)
948 : Node(KSyntheticTemplateParamName), Kind(Kind_), Index(Index_) {}
949
950 template<typename Fn> void match(Fn F) const { F(Kind, Index); }
951
952 void printLeft(OutputStream &S) const override {
953 switch (Kind) {
954 case TemplateParamKind::Type:
955 S += "$T";
956 break;
957 case TemplateParamKind::NonType:
958 S += "$N";
959 break;
960 case TemplateParamKind::Template:
961 S += "$TT";
962 break;
963 }
964 if (Index > 0)
965 S << Index - 1;
966 }
967};
968
969/// A template type parameter declaration, 'typename T'.
970class TypeTemplateParamDecl final : public Node {
971 Node *Name;
972
973public:
974 TypeTemplateParamDecl(Node *Name_)
975 : Node(KTypeTemplateParamDecl, Cache::Yes), Name(Name_) {}
976
977 template<typename Fn> void match(Fn F) const { F(Name); }
978
979 void printLeft(OutputStream &S) const override {
980 S += "typename ";
981 }
982
983 void printRight(OutputStream &S) const override {
984 Name->print(S);
985 }
986};
987
988/// A non-type template parameter declaration, 'int N'.
989class NonTypeTemplateParamDecl final : public Node {
990 Node *Name;
991 Node *Type;
992
993public:
994 NonTypeTemplateParamDecl(Node *Name_, Node *Type_)
995 : Node(KNonTypeTemplateParamDecl, Cache::Yes), Name(Name_), Type(Type_) {}
996
997 template<typename Fn> void match(Fn F) const { F(Name, Type); }
998
999 void printLeft(OutputStream &S) const override {
1000 Type->printLeft(S);
1001 if (!Type->hasRHSComponent(S))
1002 S += " ";
1003 }
1004
1005 void printRight(OutputStream &S) const override {
1006 Name->print(S);
1007 Type->printRight(S);
1008 }
1009};
1010
1011/// A template template parameter declaration,
1012/// 'template<typename T> typename N'.
1013class TemplateTemplateParamDecl final : public Node {
1014 Node *Name;
1015 NodeArray Params;
1016
1017public:
1018 TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
1019 : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
1020 Params(Params_) {}
1021
1022 template<typename Fn> void match(Fn F) const { F(Name, Params); }
1023
1024 void printLeft(OutputStream &S) const override {
1025 S += "template<";
1026 Params.printWithComma(S);
1027 S += "> typename ";
1028 }
1029
1030 void printRight(OutputStream &S) const override {
1031 Name->print(S);
1032 }
1033};
1034
1035/// A template parameter pack declaration, 'typename ...T'.
1036class TemplateParamPackDecl final : public Node {
1037 Node *Param;
1038
1039public:
1040 TemplateParamPackDecl(Node *Param_)
1041 : Node(KTemplateParamPackDecl, Cache::Yes), Param(Param_) {}
1042
1043 template<typename Fn> void match(Fn F) const { F(Param); }
1044
1045 void printLeft(OutputStream &S) const override {
1046 Param->printLeft(S);
1047 S += "...";
1048 }
1049
1050 void printRight(OutputStream &S) const override {
1051 Param->printRight(S);
1052 }
1053};
1054
1055/// An unexpanded parameter pack (either in the expression or type context). If
1056/// this AST is correct, this node will have a ParameterPackExpansion node above
1057/// it.
1058///
1059/// This node is created when some <template-args> are found that apply to an
1060/// <encoding>, and is stored in the TemplateParams table. In order for this to
1061/// appear in the final AST, it has to referenced via a <template-param> (ie,
1062/// T_).
1063class ParameterPack final : public Node {
1064 NodeArray Data;
1065
1066 // Setup OutputStream for a pack expansion unless we're already expanding one.
1067 void initializePackExpansion(OutputStream &S) const {
1068 if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
1069 S.CurrentPackMax = static_cast<unsigned>(Data.size());
1070 S.CurrentPackIndex = 0;
1071 }
1072 }
1073
1074public:
1075 ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {
1076 ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;
1077 if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
1078 return P->ArrayCache == Cache::No;
1079 }))
1080 ArrayCache = Cache::No;
1081 if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
1082 return P->FunctionCache == Cache::No;
1083 }))
1084 FunctionCache = Cache::No;
1085 if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
1086 return P->RHSComponentCache == Cache::No;
1087 }))
1088 RHSComponentCache = Cache::No;
1089 }
1090
1091 template<typename Fn> void match(Fn F) const { F(Data); }
1092
1093 bool hasRHSComponentSlow(OutputStream &S) const override {
1094 initializePackExpansion(S);
1095 size_t Idx = S.CurrentPackIndex;
1096 return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
1097 }
1098 bool hasArraySlow(OutputStream &S) const override {
1099 initializePackExpansion(S);
1100 size_t Idx = S.CurrentPackIndex;
1101 return Idx < Data.size() && Data[Idx]->hasArray(S);
1102 }
1103 bool hasFunctionSlow(OutputStream &S) const override {
1104 initializePackExpansion(S);
1105 size_t Idx = S.CurrentPackIndex;
1106 return Idx < Data.size() && Data[Idx]->hasFunction(S);
1107 }
1108 const Node *getSyntaxNode(OutputStream &S) const override {
1109 initializePackExpansion(S);
1110 size_t Idx = S.CurrentPackIndex;
1111 return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
1112 }
1113
1114 void printLeft(OutputStream &S) const override {
1115 initializePackExpansion(S);
1116 size_t Idx = S.CurrentPackIndex;
1117 if (Idx < Data.size())
1118 Data[Idx]->printLeft(S);
1119 }
1120 void printRight(OutputStream &S) const override {
1121 initializePackExpansion(S);
1122 size_t Idx = S.CurrentPackIndex;
1123 if (Idx < Data.size())
1124 Data[Idx]->printRight(S);
1125 }
1126};
1127
1128/// A variadic template argument. This node represents an occurrence of
1129/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
1130/// one of it's Elements is. The parser inserts a ParameterPack into the
1131/// TemplateParams table if the <template-args> this pack belongs to apply to an
1132/// <encoding>.
1133class TemplateArgumentPack final : public Node {
1134 NodeArray Elements;
1135public:
1136 TemplateArgumentPack(NodeArray Elements_)
1137 : Node(KTemplateArgumentPack), Elements(Elements_) {}
1138
1139 template<typename Fn> void match(Fn F) const { F(Elements); }
1140
1141 NodeArray getElements() const { return Elements; }
1142
1143 void printLeft(OutputStream &S) const override {
1144 Elements.printWithComma(S);
1145 }
1146};
1147
1148/// A pack expansion. Below this node, there are some unexpanded ParameterPacks
1149/// which each have Child->ParameterPackSize elements.
1150class ParameterPackExpansion final : public Node {
1151 const Node *Child;
1152
1153public:
1154 ParameterPackExpansion(const Node *Child_)
1155 : Node(KParameterPackExpansion), Child(Child_) {}
1156
1157 template<typename Fn> void match(Fn F) const { F(Child); }
1158
1159 const Node *getChild() const { return Child; }
1160
1161 void printLeft(OutputStream &S) const override {
1162 constexpr unsigned Max = std::numeric_limits<unsigned>::max();
1163 SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);
1164 SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);
1165 size_t StreamPos = S.getCurrentPosition();
1166
1167 // Print the first element in the pack. If Child contains a ParameterPack,
1168 // it will set up S.CurrentPackMax and print the first element.
1169 Child->print(S);
1170
1171 // No ParameterPack was found in Child. This can occur if we've found a pack
1172 // expansion on a <function-param>.
1173 if (S.CurrentPackMax == Max) {
1174 S += "...";
1175 return;
1176 }
1177
1178 // We found a ParameterPack, but it has no elements. Erase whatever we may
1179 // of printed.
1180 if (S.CurrentPackMax == 0) {
1181 S.setCurrentPosition(StreamPos);
1182 return;
1183 }
1184
1185 // Else, iterate through the rest of the elements in the pack.
1186 for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
1187 S += ", ";
1188 S.CurrentPackIndex = I;
1189 Child->print(S);
1190 }
1191 }
1192};
1193
1194class TemplateArgs final : public Node {
1195 NodeArray Params;
1196
1197public:
1198 TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
1199
1200 template<typename Fn> void match(Fn F) const { F(Params); }
1201
1202 NodeArray getParams() { return Params; }
1203
1204 void printLeft(OutputStream &S) const override {
1205 S += "<";
1206 Params.printWithComma(S);
1207 if (S.back() == '>')
1208 S += " ";
1209 S += ">";
1210 }
1211};
1212
1213/// A forward-reference to a template argument that was not known at the point
1214/// where the template parameter name was parsed in a mangling.
1215///
1216/// This is created when demangling the name of a specialization of a
1217/// conversion function template:
1218///
1219/// \code
1220/// struct A {
1221/// template<typename T> operator T*();
1222/// };
1223/// \endcode
1224///
1225/// When demangling a specialization of the conversion function template, we
1226/// encounter the name of the template (including the \c T) before we reach
1227/// the template argument list, so we cannot substitute the parameter name
1228/// for the corresponding argument while parsing. Instead, we create a
1229/// \c ForwardTemplateReference node that is resolved after we parse the
1230/// template arguments.
1231struct ForwardTemplateReference : Node {
1232 size_t Index;
1233 Node *Ref = nullptr;
1234
1235 // If we're currently printing this node. It is possible (though invalid) for
1236 // a forward template reference to refer to itself via a substitution. This
1237 // creates a cyclic AST, which will stack overflow printing. To fix this, bail
1238 // out if more than one print* function is active.
1239 mutable bool Printing = false;
1240
1241 ForwardTemplateReference(size_t Index_)
1242 : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown,
1243 Cache::Unknown),
1244 Index(Index_) {}
1245
1246 // We don't provide a matcher for these, because the value of the node is
1247 // not determined by its construction parameters, and it generally needs
1248 // special handling.
1249 template<typename Fn> void match(Fn F) const = delete;
1250
1251 bool hasRHSComponentSlow(OutputStream &S) const override {
1252 if (Printing)
1253 return false;
1254 SwapAndRestore<bool> SavePrinting(Printing, true);
1255 return Ref->hasRHSComponent(S);
1256 }
1257 bool hasArraySlow(OutputStream &S) const override {
1258 if (Printing)
1259 return false;
1260 SwapAndRestore<bool> SavePrinting(Printing, true);
1261 return Ref->hasArray(S);
1262 }
1263 bool hasFunctionSlow(OutputStream &S) const override {
1264 if (Printing)
1265 return false;
1266 SwapAndRestore<bool> SavePrinting(Printing, true);
1267 return Ref->hasFunction(S);
1268 }
1269 const Node *getSyntaxNode(OutputStream &S) const override {
1270 if (Printing)
1271 return this;
1272 SwapAndRestore<bool> SavePrinting(Printing, true);
1273 return Ref->getSyntaxNode(S);
1274 }
1275
1276 void printLeft(OutputStream &S) const override {
1277 if (Printing)
1278 return;
1279 SwapAndRestore<bool> SavePrinting(Printing, true);
1280 Ref->printLeft(S);
1281 }
1282 void printRight(OutputStream &S) const override {
1283 if (Printing)
1284 return;
1285 SwapAndRestore<bool> SavePrinting(Printing, true);
1286 Ref->printRight(S);
1287 }
1288};
1289
1290struct NameWithTemplateArgs : Node {
1291 // name<template_args>
1292 Node *Name;
1293 Node *TemplateArgs;
1294
1295 NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
1296 : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
1297
1298 template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); }
1299
1300 StringView getBaseName() const override { return Name->getBaseName(); }
1301
1302 void printLeft(OutputStream &S) const override {
1303 Name->print(S);
1304 TemplateArgs->print(S);
1305 }
1306};
1307
1308class GlobalQualifiedName final : public Node {
1309 Node *Child;
1310
1311public:
1312 GlobalQualifiedName(Node* Child_)
1313 : Node(KGlobalQualifiedName), Child(Child_) {}
1314
1315 template<typename Fn> void match(Fn F) const { F(Child); }
1316
1317 StringView getBaseName() const override { return Child->getBaseName(); }
1318
1319 void printLeft(OutputStream &S) const override {
1320 S += "::";
1321 Child->print(S);
1322 }
1323};
1324
1325struct StdQualifiedName : Node {
1326 Node *Child;
1327
1328 StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
1329
1330 template<typename Fn> void match(Fn F) const { F(Child); }
1331
1332 StringView getBaseName() const override { return Child->getBaseName(); }
1333
1334 void printLeft(OutputStream &S) const override {
1335 S += "std::";
1336 Child->print(S);
1337 }
1338};
1339
1340enum class SpecialSubKind {
1341 allocator,
1342 basic_string,
1343 string,
1344 istream,
1345 ostream,
1346 iostream,
1347};
1348
1349class ExpandedSpecialSubstitution final : public Node {
1350 SpecialSubKind SSK;
1351
1352public:
1353 ExpandedSpecialSubstitution(SpecialSubKind SSK_)
1354 : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
1355
1356 template<typename Fn> void match(Fn F) const { F(SSK); }
1357
1358 StringView getBaseName() const override {
1359 switch (SSK) {
1360 case SpecialSubKind::allocator:
1361 return StringView("allocator");
1362 case SpecialSubKind::basic_string:
1363 return StringView("basic_string");
1364 case SpecialSubKind::string:
1365 return StringView("basic_string");
1366 case SpecialSubKind::istream:
1367 return StringView("basic_istream");
1368 case SpecialSubKind::ostream:
1369 return StringView("basic_ostream");
1370 case SpecialSubKind::iostream:
1371 return StringView("basic_iostream");
1372 }
1373 DEMANGLE_UNREACHABLE;
1374 }
1375
1376 void printLeft(OutputStream &S) const override {
1377 switch (SSK) {
1378 case SpecialSubKind::allocator:
1379 S += "std::allocator";
1380 break;
1381 case SpecialSubKind::basic_string:
1382 S += "std::basic_string";
1383 break;
1384 case SpecialSubKind::string:
1385 S += "std::basic_string<char, std::char_traits<char>, "
1386 "std::allocator<char> >";
1387 break;
1388 case SpecialSubKind::istream:
1389 S += "std::basic_istream<char, std::char_traits<char> >";
1390 break;
1391 case SpecialSubKind::ostream:
1392 S += "std::basic_ostream<char, std::char_traits<char> >";
1393 break;
1394 case SpecialSubKind::iostream:
1395 S += "std::basic_iostream<char, std::char_traits<char> >";
1396 break;
1397 }
1398 }
1399};
1400
1401class SpecialSubstitution final : public Node {
1402public:
1403 SpecialSubKind SSK;
1404
1405 SpecialSubstitution(SpecialSubKind SSK_)
1406 : Node(KSpecialSubstitution), SSK(SSK_) {}
1407
1408 template<typename Fn> void match(Fn F) const { F(SSK); }
1409
1410 StringView getBaseName() const override {
1411 switch (SSK) {
1412 case SpecialSubKind::allocator:
1413 return StringView("allocator");
1414 case SpecialSubKind::basic_string:
1415 return StringView("basic_string");
1416 case SpecialSubKind::string:
1417 return StringView("string");
1418 case SpecialSubKind::istream:
1419 return StringView("istream");
1420 case SpecialSubKind::ostream:
1421 return StringView("ostream");
1422 case SpecialSubKind::iostream:
1423 return StringView("iostream");
1424 }
1425 DEMANGLE_UNREACHABLE;
1426 }
1427
1428 void printLeft(OutputStream &S) const override {
1429 switch (SSK) {
1430 case SpecialSubKind::allocator:
1431 S += "std::allocator";
1432 break;
1433 case SpecialSubKind::basic_string:
1434 S += "std::basic_string";
1435 break;
1436 case SpecialSubKind::string:
1437 S += "std::string";
1438 break;
1439 case SpecialSubKind::istream:
1440 S += "std::istream";
1441 break;
1442 case SpecialSubKind::ostream:
1443 S += "std::ostream";
1444 break;
1445 case SpecialSubKind::iostream:
1446 S += "std::iostream";
1447 break;
1448 }
1449 }
1450};
1451
1452class CtorDtorName final : public Node {
1453 const Node *Basename;
1454 const bool IsDtor;
1455 const int Variant;
1456
1457public:
1458 CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_)
1459 : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_),
1460 Variant(Variant_) {}
1461
1462 template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
1463
1464 void printLeft(OutputStream &S) const override {
1465 if (IsDtor)
1466 S += "~";
1467 S += Basename->getBaseName();
1468 }
1469};
1470
1471class DtorName : public Node {
1472 const Node *Base;
1473
1474public:
1475 DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {}
1476
1477 template<typename Fn> void match(Fn F) const { F(Base); }
1478
1479 void printLeft(OutputStream &S) const override {
1480 S += "~";
1481 Base->printLeft(S);
1482 }
1483};
1484
1485class UnnamedTypeName : public Node {
1486 const StringView Count;
1487
1488public:
1489 UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {}
1490
1491 template<typename Fn> void match(Fn F) const { F(Count); }
1492
1493 void printLeft(OutputStream &S) const override {
1494 S += "'unnamed";
1495 S += Count;
1496 S += "\'";
1497 }
1498};
1499
1500class ClosureTypeName : public Node {
1501 NodeArray TemplateParams;
1502 NodeArray Params;
1503 StringView Count;
1504
1505public:
1506 ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
1507 StringView Count_)
1508 : Node(KClosureTypeName), TemplateParams(TemplateParams_),
1509 Params(Params_), Count(Count_) {}
1510
1511 template<typename Fn> void match(Fn F) const {
1512 F(TemplateParams, Params, Count);
1513 }
1514
1515 void printDeclarator(OutputStream &S) const {
1516 if (!TemplateParams.empty()) {
1517 S += "<";
1518 TemplateParams.printWithComma(S);
1519 S += ">";
1520 }
1521 S += "(";
1522 Params.printWithComma(S);
1523 S += ")";
1524 }
1525
1526 void printLeft(OutputStream &S) const override {
1527 S += "\'lambda";
1528 S += Count;
1529 S += "\'";
1530 printDeclarator(S);
1531 }
1532};
1533
1534class StructuredBindingName : public Node {
1535 NodeArray Bindings;
1536public:
1537 StructuredBindingName(NodeArray Bindings_)
1538 : Node(KStructuredBindingName), Bindings(Bindings_) {}
1539
1540 template<typename Fn> void match(Fn F) const { F(Bindings); }
1541
1542 void printLeft(OutputStream &S) const override {
1543 S += '[';
1544 Bindings.printWithComma(S);
1545 S += ']';
1546 }
1547};
1548
1549// -- Expression Nodes --
1550
1551class BinaryExpr : public Node {
1552 const Node *LHS;
1553 const StringView InfixOperator;
1554 const Node *RHS;
1555
1556public:
1557 BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_)
1558 : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {
1559 }
1560
1561 template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }
1562
1563 void printLeft(OutputStream &S) const override {
1564 // might be a template argument expression, then we need to disambiguate
1565 // with parens.
1566 if (InfixOperator == ">")
1567 S += "(";
1568
1569 S += "(";
1570 LHS->print(S);
1571 S += ") ";
1572 S += InfixOperator;
1573 S += " (";
1574 RHS->print(S);
1575 S += ")";
1576
1577 if (InfixOperator == ">")
1578 S += ")";
1579 }
1580};
1581
1582class ArraySubscriptExpr : public Node {
1583 const Node *Op1;
1584 const Node *Op2;
1585
1586public:
1587 ArraySubscriptExpr(const Node *Op1_, const Node *Op2_)
1588 : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {}
1589
1590 template<typename Fn> void match(Fn F) const { F(Op1, Op2); }
1591
1592 void printLeft(OutputStream &S) const override {
1593 S += "(";
1594 Op1->print(S);
1595 S += ")[";
1596 Op2->print(S);
1597 S += "]";
1598 }
1599};
1600
1601class PostfixExpr : public Node {
1602 const Node *Child;
1603 const StringView Operator;
1604
1605public:
1606 PostfixExpr(const Node *Child_, StringView Operator_)
1607 : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {}
1608
1609 template<typename Fn> void match(Fn F) const { F(Child, Operator); }
1610
1611 void printLeft(OutputStream &S) const override {
1612 S += "(";
1613 Child->print(S);
1614 S += ")";
1615 S += Operator;
1616 }
1617};
1618
1619class ConditionalExpr : public Node {
1620 const Node *Cond;
1621 const Node *Then;
1622 const Node *Else;
1623
1624public:
1625 ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_)
1626 : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {}
1627
1628 template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }
1629
1630 void printLeft(OutputStream &S) const override {
1631 S += "(";
1632 Cond->print(S);
1633 S += ") ? (";
1634 Then->print(S);
1635 S += ") : (";
1636 Else->print(S);
1637 S += ")";
1638 }
1639};
1640
1641class MemberExpr : public Node {
1642 const Node *LHS;
1643 const StringView Kind;
1644 const Node *RHS;
1645
1646public:
1647 MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_)
1648 : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
1649
1650 template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }
1651
1652 void printLeft(OutputStream &S) const override {
1653 LHS->print(S);
1654 S += Kind;
1655 RHS->print(S);
1656 }
1657};
1658
1659class EnclosingExpr : public Node {
1660 const StringView Prefix;
1661 const Node *Infix;
1662 const StringView Postfix;
1663
1664public:
1665 EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
1666 : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_),
1667 Postfix(Postfix_) {}
1668
1669 template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }
1670
1671 void printLeft(OutputStream &S) const override {
1672 S += Prefix;
1673 Infix->print(S);
1674 S += Postfix;
1675 }
1676};
1677
1678class CastExpr : public Node {
1679 // cast_kind<to>(from)
1680 const StringView CastKind;
1681 const Node *To;
1682 const Node *From;
1683
1684public:
1685 CastExpr(StringView CastKind_, const Node *To_, const Node *From_)
1686 : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {}
1687
1688 template<typename Fn> void match(Fn F) const { F(CastKind, To, From); }
1689
1690 void printLeft(OutputStream &S) const override {
1691 S += CastKind;
1692 S += "<";
1693 To->printLeft(S);
1694 S += ">(";
1695 From->printLeft(S);
1696 S += ")";
1697 }
1698};
1699
1700class SizeofParamPackExpr : public Node {
1701 const Node *Pack;
1702
1703public:
1704 SizeofParamPackExpr(const Node *Pack_)
1705 : Node(KSizeofParamPackExpr), Pack(Pack_) {}
1706
1707 template<typename Fn> void match(Fn F) const { F(Pack); }
1708
1709 void printLeft(OutputStream &S) const override {
1710 S += "sizeof...(";
1711 ParameterPackExpansion PPE(Pack);
1712 PPE.printLeft(S);
1713 S += ")";
1714 }
1715};
1716
1717class CallExpr : public Node {
1718 const Node *Callee;
1719 NodeArray Args;
1720
1721public:
1722 CallExpr(const Node *Callee_, NodeArray Args_)
1723 : Node(KCallExpr), Callee(Callee_), Args(Args_) {}
1724
1725 template<typename Fn> void match(Fn F) const { F(Callee, Args); }
1726
1727 void printLeft(OutputStream &S) const override {
1728 Callee->print(S);
1729 S += "(";
1730 Args.printWithComma(S);
1731 S += ")";
1732 }
1733};
1734
1735class NewExpr : public Node {
1736 // new (expr_list) type(init_list)
1737 NodeArray ExprList;
1738 Node *Type;
1739 NodeArray InitList;
1740 bool IsGlobal; // ::operator new ?
1741 bool IsArray; // new[] ?
1742public:
1743 NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
1744 bool IsArray_)
1745 : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_),
1746 IsGlobal(IsGlobal_), IsArray(IsArray_) {}
1747
1748 template<typename Fn> void match(Fn F) const {
1749 F(ExprList, Type, InitList, IsGlobal, IsArray);
1750 }
1751
1752 void printLeft(OutputStream &S) const override {
1753 if (IsGlobal)
1754 S += "::operator ";
1755 S += "new";
1756 if (IsArray)
1757 S += "[]";
1758 S += ' ';
1759 if (!ExprList.empty()) {
1760 S += "(";
1761 ExprList.printWithComma(S);
1762 S += ")";
1763 }
1764 Type->print(S);
1765 if (!InitList.empty()) {
1766 S += "(";
1767 InitList.printWithComma(S);
1768 S += ")";
1769 }
1770
1771 }
1772};
1773
1774class DeleteExpr : public Node {
1775 Node *Op;
1776 bool IsGlobal;
1777 bool IsArray;
1778
1779public:
1780 DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
1781 : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
1782
1783 template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }
1784
1785 void printLeft(OutputStream &S) const override {
1786 if (IsGlobal)
1787 S += "::";
1788 S += "delete";
1789 if (IsArray)
1790 S += "[] ";
1791 Op->print(S);
1792 }
1793};
1794
1795class PrefixExpr : public Node {
1796 StringView Prefix;
1797 Node *Child;
1798
1799public:
1800 PrefixExpr(StringView Prefix_, Node *Child_)
1801 : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {}
1802
1803 template<typename Fn> void match(Fn F) const { F(Prefix, Child); }
1804
1805 void printLeft(OutputStream &S) const override {
1806 S += Prefix;
1807 S += "(";
1808 Child->print(S);
1809 S += ")";
1810 }
1811};
1812
1813class FunctionParam : public Node {
1814 StringView Number;
1815
1816public:
1817 FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {}
1818
1819 template<typename Fn> void match(Fn F) const { F(Number); }
1820
1821 void printLeft(OutputStream &S) const override {
1822 S += "fp";
1823 S += Number;
1824 }
1825};
1826
1827class ConversionExpr : public Node {
1828 const Node *Type;
1829 NodeArray Expressions;
1830
1831public:
1832 ConversionExpr(const Node *Type_, NodeArray Expressions_)
1833 : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {}
1834
1835 template<typename Fn> void match(Fn F) const { F(Type, Expressions); }
1836
1837 void printLeft(OutputStream &S) const override {
1838 S += "(";
1839 Type->print(S);
1840 S += ")(";
1841 Expressions.printWithComma(S);
1842 S += ")";
1843 }
1844};
1845
1846class InitListExpr : public Node {
1847 const Node *Ty;
1848 NodeArray Inits;
1849public:
1850 InitListExpr(const Node *Ty_, NodeArray Inits_)
1851 : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {}
1852
1853 template<typename Fn> void match(Fn F) const { F(Ty, Inits); }
1854
1855 void printLeft(OutputStream &S) const override {
1856 if (Ty)
1857 Ty->print(S);
1858 S += '{';
1859 Inits.printWithComma(S);
1860 S += '}';
1861 }
1862};
1863
1864class BracedExpr : public Node {
1865 const Node *Elem;
1866 const Node *Init;
1867 bool IsArray;
1868public:
1869 BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_)
1870 : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}
1871
1872 template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }
1873
1874 void printLeft(OutputStream &S) const override {
1875 if (IsArray) {
1876 S += '[';
1877 Elem->print(S);
1878 S += ']';
1879 } else {
1880 S += '.';
1881 Elem->print(S);
1882 }
1883 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
1884 S += " = ";
1885 Init->print(S);
1886 }
1887};
1888
1889class BracedRangeExpr : public Node {
1890 const Node *First;
1891 const Node *Last;
1892 const Node *Init;
1893public:
1894 BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_)
1895 : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}
1896
1897 template<typename Fn> void match(Fn F) const { F(First, Last, Init); }
1898
1899 void printLeft(OutputStream &S) const override {
1900 S += '[';
1901 First->print(S);
1902 S += " ... ";
1903 Last->print(S);
1904 S += ']';
1905 if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
1906 S += " = ";
1907 Init->print(S);
1908 }
1909};
1910
1911class FoldExpr : public Node {
1912 const Node *Pack, *Init;
1913 StringView OperatorName;
1914 bool IsLeftFold;
1915
1916public:
1917 FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_,
1918 const Node *Init_)
1919 : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_),
1920 IsLeftFold(IsLeftFold_) {}
1921
1922 template<typename Fn> void match(Fn F) const {
1923 F(IsLeftFold, OperatorName, Pack, Init);
1924 }
1925
1926 void printLeft(OutputStream &S) const override {
1927 auto PrintPack = [&] {
1928 S += '(';
1929 ParameterPackExpansion(Pack).print(S);
1930 S += ')';
1931 };
1932
1933 S += '(';
1934
1935 if (IsLeftFold) {
1936 // init op ... op pack
1937 if (Init != nullptr) {
1938 Init->print(S);
1939 S += ' ';
1940 S += OperatorName;
1941 S += ' ';
1942 }
1943 // ... op pack
1944 S += "... ";
1945 S += OperatorName;
1946 S += ' ';
1947 PrintPack();
1948 } else { // !IsLeftFold
1949 // pack op ...
1950 PrintPack();
1951 S += ' ';
1952 S += OperatorName;
1953 S += " ...";
1954 // pack op ... op init
1955 if (Init != nullptr) {
1956 S += ' ';
1957 S += OperatorName;
1958 S += ' ';
1959 Init->print(S);
1960 }
1961 }
1962 S += ')';
1963 }
1964};
1965
1966class ThrowExpr : public Node {
1967 const Node *Op;
1968
1969public:
1970 ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {}
1971
1972 template<typename Fn> void match(Fn F) const { F(Op); }
1973
1974 void printLeft(OutputStream &S) const override {
1975 S += "throw ";
1976 Op->print(S);
1977 }
1978};
1979
1980// MSVC __uuidof extension, generated by clang in -fms-extensions mode.
1981class UUIDOfExpr : public Node {
1982 Node *Operand;
1983public:
1984 UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {}
1985
1986 template<typename Fn> void match(Fn F) const { F(Operand); }
1987
1988 void printLeft(OutputStream &S) const override {
1989 S << "__uuidof(";
1990 Operand->print(S);
1991 S << ")";
1992 }
1993};
1994
1995class BoolExpr : public Node {
1996 bool Value;
1997
1998public:
1999 BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {}
2000
2001 template<typename Fn> void match(Fn F) const { F(Value); }
2002
2003 void printLeft(OutputStream &S) const override {
2004 S += Value ? StringView("true") : StringView("false");
2005 }
2006};
2007
2008class StringLiteral : public Node {
2009 const Node *Type;
2010
2011public:
2012 StringLiteral(const Node *Type_) : Node(KStringLiteral), Type(Type_) {}
2013
2014 template<typename Fn> void match(Fn F) const { F(Type); }
2015
2016 void printLeft(OutputStream &S) const override {
2017 S += "\"<";
2018 Type->print(S);
2019 S += ">\"";
2020 }
2021};
2022
2023class LambdaExpr : public Node {
2024 const Node *Type;
2025
2026public:
2027 LambdaExpr(const Node *Type_) : Node(KLambdaExpr), Type(Type_) {}
2028
2029 template<typename Fn> void match(Fn F) const { F(Type); }
2030
2031 void printLeft(OutputStream &S) const override {
2032 S += "[]";
2033 if (Type->getKind() == KClosureTypeName)
2034 static_cast<const ClosureTypeName *>(Type)->printDeclarator(S);
2035 S += "{...}";
2036 }
2037};
2038
2039class IntegerCastExpr : public Node {
2040 // ty(integer)
2041 const Node *Ty;
2042 StringView Integer;
2043
2044public:
2045 IntegerCastExpr(const Node *Ty_, StringView Integer_)
2046 : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {}
2047
2048 template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
2049
2050 void printLeft(OutputStream &S) const override {
2051 S += "(";
2052 Ty->print(S);
2053 S += ")";
2054 S += Integer;
2055 }
2056};
2057
2058class IntegerLiteral : public Node {
2059 StringView Type;
2060 StringView Value;
2061
2062public:
2063 IntegerLiteral(StringView Type_, StringView Value_)
2064 : Node(KIntegerLiteral), Type(Type_), Value(Value_) {}
2065
2066 template<typename Fn> void match(Fn F) const { F(Type, Value); }
2067
2068 void printLeft(OutputStream &S) const override {
2069 if (Type.size() > 3) {
2070 S += "(";
2071 S += Type;
2072 S += ")";
2073 }
2074
2075 if (Value[0] == 'n') {
2076 S += "-";
2077 S += Value.dropFront(1);
2078 } else
2079 S += Value;
2080
2081 if (Type.size() <= 3)
2082 S += Type;
2083 }
2084};
2085
2086template <class Float> struct FloatData;
2087
2088namespace float_literal_impl {
2089constexpr Node::Kind getFloatLiteralKind(float *) {
2090 return Node::KFloatLiteral;
2091}
2092constexpr Node::Kind getFloatLiteralKind(double *) {
2093 return Node::KDoubleLiteral;
2094}
2095constexpr Node::Kind getFloatLiteralKind(long double *) {
2096 return Node::KLongDoubleLiteral;
2097}
2098}
2099
2100template <class Float> class FloatLiteralImpl : public Node {
2101 const StringView Contents;
2102
2103 static constexpr Kind KindForClass =
2104 float_literal_impl::getFloatLiteralKind((Float *)nullptr);
2105
2106public:
2107 FloatLiteralImpl(StringView Contents_)
2108 : Node(KindForClass), Contents(Contents_) {}
2109
2110 template<typename Fn> void match(Fn F) const { F(Contents); }
2111
2112 void printLeft(OutputStream &s) const override {
2113 const char *first = Contents.begin();
2114 const char *last = Contents.end() + 1;
2115
2116 const size_t N = FloatData<Float>::mangled_size;
2117 if (static_cast<std::size_t>(last - first) > N) {
2118 last = first + N;
2119 union {
2120 Float value;
2121 char buf[sizeof(Float)];
2122 };
2123 const char *t = first;
2124 char *e = buf;
2125 for (; t != last; ++t, ++e) {
2126 unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
2127 : static_cast<unsigned>(*t - 'a' + 10);
2128 ++t;
2129 unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')
2130 : static_cast<unsigned>(*t - 'a' + 10);
2131 *e = static_cast<char>((d1 << 4) + d0);
2132 }
2133#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
2134 std::reverse(buf, e);
2135#endif
2136 char num[FloatData<Float>::max_demangled_size] = {0};
2137 int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
2138 s += StringView(num, num + n);
2139 }
2140 }
2141};
2142
2143using FloatLiteral = FloatLiteralImpl<float>;
2144using DoubleLiteral = FloatLiteralImpl<double>;
2145using LongDoubleLiteral = FloatLiteralImpl<long double>;
2146
2147/// Visit the node. Calls \c F(P), where \c P is the node cast to the
2148/// appropriate derived class.
2149template<typename Fn>
2150void Node::visit(Fn F) const {
2151 switch (K) {
2152#define CASE(X) case K ## X: return F(static_cast<const X*>(this));
2153 FOR_EACH_NODE_KIND(CASE)
2154#undef CASE
2155 }
2156 assert(0 && "unknown mangling node kind");
2157}
2158
2159/// Determine the kind of a node from its type.
2160template<typename NodeT> struct NodeKind;
2161#define SPECIALIZATION(X) \
2162 template<> struct NodeKind<X> { \
2163 static constexpr Node::Kind Kind = Node::K##X; \
2164 static constexpr const char *name() { return #X; } \
2165 };
2166FOR_EACH_NODE_KIND(SPECIALIZATION)
2167#undef SPECIALIZATION
2168
2169#undef FOR_EACH_NODE_KIND
2170
2171template <class T, size_t N>
2172class PODSmallVector {
2173 static_assert(std::is_pod<T>::value,
2174 "T is required to be a plain old data type");
2175
2176 T* First = nullptr;
2177 T* Last = nullptr;
2178 T* Cap = nullptr;
2179 T Inline[N] = {0};
2180
2181 bool isInline() const { return First == Inline; }
2182
2183 void clearInline() {
2184 First = Inline;
2185 Last = Inline;
2186 Cap = Inline + N;
2187 }
2188
2189 void reserve(size_t NewCap) {
2190 size_t S = size();
2191 if (isInline()) {
2192 auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
2193 if (Tmp == nullptr)
2194 std::terminate();
2195 std::copy(First, Last, Tmp);
2196 First = Tmp;
2197 } else {
2198 First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
2199 if (First == nullptr)
2200 std::terminate();
2201 }
2202 Last = First + S;
2203 Cap = First + NewCap;
2204 }
2205
2206public:
2207 PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
2208
2209 PODSmallVector(const PODSmallVector&) = delete;
2210 PODSmallVector& operator=(const PODSmallVector&) = delete;
2211
2212 PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
2213 if (Other.isInline()) {
2214 std::copy(Other.begin(), Other.end(), First);
2215 Last = First + Other.size();
2216 Other.clear();
2217 return;
2218 }
2219
2220 First = Other.First;
2221 Last = Other.Last;
2222 Cap = Other.Cap;
2223 Other.clearInline();
2224 }
2225
2226 PODSmallVector& operator=(PODSmallVector&& Other) {
2227 if (Other.isInline()) {
2228 if (!isInline()) {
2229 std::free(First);
2230 clearInline();
2231 }
2232 std::copy(Other.begin(), Other.end(), First);
2233 Last = First + Other.size();
2234 Other.clear();
2235 return *this;
2236 }
2237
2238 if (isInline()) {
2239 First = Other.First;
2240 Last = Other.Last;
2241 Cap = Other.Cap;
2242 Other.clearInline();
2243 return *this;
2244 }
2245
2246 std::swap(First, Other.First);
2247 std::swap(Last, Other.Last);
2248 std::swap(Cap, Other.Cap);
2249 Other.clear();
2250 return *this;
2251 }
2252
2253 void push_back(const T& Elem) {
2254 if (Last == Cap)
2255 reserve(size() * 2);
2256 *Last++ = Elem;
2257 }
2258
2259 void pop_back() {
2260 assert(Last != First && "Popping empty vector!");
2261 --Last;
2262 }
2263
2264 void dropBack(size_t Index) {
2265 assert(Index <= size() && "dropBack() can't expand!");
2266 Last = First + Index;
2267 }
2268
2269 T* begin() { return First; }
2270 T* end() { return Last; }
2271
2272 bool empty() const { return First == Last; }
2273 size_t size() const { return static_cast<size_t>(Last - First); }
2274 T& back() {
2275 assert(Last != First && "Calling back() on empty vector!");
2276 return *(Last - 1);
2277 }
2278 T& operator[](size_t Index) {
2279 assert(Index < size() && "Invalid access!");
2280 return *(begin() + Index);
2281 }
2282 void clear() { Last = First; }
2283
2284 ~PODSmallVector() {
2285 if (!isInline())
2286 std::free(First);
2287 }
2288};
2289
2290template <typename Derived, typename Alloc> struct AbstractManglingParser {
2291 const char *First;
2292 const char *Last;
2293
2294 // Name stack, this is used by the parser to hold temporary names that were
2295 // parsed. The parser collapses multiple names into new nodes to construct
2296 // the AST. Once the parser is finished, names.size() == 1.
2297 PODSmallVector<Node *, 32> Names;
2298
2299 // Substitution table. Itanium supports name substitutions as a means of
2300 // compression. The string "S42_" refers to the 44nd entry (base-36) in this
2301 // table.
2302 PODSmallVector<Node *, 32> Subs;
2303
2304 using TemplateParamList = PODSmallVector<Node *, 8>;
2305
2306 class ScopedTemplateParamList {
2307 AbstractManglingParser *Parser;
2308 size_t OldNumTemplateParamLists;
2309 TemplateParamList Params;
2310
2311 public:
2312 ScopedTemplateParamList(AbstractManglingParser *Parser)
2313 : Parser(Parser),
2314 OldNumTemplateParamLists(Parser->TemplateParams.size()) {
2315 Parser->TemplateParams.push_back(&Params);
2316 }
2317 ~ScopedTemplateParamList() {
2318 assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
2319 Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
2320 }
2321 };
2322
2323 // Template parameter table. Like the above, but referenced like "T42_".
2324 // This has a smaller size compared to Subs and Names because it can be
2325 // stored on the stack.
2326 TemplateParamList OuterTemplateParams;
2327
2328 // Lists of template parameters indexed by template parameter depth,
2329 // referenced like "TL2_4_". If nonempty, element 0 is always
2330 // OuterTemplateParams; inner elements are always template parameter lists of
2331 // lambda expressions. For a generic lambda with no explicit template
2332 // parameter list, the corresponding parameter list pointer will be null.
2333 PODSmallVector<TemplateParamList *, 4> TemplateParams;
2334
2335 // Set of unresolved forward <template-param> references. These can occur in a
2336 // conversion operator's type, and are resolved in the enclosing <encoding>.
2337 PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
2338
2339 bool TryToParseTemplateArgs = true;
2340 bool PermitForwardTemplateReferences = false;
2341 size_t ParsingLambdaParamsAtLevel = (size_t)-1;
2342
2343 unsigned NumSyntheticTemplateParameters[3] = {};
2344
2345 Alloc ASTAllocator;
2346
2347 AbstractManglingParser(const char *First_, const char *Last_)
2348 : First(First_), Last(Last_) {}
2349
2350 Derived &getDerived() { return static_cast<Derived &>(*this); }
2351
2352 void reset(const char *First_, const char *Last_) {
2353 First = First_;
2354 Last = Last_;
2355 Names.clear();
2356 Subs.clear();
2357 TemplateParams.clear();
2358 ParsingLambdaParamsAtLevel = (size_t)-1;
2359 TryToParseTemplateArgs = true;
2360 PermitForwardTemplateReferences = false;
2361 for (int I = 0; I != 3; ++I)
2362 NumSyntheticTemplateParameters[I] = 0;
2363 ASTAllocator.reset();
2364 }
2365
2366 template <class T, class... Args> Node *make(Args &&... args) {
2367 return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...);
2368 }
2369
2370 template <class It> NodeArray makeNodeArray(It begin, It end) {
2371 size_t sz = static_cast<size_t>(end - begin);
2372 void *mem = ASTAllocator.allocateNodeArray(sz);
2373 Node **data = new (mem) Node *[sz];
2374 std::copy(begin, end, data);
2375 return NodeArray(data, sz);
2376 }
2377
2378 NodeArray popTrailingNodeArray(size_t FromPosition) {
2379 assert(FromPosition <= Names.size());
2380 NodeArray res =
2381 makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
2382 Names.dropBack(FromPosition);
2383 return res;
2384 }
2385
2386 bool consumeIf(StringView S) {
2387 if (StringView(First, Last).startsWith(S)) {
2388 First += S.size();
2389 return true;
2390 }
2391 return false;
2392 }
2393
2394 bool consumeIf(char C) {
2395 if (First != Last && *First == C) {
2396 ++First;
2397 return true;
2398 }
2399 return false;
2400 }
2401
2402 char consume() { return First != Last ? *First++ : '\0'; }
2403
2404 char look(unsigned Lookahead = 0) {
2405 if (static_cast<size_t>(Last - First) <= Lookahead)
2406 return '\0';
2407 return First[Lookahead];
2408 }
2409
2410 size_t numLeft() const { return static_cast<size_t>(Last - First); }
2411
2412 StringView parseNumber(bool AllowNegative = false);
2413 Qualifiers parseCVQualifiers();
2414 bool parsePositiveInteger(size_t *Out);
2415 StringView parseBareSourceName();
2416
2417 bool parseSeqId(size_t *Out);
2418 Node *parseSubstitution();
2419 Node *parseTemplateParam();
2420 Node *parseTemplateParamDecl();
2421 Node *parseTemplateArgs(bool TagTemplates = false);
2422 Node *parseTemplateArg();
2423
2424 /// Parse the <expr> production.
2425 Node *parseExpr();
2426 Node *parsePrefixExpr(StringView Kind);
2427 Node *parseBinaryExpr(StringView Kind);
2428 Node *parseIntegerLiteral(StringView Lit);
2429 Node *parseExprPrimary();
2430 template <class Float> Node *parseFloatingLiteral();
2431 Node *parseFunctionParam();
2432 Node *parseNewExpr();
2433 Node *parseConversionExpr();
2434 Node *parseBracedExpr();
2435 Node *parseFoldExpr();
2436
2437 /// Parse the <type> production.
2438 Node *parseType();
2439 Node *parseFunctionType();
2440 Node *parseVectorType();
2441 Node *parseDecltype();
2442 Node *parseArrayType();
2443 Node *parsePointerToMemberType();
2444 Node *parseClassEnumType();
2445 Node *parseQualifiedType();
2446
2447 Node *parseEncoding();
2448 bool parseCallOffset();
2449 Node *parseSpecialName();
2450
2451 /// Holds some extra information about a <name> that is being parsed. This
2452 /// information is only pertinent if the <name> refers to an <encoding>.
2453 struct NameState {
2454 bool CtorDtorConversion = false;
2455 bool EndsWithTemplateArgs = false;
2456 Qualifiers CVQualifiers = QualNone;
2457 FunctionRefQual ReferenceQualifier = FrefQualNone;
2458 size_t ForwardTemplateRefsBegin;
2459
2460 NameState(AbstractManglingParser *Enclosing)
2461 : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
2462 };
2463
2464 bool resolveForwardTemplateRefs(NameState &State) {
2465 size_t I = State.ForwardTemplateRefsBegin;
2466 size_t E = ForwardTemplateRefs.size();
2467 for (; I < E; ++I) {
2468 size_t Idx = ForwardTemplateRefs[I]->Index;
2469 if (TemplateParams.empty() || !TemplateParams[0] ||
2470 Idx >= TemplateParams[0]->size())
2471 return true;
2472 ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
2473 }
2474 ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
2475 return false;
2476 }
2477
2478 /// Parse the <name> production>
2479 Node *parseName(NameState *State = nullptr);
2480 Node *parseLocalName(NameState *State);
2481 Node *parseOperatorName(NameState *State);
2482 Node *parseUnqualifiedName(NameState *State);
2483 Node *parseUnnamedTypeName(NameState *State);
2484 Node *parseSourceName(NameState *State);
2485 Node *parseUnscopedName(NameState *State);
2486 Node *parseNestedName(NameState *State);
2487 Node *parseCtorDtorName(Node *&SoFar, NameState *State);
2488
2489 Node *parseAbiTags(Node *N);
2490
2491 /// Parse the <unresolved-name> production.
2492 Node *parseUnresolvedName();
2493 Node *parseSimpleId();
2494 Node *parseBaseUnresolvedName();
2495 Node *parseUnresolvedType();
2496 Node *parseDestructorName();
2497
2498 /// Top-level entry point into the parser.
2499 Node *parse();
2500};
2501
2502const char* parse_discriminator(const char* first, const char* last);
2503
2504// <name> ::= <nested-name> // N
2505// ::= <local-name> # See Scope Encoding below // Z
2506// ::= <unscoped-template-name> <template-args>
2507// ::= <unscoped-name>
2508//
2509// <unscoped-template-name> ::= <unscoped-name>
2510// ::= <substitution>
2511template <typename Derived, typename Alloc>
2512Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) {
2513 consumeIf('L'); // extension
2514
2515 if (look() == 'N')
2516 return getDerived().parseNestedName(State);
2517 if (look() == 'Z')
2518 return getDerived().parseLocalName(State);
2519
2520 // ::= <unscoped-template-name> <template-args>
2521 if (look() == 'S' && look(1) != 't') {
2522 Node *S = getDerived().parseSubstitution();
2523 if (S == nullptr)
2524 return nullptr;
2525 if (look() != 'I')
2526 return nullptr;
2527 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
2528 if (TA == nullptr)
2529 return nullptr;
2530 if (State) State->EndsWithTemplateArgs = true;
2531 return make<NameWithTemplateArgs>(S, TA);
2532 }
2533
2534 Node *N = getDerived().parseUnscopedName(State);
2535 if (N == nullptr)
2536 return nullptr;
2537 // ::= <unscoped-template-name> <template-args>
2538 if (look() == 'I') {
2539 Subs.push_back(N);
2540 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
2541 if (TA == nullptr)
2542 return nullptr;
2543 if (State) State->EndsWithTemplateArgs = true;
2544 return make<NameWithTemplateArgs>(N, TA);
2545 }
2546 // ::= <unscoped-name>
2547 return N;
2548}
2549
2550// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
2551// := Z <function encoding> E s [<discriminator>]
2552// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
2553template <typename Derived, typename Alloc>
2554Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
2555 if (!consumeIf('Z'))
2556 return nullptr;
2557 Node *Encoding = getDerived().parseEncoding();
2558 if (Encoding == nullptr || !consumeIf('E'))
2559 return nullptr;
2560
2561 if (consumeIf('s')) {
2562 First = parse_discriminator(First, Last);
2563 auto *StringLitName = make<NameType>("string literal");
2564 if (!StringLitName)
2565 return nullptr;
2566 return make<LocalName>(Encoding, StringLitName);
2567 }
2568
2569 if (consumeIf('d')) {
2570 parseNumber(true);
2571 if (!consumeIf('_'))
2572 return nullptr;
2573 Node *N = getDerived().parseName(State);
2574 if (N == nullptr)
2575 return nullptr;
2576 return make<LocalName>(Encoding, N);
2577 }
2578
2579 Node *Entity = getDerived().parseName(State);
2580 if (Entity == nullptr)
2581 return nullptr;
2582 First = parse_discriminator(First, Last);
2583 return make<LocalName>(Encoding, Entity);
2584}
2585
2586// <unscoped-name> ::= <unqualified-name>
2587// ::= St <unqualified-name> # ::std::
2588// extension ::= StL<unqualified-name>
2589template <typename Derived, typename Alloc>
2590Node *
2591AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) {
2592 if (consumeIf("StL") || consumeIf("St")) {
2593 Node *R = getDerived().parseUnqualifiedName(State);
2594 if (R == nullptr)
2595 return nullptr;
2596 return make<StdQualifiedName>(R);
2597 }
2598 return getDerived().parseUnqualifiedName(State);
2599}
2600
2601// <unqualified-name> ::= <operator-name> [abi-tags]
2602// ::= <ctor-dtor-name>
2603// ::= <source-name>
2604// ::= <unnamed-type-name>
2605// ::= DC <source-name>+ E # structured binding declaration
2606template <typename Derived, typename Alloc>
2607Node *
2608AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
2609 // <ctor-dtor-name>s are special-cased in parseNestedName().
2610 Node *Result;
2611 if (look() == 'U')
2612 Result = getDerived().parseUnnamedTypeName(State);
2613 else if (look() >= '1' && look() <= '9')
2614 Result = getDerived().parseSourceName(State);
2615 else if (consumeIf("DC")) {
2616 size_t BindingsBegin = Names.size();
2617 do {
2618 Node *Binding = getDerived().parseSourceName(State);
2619 if (Binding == nullptr)
2620 return nullptr;
2621 Names.push_back(Binding);
2622 } while (!consumeIf('E'));
2623 Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
2624 } else
2625 Result = getDerived().parseOperatorName(State);
2626 if (Result != nullptr)
2627 Result = getDerived().parseAbiTags(Result);
2628 return Result;
2629}
2630
2631// <unnamed-type-name> ::= Ut [<nonnegative number>] _
2632// ::= <closure-type-name>
2633//
2634// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
2635//
2636// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
2637template <typename Derived, typename Alloc>
2638Node *
2639AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
2640 // <template-params> refer to the innermost <template-args>. Clear out any
2641 // outer args that we may have inserted into TemplateParams.
2642 if (State != nullptr)
2643 TemplateParams.clear();
2644
2645 if (consumeIf("Ut")) {
2646 StringView Count = parseNumber();
2647 if (!consumeIf('_'))
2648 return nullptr;
2649 return make<UnnamedTypeName>(Count);
2650 }
2651 if (consumeIf("Ul")) {
2652 SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel,
2653 TemplateParams.size());
2654 ScopedTemplateParamList LambdaTemplateParams(this);
2655
2656 size_t ParamsBegin = Names.size();
2657 while (look() == 'T' &&
2658 StringView("yptn").find(look(1)) != StringView::npos) {
2659 Node *T = parseTemplateParamDecl();
2660 if (!T)
2661 return nullptr;
2662 Names.push_back(T);
2663 }
2664 NodeArray TempParams = popTrailingNodeArray(ParamsBegin);
2665
2666 // FIXME: If TempParams is empty and none of the function parameters
2667 // includes 'auto', we should remove LambdaTemplateParams from the
2668 // TemplateParams list. Unfortunately, we don't find out whether there are
2669 // any 'auto' parameters until too late in an example such as:
2670 //
2671 // template<typename T> void f(
2672 // decltype([](decltype([]<typename T>(T v) {}),
2673 // auto) {})) {}
2674 // template<typename T> void f(
2675 // decltype([](decltype([]<typename T>(T w) {}),
2676 // int) {})) {}
2677 //
2678 // Here, the type of v is at level 2 but the type of w is at level 1. We
2679 // don't find this out until we encounter the type of the next parameter.
2680 //
2681 // However, compilers can't actually cope with the former example in
2682 // practice, and it's likely to be made ill-formed in future, so we don't
2683 // need to support it here.
2684 //
2685 // If we encounter an 'auto' in the function parameter types, we will
2686 // recreate a template parameter scope for it, but any intervening lambdas
2687 // will be parsed in the 'wrong' template parameter depth.
2688 if (TempParams.empty())
2689 TemplateParams.pop_back();
2690
2691 if (!consumeIf("vE")) {
2692 do {
2693 Node *P = getDerived().parseType();
2694 if (P == nullptr)
2695 return nullptr;
2696 Names.push_back(P);
2697 } while (!consumeIf('E'));
2698 }
2699 NodeArray Params = popTrailingNodeArray(ParamsBegin);
2700
2701 StringView Count = parseNumber();
2702 if (!consumeIf('_'))
2703 return nullptr;
2704 return make<ClosureTypeName>(TempParams, Params, Count);
2705 }
2706 if (consumeIf("Ub")) {
2707 (void)parseNumber();
2708 if (!consumeIf('_'))
2709 return nullptr;
2710 return make<NameType>("'block-literal'");
2711 }
2712 return nullptr;
2713}
2714
2715// <source-name> ::= <positive length number> <identifier>
2716template <typename Derived, typename Alloc>
2717Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
2718 size_t Length = 0;
2719 if (parsePositiveInteger(&Length))
2720 return nullptr;
2721 if (numLeft() < Length || Length == 0)
2722 return nullptr;
2723 StringView Name(First, First + Length);
2724 First += Length;
2725 if (Name.startsWith("_GLOBAL__N"))
2726 return make<NameType>("(anonymous namespace)");
2727 return make<NameType>(Name);
2728}
2729
2730// <operator-name> ::= aa # &&
2731// ::= ad # & (unary)
2732// ::= an # &
2733// ::= aN # &=
2734// ::= aS # =
2735// ::= cl # ()
2736// ::= cm # ,
2737// ::= co # ~
2738// ::= cv <type> # (cast)
2739// ::= da # delete[]
2740// ::= de # * (unary)
2741// ::= dl # delete
2742// ::= dv # /
2743// ::= dV # /=
2744// ::= eo # ^
2745// ::= eO # ^=
2746// ::= eq # ==
2747// ::= ge # >=
2748// ::= gt # >
2749// ::= ix # []
2750// ::= le # <=
2751// ::= li <source-name> # operator ""
2752// ::= ls # <<
2753// ::= lS # <<=
2754// ::= lt # <
2755// ::= mi # -
2756// ::= mI # -=
2757// ::= ml # *
2758// ::= mL # *=
2759// ::= mm # -- (postfix in <expression> context)
2760// ::= na # new[]
2761// ::= ne # !=
2762// ::= ng # - (unary)
2763// ::= nt # !
2764// ::= nw # new
2765// ::= oo # ||
2766// ::= or # |
2767// ::= oR # |=
2768// ::= pm # ->*
2769// ::= pl # +
2770// ::= pL # +=
2771// ::= pp # ++ (postfix in <expression> context)
2772// ::= ps # + (unary)
2773// ::= pt # ->
2774// ::= qu # ?
2775// ::= rm # %
2776// ::= rM # %=
2777// ::= rs # >>
2778// ::= rS # >>=
2779// ::= ss # <=> C++2a
2780// ::= v <digit> <source-name> # vendor extended operator
2781template <typename Derived, typename Alloc>
2782Node *
2783AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
2784 switch (look()) {
2785 case 'a':
2786 switch (look(1)) {
2787 case 'a':
2788 First += 2;
2789 return make<NameType>("operator&&");
2790 case 'd':
2791 case 'n':
2792 First += 2;
2793 return make<NameType>("operator&");
2794 case 'N':
2795 First += 2;
2796 return make<NameType>("operator&=");
2797 case 'S':
2798 First += 2;
2799 return make<NameType>("operator=");
2800 }
2801 return nullptr;
2802 case 'c':
2803 switch (look(1)) {
2804 case 'l':
2805 First += 2;
2806 return make<NameType>("operator()");
2807 case 'm':
2808 First += 2;
2809 return make<NameType>("operator,");
2810 case 'o':
2811 First += 2;
2812 return make<NameType>("operator~");
2813 // ::= cv <type> # (cast)
2814 case 'v': {
2815 First += 2;
2816 SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
2817 // If we're parsing an encoding, State != nullptr and the conversion
2818 // operators' <type> could have a <template-param> that refers to some
2819 // <template-arg>s further ahead in the mangled name.
2820 SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
2821 PermitForwardTemplateReferences ||
2822 State != nullptr);
2823 Node *Ty = getDerived().parseType();
2824 if (Ty == nullptr)
2825 return nullptr;
2826 if (State) State->CtorDtorConversion = true;
2827 return make<ConversionOperatorType>(Ty);
2828 }
2829 }
2830 return nullptr;
2831 case 'd':
2832 switch (look(1)) {
2833 case 'a':
2834 First += 2;
2835 return make<NameType>("operator delete[]");
2836 case 'e':
2837 First += 2;
2838 return make<NameType>("operator*");
2839 case 'l':
2840 First += 2;
2841 return make<NameType>("operator delete");
2842 case 'v':
2843 First += 2;
2844 return make<NameType>("operator/");
2845 case 'V':
2846 First += 2;
2847 return make<NameType>("operator/=");
2848 }
2849 return nullptr;
2850 case 'e':
2851 switch (look(1)) {
2852 case 'o':
2853 First += 2;
2854 return make<NameType>("operator^");
2855 case 'O':
2856 First += 2;
2857 return make<NameType>("operator^=");
2858 case 'q':
2859 First += 2;
2860 return make<NameType>("operator==");
2861 }
2862 return nullptr;
2863 case 'g':
2864 switch (look(1)) {
2865 case 'e':
2866 First += 2;
2867 return make<NameType>("operator>=");
2868 case 't':
2869 First += 2;
2870 return make<NameType>("operator>");
2871 }
2872 return nullptr;
2873 case 'i':
2874 if (look(1) == 'x') {
2875 First += 2;
2876 return make<NameType>("operator[]");
2877 }
2878 return nullptr;
2879 case 'l':
2880 switch (look(1)) {
2881 case 'e':
2882 First += 2;
2883 return make<NameType>("operator<=");
2884 // ::= li <source-name> # operator ""
2885 case 'i': {
2886 First += 2;
2887 Node *SN = getDerived().parseSourceName(State);
2888 if (SN == nullptr)
2889 return nullptr;
2890 return make<LiteralOperator>(SN);
2891 }
2892 case 's':
2893 First += 2;
2894 return make<NameType>("operator<<");
2895 case 'S':
2896 First += 2;
2897 return make<NameType>("operator<<=");
2898 case 't':
2899 First += 2;
2900 return make<NameType>("operator<");
2901 }
2902 return nullptr;
2903 case 'm':
2904 switch (look(1)) {
2905 case 'i':
2906 First += 2;
2907 return make<NameType>("operator-");
2908 case 'I':
2909 First += 2;
2910 return make<NameType>("operator-=");
2911 case 'l':
2912 First += 2;
2913 return make<NameType>("operator*");
2914 case 'L':
2915 First += 2;
2916 return make<NameType>("operator*=");
2917 case 'm':
2918 First += 2;
2919 return make<NameType>("operator--");
2920 }
2921 return nullptr;
2922 case 'n':
2923 switch (look(1)) {
2924 case 'a':
2925 First += 2;
2926 return make<NameType>("operator new[]");
2927 case 'e':
2928 First += 2;
2929 return make<NameType>("operator!=");
2930 case 'g':
2931 First += 2;
2932 return make<NameType>("operator-");
2933 case 't':
2934 First += 2;
2935 return make<NameType>("operator!");
2936 case 'w':
2937 First += 2;
2938 return make<NameType>("operator new");
2939 }
2940 return nullptr;
2941 case 'o':
2942 switch (look(1)) {
2943 case 'o':
2944 First += 2;
2945 return make<NameType>("operator||");
2946 case 'r':
2947 First += 2;
2948 return make<NameType>("operator|");
2949 case 'R':
2950 First += 2;
2951 return make<NameType>("operator|=");
2952 }
2953 return nullptr;
2954 case 'p':
2955 switch (look(1)) {
2956 case 'm':
2957 First += 2;
2958 return make<NameType>("operator->*");
2959 case 'l':
2960 First += 2;
2961 return make<NameType>("operator+");
2962 case 'L':
2963 First += 2;
2964 return make<NameType>("operator+=");
2965 case 'p':
2966 First += 2;
2967 return make<NameType>("operator++");
2968 case 's':
2969 First += 2;
2970 return make<NameType>("operator+");
2971 case 't':
2972 First += 2;
2973 return make<NameType>("operator->");
2974 }
2975 return nullptr;
2976 case 'q':
2977 if (look(1) == 'u') {
2978 First += 2;
2979 return make<NameType>("operator?");
2980 }
2981 return nullptr;
2982 case 'r':
2983 switch (look(1)) {
2984 case 'm':
2985 First += 2;
2986 return make<NameType>("operator%");
2987 case 'M':
2988 First += 2;
2989 return make<NameType>("operator%=");
2990 case 's':
2991 First += 2;
2992 return make<NameType>("operator>>");
2993 case 'S':
2994 First += 2;
2995 return make<NameType>("operator>>=");
2996 }
2997 return nullptr;
2998 case 's':
2999 if (look(1) == 's') {
3000 First += 2;
3001 return make<NameType>("operator<=>");
3002 }
3003 return nullptr;
3004 // ::= v <digit> <source-name> # vendor extended operator
3005 case 'v':
3006 if (std::isdigit(look(1))) {
3007 First += 2;
3008 Node *SN = getDerived().parseSourceName(State);
3009 if (SN == nullptr)
3010 return nullptr;
3011 return make<ConversionOperatorType>(SN);
3012 }
3013 return nullptr;
3014 }
3015 return nullptr;
3016}
3017
3018// <ctor-dtor-name> ::= C1 # complete object constructor
3019// ::= C2 # base object constructor
3020// ::= C3 # complete object allocating constructor
3021// extension ::= C4 # gcc old-style "[unified]" constructor
3022// extension ::= C5 # the COMDAT used for ctors
3023// ::= D0 # deleting destructor
3024// ::= D1 # complete object destructor
3025// ::= D2 # base object destructor
3026// extension ::= D4 # gcc old-style "[unified]" destructor
3027// extension ::= D5 # the COMDAT used for dtors
3028template <typename Derived, typename Alloc>
3029Node *
3030AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
3031 NameState *State) {
3032 if (SoFar->getKind() == Node::KSpecialSubstitution) {
3033 auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
3034 switch (SSK) {
3035 case SpecialSubKind::string:
3036 case SpecialSubKind::istream:
3037 case SpecialSubKind::ostream:
3038 case SpecialSubKind::iostream:
3039 SoFar = make<ExpandedSpecialSubstitution>(SSK);
3040 if (!SoFar)
3041 return nullptr;
3042 break;
3043 default:
3044 break;
3045 }
3046 }
3047
3048 if (consumeIf('C')) {
3049 bool IsInherited = consumeIf('I');
3050 if (look() != '1' && look() != '2' && look() != '3' && look() != '4' &&
3051 look() != '5')
3052 return nullptr;
3053 int Variant = look() - '0';
3054 ++First;
3055 if (State) State->CtorDtorConversion = true;
3056 if (IsInherited) {
3057 if (getDerived().parseName(State) == nullptr)
3058 return nullptr;
3059 }
3060 return make<CtorDtorName>(SoFar, /*IsDtor=*/false, Variant);
3061 }
3062
3063 if (look() == 'D' && (look(1) == '0' || look(1) == '1' || look(1) == '2' ||
3064 look(1) == '4' || look(1) == '5')) {
3065 int Variant = look(1) - '0';
3066 First += 2;
3067 if (State) State->CtorDtorConversion = true;
3068 return make<CtorDtorName>(SoFar, /*IsDtor=*/true, Variant);
3069 }
3070
3071 return nullptr;
3072}
3073
3074// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
3075// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
3076//
3077// <prefix> ::= <prefix> <unqualified-name>
3078// ::= <template-prefix> <template-args>
3079// ::= <template-param>
3080// ::= <decltype>
3081// ::= # empty
3082// ::= <substitution>
3083// ::= <prefix> <data-member-prefix>
3084// extension ::= L
3085//
3086// <data-member-prefix> := <member source-name> [<template-args>] M
3087//
3088// <template-prefix> ::= <prefix> <template unqualified-name>
3089// ::= <template-param>
3090// ::= <substitution>
3091template <typename Derived, typename Alloc>
3092Node *
3093AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
3094 if (!consumeIf('N'))
3095 return nullptr;
3096
3097 Qualifiers CVTmp = parseCVQualifiers();
3098 if (State) State->CVQualifiers = CVTmp;
3099
3100 if (consumeIf('O')) {
3101 if (State) State->ReferenceQualifier = FrefQualRValue;
3102 } else if (consumeIf('R')) {
3103 if (State) State->ReferenceQualifier = FrefQualLValue;
3104 } else
3105 if (State) State->ReferenceQualifier = FrefQualNone;
3106
3107 Node *SoFar = nullptr;
3108 auto PushComponent = [&](Node *Comp) {
3109 if (!Comp) return false;
3110 if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
3111 else SoFar = Comp;
3112 if (State) State->EndsWithTemplateArgs = false;
3113 return SoFar != nullptr;
3114 };
3115
3116 if (consumeIf("St")) {
3117 SoFar = make<NameType>("std");
3118 if (!SoFar)
3119 return nullptr;
3120 }
3121
3122 while (!consumeIf('E')) {
3123 consumeIf('L'); // extension
3124
3125 // <data-member-prefix> := <member source-name> [<template-args>] M
3126 if (consumeIf('M')) {
3127 if (SoFar == nullptr)
3128 return nullptr;
3129 continue;
3130 }
3131
3132 // ::= <template-param>
3133 if (look() == 'T') {
3134 if (!PushComponent(getDerived().parseTemplateParam()))
3135 return nullptr;
3136 Subs.push_back(SoFar);
3137 continue;
3138 }
3139
3140 // ::= <template-prefix> <template-args>
3141 if (look() == 'I') {
3142 Node *TA = getDerived().parseTemplateArgs(State != nullptr);
3143 if (TA == nullptr || SoFar == nullptr)
3144 return nullptr;
3145 SoFar = make<NameWithTemplateArgs>(SoFar, TA);
3146 if (!SoFar)
3147 return nullptr;
3148 if (State) State->EndsWithTemplateArgs = true;
3149 Subs.push_back(SoFar);
3150 continue;
3151 }
3152
3153 // ::= <decltype>
3154 if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
3155 if (!PushComponent(getDerived().parseDecltype()))
3156 return nullptr;
3157 Subs.push_back(SoFar);
3158 continue;
3159 }
3160
3161 // ::= <substitution>
3162 if (look() == 'S' && look(1) != 't') {
3163 Node *S = getDerived().parseSubstitution();
3164 if (!PushComponent(S))
3165 return nullptr;
3166 if (SoFar != S)
3167 Subs.push_back(S);
3168 continue;
3169 }
3170
3171 // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
3172 if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
3173 if (SoFar == nullptr)
3174 return nullptr;
3175 if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
3176 return nullptr;
3177 SoFar = getDerived().parseAbiTags(SoFar);
3178 if (SoFar == nullptr)
3179 return nullptr;
3180 Subs.push_back(SoFar);
3181 continue;
3182 }
3183
3184 // ::= <prefix> <unqualified-name>
3185 if (!PushComponent(getDerived().parseUnqualifiedName(State)))
3186 return nullptr;
3187 Subs.push_back(SoFar);
3188 }
3189
3190 if (SoFar == nullptr || Subs.empty())
3191 return nullptr;
3192
3193 Subs.pop_back();
3194 return SoFar;
3195}
3196
3197// <simple-id> ::= <source-name> [ <template-args> ]
3198template <typename Derived, typename Alloc>
3199Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() {
3200 Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr);
3201 if (SN == nullptr)
3202 return nullptr;
3203 if (look() == 'I') {
3204 Node *TA = getDerived().parseTemplateArgs();
3205 if (TA == nullptr)
3206 return nullptr;
3207 return make<NameWithTemplateArgs>(SN, TA);
3208 }
3209 return SN;
3210}
3211
3212// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
3213// ::= <simple-id> # e.g., ~A<2*N>
3214template <typename Derived, typename Alloc>
3215Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() {
3216 Node *Result;
3217 if (std::isdigit(look()))
3218 Result = getDerived().parseSimpleId();
3219 else
3220 Result = getDerived().parseUnresolvedType();
3221 if (Result == nullptr)
3222 return nullptr;
3223 return make<DtorName>(Result);
3224}
3225
3226// <unresolved-type> ::= <template-param>
3227// ::= <decltype>
3228// ::= <substitution>
3229template <typename Derived, typename Alloc>
3230Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() {
3231 if (look() == 'T') {
3232 Node *TP = getDerived().parseTemplateParam();
3233 if (TP == nullptr)
3234 return nullptr;
3235 Subs.push_back(TP);
3236 return TP;
3237 }
3238 if (look() == 'D') {
3239 Node *DT = getDerived().parseDecltype();
3240 if (DT == nullptr)
3241 return nullptr;
3242 Subs.push_back(DT);
3243 return DT;
3244 }
3245 return getDerived().parseSubstitution();
3246}
3247
3248// <base-unresolved-name> ::= <simple-id> # unresolved name
3249// extension ::= <operator-name> # unresolved operator-function-id
3250// extension ::= <operator-name> <template-args> # unresolved operator template-id
3251// ::= on <operator-name> # unresolved operator-function-id
3252// ::= on <operator-name> <template-args> # unresolved operator template-id
3253// ::= dn <destructor-name> # destructor or pseudo-destructor;
3254// # e.g. ~X or ~X<N-1>
3255template <typename Derived, typename Alloc>
3256Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
3257 if (std::isdigit(look()))
3258 return getDerived().parseSimpleId();
3259
3260 if (consumeIf("dn"))
3261 return getDerived().parseDestructorName();
3262
3263 consumeIf("on");
3264
3265 Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr);
3266 if (Oper == nullptr)
3267 return nullptr;
3268 if (look() == 'I') {
3269 Node *TA = getDerived().parseTemplateArgs();
3270 if (TA == nullptr)
3271 return nullptr;
3272 return make<NameWithTemplateArgs>(Oper, TA);
3273 }
3274 return Oper;
3275}
3276
3277// <unresolved-name>
3278// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
3279// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
3280// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
3281// # A::x, N::y, A<T>::z; "gs" means leading "::"
3282// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
3283// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
3284// # T::N::x /decltype(p)::N::x
3285// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
3286//
3287// <unresolved-qualifier-level> ::= <simple-id>
3288template <typename Derived, typename Alloc>
3289Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
3290 Node *SoFar = nullptr;
3291
3292 // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
3293 // srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
3294 if (consumeIf("srN")) {
3295 SoFar = getDerived().parseUnresolvedType();
3296 if (SoFar == nullptr)
3297 return nullptr;
3298
3299 if (look() == 'I') {
3300 Node *TA = getDerived().parseTemplateArgs();
3301 if (TA == nullptr)
3302 return nullptr;
3303 SoFar = make<NameWithTemplateArgs>(SoFar, TA);
3304 if (!SoFar)
3305 return nullptr;
3306 }
3307
3308 while (!consumeIf('E')) {
3309 Node *Qual = getDerived().parseSimpleId();
3310 if (Qual == nullptr)
3311 return nullptr;
3312 SoFar = make<QualifiedName>(SoFar, Qual);
3313 if (!SoFar)
3314 return nullptr;
3315 }
3316
3317 Node *Base = getDerived().parseBaseUnresolvedName();
3318 if (Base == nullptr)
3319 return nullptr;
3320 return make<QualifiedName>(SoFar, Base);
3321 }
3322
3323 bool Global = consumeIf("gs");
3324
3325 // [gs] <base-unresolved-name> # x or (with "gs") ::x
3326 if (!consumeIf("sr")) {
3327 SoFar = getDerived().parseBaseUnresolvedName();
3328 if (SoFar == nullptr)
3329 return nullptr;
3330 if (Global)
3331 SoFar = make<GlobalQualifiedName>(SoFar);
3332 return SoFar;
3333 }
3334
3335 // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
3336 if (std::isdigit(look())) {
3337 do {
3338 Node *Qual = getDerived().parseSimpleId();
3339 if (Qual == nullptr)
3340 return nullptr;
3341 if (SoFar)
3342 SoFar = make<QualifiedName>(SoFar, Qual);
3343 else if (Global)
3344 SoFar = make<GlobalQualifiedName>(Qual);
3345 else
3346 SoFar = Qual;
3347 if (!SoFar)
3348 return nullptr;
3349 } while (!consumeIf('E'));
3350 }
3351 // sr <unresolved-type> <base-unresolved-name>
3352 // sr <unresolved-type> <template-args> <base-unresolved-name>
3353 else {
3354 SoFar = getDerived().parseUnresolvedType();
3355 if (SoFar == nullptr)
3356 return nullptr;
3357
3358 if (look() == 'I') {
3359 Node *TA = getDerived().parseTemplateArgs();
3360 if (TA == nullptr)
3361 return nullptr;
3362 SoFar = make<NameWithTemplateArgs>(SoFar, TA);
3363 if (!SoFar)
3364 return nullptr;
3365 }
3366 }
3367
3368 assert(SoFar != nullptr);
3369
3370 Node *Base = getDerived().parseBaseUnresolvedName();
3371 if (Base == nullptr)
3372 return nullptr;
3373 return make<QualifiedName>(SoFar, Base);
3374}
3375
3376// <abi-tags> ::= <abi-tag> [<abi-tags>]
3377// <abi-tag> ::= B <source-name>
3378template <typename Derived, typename Alloc>
3379Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) {
3380 while (consumeIf('B')) {
3381 StringView SN = parseBareSourceName();
3382 if (SN.empty())
3383 return nullptr;
3384 N = make<AbiTagAttr>(N, SN);
3385 if (!N)
3386 return nullptr;
3387 }
3388 return N;
3389}
3390
3391// <number> ::= [n] <non-negative decimal integer>
3392template <typename Alloc, typename Derived>
3393StringView
3394AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) {
3395 const char *Tmp = First;
3396 if (AllowNegative)
3397 consumeIf('n');
3398 if (numLeft() == 0 || !std::isdigit(*First))
3399 return StringView();
3400 while (numLeft() != 0 && std::isdigit(*First))
3401 ++First;
3402 return StringView(Tmp, First);
3403}
3404
3405// <positive length number> ::= [0-9]*
3406template <typename Alloc, typename Derived>
3407bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) {
3408 *Out = 0;
3409 if (look() < '0' || look() > '9')
3410 return true;
3411 while (look() >= '0' && look() <= '9') {
3412 *Out *= 10;
3413 *Out += static_cast<size_t>(consume() - '0');
3414 }
3415 return false;
3416}
3417
3418template <typename Alloc, typename Derived>
3419StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() {
3420 size_t Int = 0;
3421 if (parsePositiveInteger(&Int) || numLeft() < Int)
3422 return StringView();
3423 StringView R(First, First + Int);
3424 First += Int;
3425 return R;
3426}
3427
3428// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
3429//
3430// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
3431// ::= DO <expression> E # computed (instantiation-dependent) noexcept
3432// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types
3433//
3434// <ref-qualifier> ::= R # & ref-qualifier
3435// <ref-qualifier> ::= O # && ref-qualifier
3436template <typename Derived, typename Alloc>
3437Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() {
3438 Qualifiers CVQuals = parseCVQualifiers();
3439
3440 Node *ExceptionSpec = nullptr;
3441 if (consumeIf("Do")) {
3442 ExceptionSpec = make<NameType>("noexcept");
3443 if (!ExceptionSpec)
3444 return nullptr;
3445 } else if (consumeIf("DO")) {
3446 Node *E = getDerived().parseExpr();
3447 if (E == nullptr || !consumeIf('E'))
3448 return nullptr;
3449 ExceptionSpec = make<NoexceptSpec>(E);
3450 if (!ExceptionSpec)
3451 return nullptr;
3452 } else if (consumeIf("Dw")) {
3453 size_t SpecsBegin = Names.size();
3454 while (!consumeIf('E')) {
3455 Node *T = getDerived().parseType();
3456 if (T == nullptr)
3457 return nullptr;
3458 Names.push_back(T);
3459 }
3460 ExceptionSpec =
3461 make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
3462 if (!ExceptionSpec)
3463 return nullptr;
3464 }
3465
3466 consumeIf("Dx"); // transaction safe
3467
3468 if (!consumeIf('F'))
3469 return nullptr;
3470 consumeIf('Y'); // extern "C"
3471 Node *ReturnType = getDerived().parseType();
3472 if (ReturnType == nullptr)
3473 return nullptr;
3474
3475 FunctionRefQual ReferenceQualifier = FrefQualNone;
3476 size_t ParamsBegin = Names.size();
3477 while (true) {
3478 if (consumeIf('E'))
3479 break;
3480 if (consumeIf('v'))
3481 continue;
3482 if (consumeIf("RE")) {
3483 ReferenceQualifier = FrefQualLValue;
3484 break;
3485 }
3486 if (consumeIf("OE")) {
3487 ReferenceQualifier = FrefQualRValue;
3488 break;
3489 }
3490 Node *T = getDerived().parseType();
3491 if (T == nullptr)
3492 return nullptr;
3493 Names.push_back(T);
3494 }
3495
3496 NodeArray Params = popTrailingNodeArray(ParamsBegin);
3497 return make<FunctionType>(ReturnType, Params, CVQuals,
3498 ReferenceQualifier, ExceptionSpec);
3499}
3500
3501// extension:
3502// <vector-type> ::= Dv <positive dimension number> _ <extended element type>
3503// ::= Dv [<dimension expression>] _ <element type>
3504// <extended element type> ::= <element type>
3505// ::= p # AltiVec vector pixel
3506template <typename Derived, typename Alloc>
3507Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() {
3508 if (!consumeIf("Dv"))
3509 return nullptr;
3510 if (look() >= '1' && look() <= '9') {
3511 Node *DimensionNumber = make<NameType>(parseNumber());
3512 if (!DimensionNumber)
3513 return nullptr;
3514 if (!consumeIf('_'))
3515 return nullptr;
3516 if (consumeIf('p'))
3517 return make<PixelVectorType>(DimensionNumber);
3518 Node *ElemType = getDerived().parseType();
3519 if (ElemType == nullptr)
3520 return nullptr;
3521 return make<VectorType>(ElemType, DimensionNumber);
3522 }
3523
3524 if (!consumeIf('_')) {
3525 Node *DimExpr = getDerived().parseExpr();
3526 if (!DimExpr)
3527 return nullptr;
3528 if (!consumeIf('_'))
3529 return nullptr;
3530 Node *ElemType = getDerived().parseType();
3531 if (!ElemType)
3532 return nullptr;
3533 return make<VectorType>(ElemType, DimExpr);
3534 }
3535 Node *ElemType = getDerived().parseType();
3536 if (!ElemType)
3537 return nullptr;
3538 return make<VectorType>(ElemType, /*Dimension=*/nullptr);
3539}
3540
3541// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
3542// ::= DT <expression> E # decltype of an expression (C++0x)
3543template <typename Derived, typename Alloc>
3544Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() {
3545 if (!consumeIf('D'))
3546 return nullptr;
3547 if (!consumeIf('t') && !consumeIf('T'))
3548 return nullptr;
3549 Node *E = getDerived().parseExpr();
3550 if (E == nullptr)
3551 return nullptr;
3552 if (!consumeIf('E'))
3553 return nullptr;
3554 return make<EnclosingExpr>("decltype(", E, ")");
3555}
3556
3557// <array-type> ::= A <positive dimension number> _ <element type>
3558// ::= A [<dimension expression>] _ <element type>
3559template <typename Derived, typename Alloc>
3560Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() {
3561 if (!consumeIf('A'))
3562 return nullptr;
3563
3564 Node *Dimension = nullptr;
3565
3566 if (std::isdigit(look())) {
3567 Dimension = make<NameType>(parseNumber());
3568 if (!Dimension)
3569 return nullptr;
3570 if (!consumeIf('_'))
3571 return nullptr;
3572 } else if (!consumeIf('_')) {
3573 Node *DimExpr = getDerived().parseExpr();
3574 if (DimExpr == nullptr)
3575 return nullptr;
3576 if (!consumeIf('_'))
3577 return nullptr;
3578 Dimension = DimExpr;
3579 }
3580
3581 Node *Ty = getDerived().parseType();
3582 if (Ty == nullptr)
3583 return nullptr;
3584 return make<ArrayType>(Ty, Dimension);
3585}
3586
3587// <pointer-to-member-type> ::= M <class type> <member type>
3588template <typename Derived, typename Alloc>
3589Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() {
3590 if (!consumeIf('M'))
3591 return nullptr;
3592 Node *ClassType = getDerived().parseType();
3593 if (ClassType == nullptr)
3594 return nullptr;
3595 Node *MemberType = getDerived().parseType();
3596 if (MemberType == nullptr)
3597 return nullptr;
3598 return make<PointerToMemberType>(ClassType, MemberType);
3599}
3600
3601// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier
3602// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class'
3603// ::= Tu <name> # dependent elaborated type specifier using 'union'
3604// ::= Te <name> # dependent elaborated type specifier using 'enum'
3605template <typename Derived, typename Alloc>
3606Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() {
3607 StringView ElabSpef;
3608 if (consumeIf("Ts"))
3609 ElabSpef = "struct";
3610 else if (consumeIf("Tu"))
3611 ElabSpef = "union";
3612 else if (consumeIf("Te"))
3613 ElabSpef = "enum";
3614
3615 Node *Name = getDerived().parseName();
3616 if (Name == nullptr)
3617 return nullptr;
3618
3619 if (!ElabSpef.empty())
3620 return make<ElaboratedTypeSpefType>(ElabSpef, Name);
3621
3622 return Name;
3623}
3624
3625// <qualified-type> ::= <qualifiers> <type>
3626// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
3627// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
3628template <typename Derived, typename Alloc>
3629Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
3630 if (consumeIf('U')) {
3631 StringView Qual = parseBareSourceName();
3632 if (Qual.empty())
3633 return nullptr;
3634
3635 // FIXME parse the optional <template-args> here!
3636
3637 // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
3638 if (Qual.startsWith("objcproto")) {
3639 StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
3640 StringView Proto;
3641 {
3642 SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
3643 SaveLast(Last, ProtoSourceName.end());
3644 Proto = parseBareSourceName();
3645 }
3646 if (Proto.empty())
3647 return nullptr;
3648 Node *Child = getDerived().parseQualifiedType();
3649 if (Child == nullptr)
3650 return nullptr;
3651 return make<ObjCProtoName>(Child, Proto);
3652 }
3653
3654 Node *Child = getDerived().parseQualifiedType();
3655 if (Child == nullptr)
3656 return nullptr;
3657 return make<VendorExtQualType>(Child, Qual);
3658 }
3659
3660 Qualifiers Quals = parseCVQualifiers();
3661 Node *Ty = getDerived().parseType();
3662 if (Ty == nullptr)
3663 return nullptr;
3664 if (Quals != QualNone)
3665 Ty = make<QualType>(Ty, Quals);
3666 return Ty;
3667}
3668
3669// <type> ::= <builtin-type>
3670// ::= <qualified-type>
3671// ::= <function-type>
3672// ::= <class-enum-type>
3673// ::= <array-type>
3674// ::= <pointer-to-member-type>
3675// ::= <template-param>
3676// ::= <template-template-param> <template-args>
3677// ::= <decltype>
3678// ::= P <type> # pointer
3679// ::= R <type> # l-value reference
3680// ::= O <type> # r-value reference (C++11)
3681// ::= C <type> # complex pair (C99)
3682// ::= G <type> # imaginary (C99)
3683// ::= <substitution> # See Compression below
3684// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
3685// extension ::= <vector-type> # <vector-type> starts with Dv
3686//
3687// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
3688// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
3689template <typename Derived, typename Alloc>
3690Node *AbstractManglingParser<Derived, Alloc>::parseType() {
3691 Node *Result = nullptr;
3692
3693 switch (look()) {
3694 // ::= <qualified-type>
3695 case 'r':
3696 case 'V':
3697 case 'K': {
3698 unsigned AfterQuals = 0;
3699 if (look(AfterQuals) == 'r') ++AfterQuals;
3700 if (look(AfterQuals) == 'V') ++AfterQuals;
3701 if (look(AfterQuals) == 'K') ++AfterQuals;
3702
3703 if (look(AfterQuals) == 'F' ||
3704 (look(AfterQuals) == 'D' &&
3705 (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
3706 look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
3707 Result = getDerived().parseFunctionType();
3708 break;
3709 }
3710 DEMANGLE_FALLTHROUGH;
3711 }
3712 case 'U': {
3713 Result = getDerived().parseQualifiedType();
3714 break;
3715 }
3716 // <builtin-type> ::= v # void
3717 case 'v':
3718 ++First;
3719 return make<NameType>("void");
3720 // ::= w # wchar_t
3721 case 'w':
3722 ++First;
3723 return make<NameType>("wchar_t");
3724 // ::= b # bool
3725 case 'b':
3726 ++First;
3727 return make<NameType>("bool");
3728 // ::= c # char
3729 case 'c':
3730 ++First;
3731 return make<NameType>("char");
3732 // ::= a # signed char
3733 case 'a':
3734 ++First;
3735 return make<NameType>("signed char");
3736 // ::= h # unsigned char
3737 case 'h':
3738 ++First;
3739 return make<NameType>("unsigned char");
3740 // ::= s # short
3741 case 's':
3742 ++First;
3743 return make<NameType>("short");
3744 // ::= t # unsigned short
3745 case 't':
3746 ++First;
3747 return make<NameType>("unsigned short");
3748 // ::= i # int
3749 case 'i':
3750 ++First;
3751 return make<NameType>("int");
3752 // ::= j # unsigned int
3753 case 'j':
3754 ++First;
3755 return make<NameType>("unsigned int");
3756 // ::= l # long
3757 case 'l':
3758 ++First;
3759 return make<NameType>("long");
3760 // ::= m # unsigned long
3761 case 'm':
3762 ++First;
3763 return make<NameType>("unsigned long");
3764 // ::= x # long long, __int64
3765 case 'x':
3766 ++First;
3767 return make<NameType>("long long");
3768 // ::= y # unsigned long long, __int64
3769 case 'y':
3770 ++First;
3771 return make<NameType>("unsigned long long");
3772 // ::= n # __int128
3773 case 'n':
3774 ++First;
3775 return make<NameType>("__int128");
3776 // ::= o # unsigned __int128
3777 case 'o':
3778 ++First;
3779 return make<NameType>("unsigned __int128");
3780 // ::= f # float
3781 case 'f':
3782 ++First;
3783 return make<NameType>("float");
3784 // ::= d # double
3785 case 'd':
3786 ++First;
3787 return make<NameType>("double");
3788 // ::= e # long double, __float80
3789 case 'e':
3790 ++First;
3791 return make<NameType>("long double");
3792 // ::= g # __float128
3793 case 'g':
3794 ++First;
3795 return make<NameType>("__float128");
3796 // ::= z # ellipsis
3797 case 'z':
3798 ++First;
3799 return make<NameType>("...");
3800
3801 // <builtin-type> ::= u <source-name> # vendor extended type
3802 case 'u': {
3803 ++First;
3804 StringView Res = parseBareSourceName();
3805 if (Res.empty())
3806 return nullptr;
3807 // Typically, <builtin-type>s are not considered substitution candidates,
3808 // but the exception to that exception is vendor extended types (Itanium C++
3809 // ABI 5.9.1).
3810 Result = make<NameType>(Res);
3811 break;
3812 }
3813 case 'D':
3814 switch (look(1)) {
3815 // ::= Dd # IEEE 754r decimal floating point (64 bits)
3816 case 'd':
3817 First += 2;
3818 return make<NameType>("decimal64");
3819 // ::= De # IEEE 754r decimal floating point (128 bits)
3820 case 'e':
3821 First += 2;
3822 return make<NameType>("decimal128");
3823 // ::= Df # IEEE 754r decimal floating point (32 bits)
3824 case 'f':
3825 First += 2;
3826 return make<NameType>("decimal32");
3827 // ::= Dh # IEEE 754r half-precision floating point (16 bits)
3828 case 'h':
3829 First += 2;
3830 return make<NameType>("decimal16");
3831 // ::= Di # char32_t
3832 case 'i':
3833 First += 2;
3834 return make<NameType>("char32_t");
3835 // ::= Ds # char16_t
3836 case 's':
3837 First += 2;
3838 return make<NameType>("char16_t");
3839 // ::= Du # char8_t (C++2a, not yet in the Itanium spec)
3840 case 'u':
3841 First += 2;
3842 return make<NameType>("char8_t");
3843 // ::= Da # auto (in dependent new-expressions)
3844 case 'a':
3845 First += 2;
3846 return make<NameType>("auto");
3847 // ::= Dc # decltype(auto)
3848 case 'c':
3849 First += 2;
3850 return make<NameType>("decltype(auto)");
3851 // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
3852 case 'n':
3853 First += 2;
3854 return make<NameType>("std::nullptr_t");
3855
3856 // ::= <decltype>
3857 case 't':
3858 case 'T': {
3859 Result = getDerived().parseDecltype();
3860 break;
3861 }
3862 // extension ::= <vector-type> # <vector-type> starts with Dv
3863 case 'v': {
3864 Result = getDerived().parseVectorType();
3865 break;
3866 }
3867 // ::= Dp <type> # pack expansion (C++0x)
3868 case 'p': {
3869 First += 2;
3870 Node *Child = getDerived().parseType();
3871 if (!Child)
3872 return nullptr;
3873 Result = make<ParameterPackExpansion>(Child);
3874 break;
3875 }
3876 // Exception specifier on a function type.
3877 case 'o':
3878 case 'O':
3879 case 'w':
3880 // Transaction safe function type.
3881 case 'x':
3882 Result = getDerived().parseFunctionType();
3883 break;
3884 }
3885 break;
3886 // ::= <function-type>
3887 case 'F': {
3888 Result = getDerived().parseFunctionType();
3889 break;
3890 }
3891 // ::= <array-type>
3892 case 'A': {
3893 Result = getDerived().parseArrayType();
3894 break;
3895 }
3896 // ::= <pointer-to-member-type>
3897 case 'M': {
3898 Result = getDerived().parsePointerToMemberType();
3899 break;
3900 }
3901 // ::= <template-param>
3902 case 'T': {
3903 // This could be an elaborate type specifier on a <class-enum-type>.
3904 if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
3905 Result = getDerived().parseClassEnumType();
3906 break;
3907 }
3908
3909 Result = getDerived().parseTemplateParam();
3910 if (Result == nullptr)
3911 return nullptr;
3912
3913 // Result could be either of:
3914 // <type> ::= <template-param>
3915 // <type> ::= <template-template-param> <template-args>
3916 //
3917 // <template-template-param> ::= <template-param>
3918 // ::= <substitution>
3919 //
3920 // If this is followed by some <template-args>, and we're permitted to
3921 // parse them, take the second production.
3922
3923 if (TryToParseTemplateArgs && look() == 'I') {
3924 Node *TA = getDerived().parseTemplateArgs();
3925 if (TA == nullptr)
3926 return nullptr;
3927 Result = make<NameWithTemplateArgs>(Result, TA);
3928 }
3929 break;
3930 }
3931 // ::= P <type> # pointer
3932 case 'P': {
3933 ++First;
3934 Node *Ptr = getDerived().parseType();
3935 if (Ptr == nullptr)
3936 return nullptr;
3937 Result = make<PointerType>(Ptr);
3938 break;
3939 }
3940 // ::= R <type> # l-value reference
3941 case 'R': {
3942 ++First;
3943 Node *Ref = getDerived().parseType();
3944 if (Ref == nullptr)
3945 return nullptr;
3946 Result = make<ReferenceType>(Ref, ReferenceKind::LValue);
3947 break;
3948 }
3949 // ::= O <type> # r-value reference (C++11)
3950 case 'O': {
3951 ++First;
3952 Node *Ref = getDerived().parseType();
3953 if (Ref == nullptr)
3954 return nullptr;
3955 Result = make<ReferenceType>(Ref, ReferenceKind::RValue);
3956 break;
3957 }
3958 // ::= C <type> # complex pair (C99)
3959 case 'C': {
3960 ++First;
3961 Node *P = getDerived().parseType();
3962 if (P == nullptr)
3963 return nullptr;
3964 Result = make<PostfixQualifiedType>(P, " complex");
3965 break;
3966 }
3967 // ::= G <type> # imaginary (C99)
3968 case 'G': {
3969 ++First;
3970 Node *P = getDerived().parseType();
3971 if (P == nullptr)
3972 return P;
3973 Result = make<PostfixQualifiedType>(P, " imaginary");
3974 break;
3975 }
3976 // ::= <substitution> # See Compression below
3977 case 'S': {
3978 if (look(1) && look(1) != 't') {
3979 Node *Sub = getDerived().parseSubstitution();
3980 if (Sub == nullptr)
3981 return nullptr;
3982
3983 // Sub could be either of:
3984 // <type> ::= <substitution>
3985 // <type> ::= <template-template-param> <template-args>
3986 //
3987 // <template-template-param> ::= <template-param>
3988 // ::= <substitution>
3989 //
3990 // If this is followed by some <template-args>, and we're permitted to
3991 // parse them, take the second production.
3992
3993 if (TryToParseTemplateArgs && look() == 'I') {
3994 Node *TA = getDerived().parseTemplateArgs();
3995 if (TA == nullptr)
3996 return nullptr;
3997 Result = make<NameWithTemplateArgs>(Sub, TA);
3998 break;
3999 }
4000
4001 // If all we parsed was a substitution, don't re-insert into the
4002 // substitution table.
4003 return Sub;
4004 }
4005 DEMANGLE_FALLTHROUGH;
4006 }
4007 // ::= <class-enum-type>
4008 default: {
4009 Result = getDerived().parseClassEnumType();
4010 break;
4011 }
4012 }
4013
4014 // If we parsed a type, insert it into the substitution table. Note that all
4015 // <builtin-type>s and <substitution>s have already bailed out, because they
4016 // don't get substitutions.
4017 if (Result != nullptr)
4018 Subs.push_back(Result);
4019 return Result;
4020}
4021
4022template <typename Derived, typename Alloc>
4023Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) {
4024 Node *E = getDerived().parseExpr();
4025 if (E == nullptr)
4026 return nullptr;
4027 return make<PrefixExpr>(Kind, E);
4028}
4029
4030template <typename Derived, typename Alloc>
4031Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) {
4032 Node *LHS = getDerived().parseExpr();
4033 if (LHS == nullptr)
4034 return nullptr;
4035 Node *RHS = getDerived().parseExpr();
4036 if (RHS == nullptr)
4037 return nullptr;
4038 return make<BinaryExpr>(LHS, Kind, RHS);
4039}
4040
4041template <typename Derived, typename Alloc>
4042Node *
4043AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) {
4044 StringView Tmp = parseNumber(true);
4045 if (!Tmp.empty() && consumeIf('E'))
4046 return make<IntegerLiteral>(Lit, Tmp);
4047 return nullptr;
4048}
4049
4050// <CV-Qualifiers> ::= [r] [V] [K]
4051template <typename Alloc, typename Derived>
4052Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() {
4053 Qualifiers CVR = QualNone;
4054 if (consumeIf('r'))
4055 CVR |= QualRestrict;
4056 if (consumeIf('V'))
4057 CVR |= QualVolatile;
4058 if (consumeIf('K'))
4059 CVR |= QualConst;
4060 return CVR;
4061}
4062
4063// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
4064// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
4065// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
4066// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
4067template <typename Derived, typename Alloc>
4068Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
4069 if (consumeIf("fp")) {
4070 parseCVQualifiers();
4071 StringView Num = parseNumber();
4072 if (!consumeIf('_'))
4073 return nullptr;
4074 return make<FunctionParam>(Num);
4075 }
4076 if (consumeIf("fL")) {
4077 if (parseNumber().empty())
4078 return nullptr;
4079 if (!consumeIf('p'))
4080 return nullptr;
4081 parseCVQualifiers();
4082 StringView Num = parseNumber();
4083 if (!consumeIf('_'))
4084 return nullptr;
4085 return make<FunctionParam>(Num);
4086 }
4087 return nullptr;
4088}
4089
4090// [gs] nw <expression>* _ <type> E # new (expr-list) type
4091// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
4092// [gs] na <expression>* _ <type> E # new[] (expr-list) type
4093// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
4094// <initializer> ::= pi <expression>* E # parenthesized initialization
4095template <typename Derived, typename Alloc>
4096Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
4097 bool Global = consumeIf("gs");
4098 bool IsArray = look(1) == 'a';
4099 if (!consumeIf("nw") && !consumeIf("na"))
4100 return nullptr;
4101 size_t Exprs = Names.size();
4102 while (!consumeIf('_')) {
4103 Node *Ex = getDerived().parseExpr();
4104 if (Ex == nullptr)
4105 return nullptr;
4106 Names.push_back(Ex);
4107 }
4108 NodeArray ExprList = popTrailingNodeArray(Exprs);
4109 Node *Ty = getDerived().parseType();
4110 if (Ty == nullptr)
4111 return Ty;
4112 if (consumeIf("pi")) {
4113 size_t InitsBegin = Names.size();
4114 while (!consumeIf('E')) {
4115 Node *Init = getDerived().parseExpr();
4116 if (Init == nullptr)
4117 return Init;
4118 Names.push_back(Init);
4119 }
4120 NodeArray Inits = popTrailingNodeArray(InitsBegin);
4121 return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
4122 } else if (!consumeIf('E'))
4123 return nullptr;
4124 return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
4125}
4126
4127// cv <type> <expression> # conversion with one argument
4128// cv <type> _ <expression>* E # conversion with a different number of arguments
4129template <typename Derived, typename Alloc>
4130Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() {
4131 if (!consumeIf("cv"))
4132 return nullptr;
4133 Node *Ty;
4134 {
4135 SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
4136 Ty = getDerived().parseType();
4137 }
4138
4139 if (Ty == nullptr)
4140 return nullptr;
4141
4142 if (consumeIf('_')) {
4143 size_t ExprsBegin = Names.size();
4144 while (!consumeIf('E')) {
4145 Node *E = getDerived().parseExpr();
4146 if (E == nullptr)
4147 return E;
4148 Names.push_back(E);
4149 }
4150 NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
4151 return make<ConversionExpr>(Ty, Exprs);
4152 }
4153
4154 Node *E[1] = {getDerived().parseExpr()};
4155 if (E[0] == nullptr)
4156 return nullptr;
4157 return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
4158}
4159
4160// <expr-primary> ::= L <type> <value number> E # integer literal
4161// ::= L <type> <value float> E # floating literal
4162// ::= L <string type> E # string literal
4163// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
4164// ::= L <lambda type> E # lambda expression
4165// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
4166// ::= L <mangled-name> E # external name
4167template <typename Derived, typename Alloc>
4168Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
4169 if (!consumeIf('L'))
4170 return nullptr;
4171 switch (look()) {
4172 case 'w':
4173 ++First;
4174 return getDerived().parseIntegerLiteral("wchar_t");
4175 case 'b':
4176 if (consumeIf("b0E"))
4177 return make<BoolExpr>(0);
4178 if (consumeIf("b1E"))
4179 return make<BoolExpr>(1);
4180 return nullptr;
4181 case 'c':
4182 ++First;
4183 return getDerived().parseIntegerLiteral("char");
4184 case 'a':
4185 ++First;
4186 return getDerived().parseIntegerLiteral("signed char");
4187 case 'h':
4188 ++First;
4189 return getDerived().parseIntegerLiteral("unsigned char");
4190 case 's':
4191 ++First;
4192 return getDerived().parseIntegerLiteral("short");
4193 case 't':
4194 ++First;
4195 return getDerived().parseIntegerLiteral("unsigned short");
4196 case 'i':
4197 ++First;
4198 return getDerived().parseIntegerLiteral("");
4199 case 'j':
4200 ++First;
4201 return getDerived().parseIntegerLiteral("u");
4202 case 'l':
4203 ++First;
4204 return getDerived().parseIntegerLiteral("l");
4205 case 'm':
4206 ++First;
4207 return getDerived().parseIntegerLiteral("ul");
4208 case 'x':
4209 ++First;
4210 return getDerived().parseIntegerLiteral("ll");
4211 case 'y':
4212 ++First;
4213 return getDerived().parseIntegerLiteral("ull");
4214 case 'n':
4215 ++First;
4216 return getDerived().parseIntegerLiteral("__int128");
4217 case 'o':
4218 ++First;
4219 return getDerived().parseIntegerLiteral("unsigned __int128");
4220 case 'f':
4221 ++First;
4222 return getDerived().template parseFloatingLiteral<float>();
4223 case 'd':
4224 ++First;
4225 return getDerived().template parseFloatingLiteral<double>();
4226 case 'e':
4227 ++First;
4228 return getDerived().template parseFloatingLiteral<long double>();
4229 case '_':
4230 if (consumeIf("_Z")) {
4231 Node *R = getDerived().parseEncoding();
4232 if (R != nullptr && consumeIf('E'))
4233 return R;
4234 }
4235 return nullptr;
4236 case 'A': {
4237 Node *T = getDerived().parseType();
4238 if (T == nullptr)
4239 return nullptr;
4240 // FIXME: We need to include the string contents in the mangling.
4241 if (consumeIf('E'))
4242 return make<StringLiteral>(T);
4243 return nullptr;
4244 }
4245 case 'D':
4246 if (consumeIf("DnE"))
4247 return make<NameType>("nullptr");
4248 return nullptr;
4249 case 'T':
4250 // Invalid mangled name per
4251 // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
4252 return nullptr;
4253 case 'U': {
4254 // FIXME: Should we support LUb... for block literals?
4255 if (look(1) != 'l')
4256 return nullptr;
4257 Node *T = parseUnnamedTypeName(nullptr);
4258 if (!T || !consumeIf('E'))
4259 return nullptr;
4260 return make<LambdaExpr>(T);
4261 }
4262 default: {
4263 // might be named type
4264 Node *T = getDerived().parseType();
4265 if (T == nullptr)
4266 return nullptr;
4267 StringView N = parseNumber();
4268 if (N.empty())
4269 return nullptr;
4270 if (!consumeIf('E'))
4271 return nullptr;
4272 return make<IntegerCastExpr>(T, N);
4273 }
4274 }
4275}
4276
4277// <braced-expression> ::= <expression>
4278// ::= di <field source-name> <braced-expression> # .name = expr
4279// ::= dx <index expression> <braced-expression> # [expr] = expr
4280// ::= dX <range begin expression> <range end expression> <braced-expression>
4281template <typename Derived, typename Alloc>
4282Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() {
4283 if (look() == 'd') {
4284 switch (look(1)) {
4285 case 'i': {
4286 First += 2;
4287 Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr);
4288 if (Field == nullptr)
4289 return nullptr;
4290 Node *Init = getDerived().parseBracedExpr();
4291 if (Init == nullptr)
4292 return nullptr;
4293 return make<BracedExpr>(Field, Init, /*isArray=*/false);
4294 }
4295 case 'x': {
4296 First += 2;
4297 Node *Index = getDerived().parseExpr();
4298 if (Index == nullptr)
4299 return nullptr;
4300 Node *Init = getDerived().parseBracedExpr();
4301 if (Init == nullptr)
4302 return nullptr;
4303 return make<BracedExpr>(Index, Init, /*isArray=*/true);
4304 }
4305 case 'X': {
4306 First += 2;
4307 Node *RangeBegin = getDerived().parseExpr();
4308 if (RangeBegin == nullptr)
4309 return nullptr;
4310 Node *RangeEnd = getDerived().parseExpr();
4311 if (RangeEnd == nullptr)
4312 return nullptr;
4313 Node *Init = getDerived().parseBracedExpr();
4314 if (Init == nullptr)
4315 return nullptr;
4316 return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
4317 }
4318 }
4319 }
4320 return getDerived().parseExpr();
4321}
4322
4323// (not yet in the spec)
4324// <fold-expr> ::= fL <binary-operator-name> <expression> <expression>
4325// ::= fR <binary-operator-name> <expression> <expression>
4326// ::= fl <binary-operator-name> <expression>
4327// ::= fr <binary-operator-name> <expression>
4328template <typename Derived, typename Alloc>
4329Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
4330 if (!consumeIf('f'))
4331 return nullptr;
4332
4333 char FoldKind = look();
4334 bool IsLeftFold, HasInitializer;
4335 HasInitializer = FoldKind == 'L' || FoldKind == 'R';
4336 if (FoldKind == 'l' || FoldKind == 'L')
4337 IsLeftFold = true;
4338 else if (FoldKind == 'r' || FoldKind == 'R')
4339 IsLeftFold = false;
4340 else
4341 return nullptr;
4342 ++First;
4343
4344 // FIXME: This map is duplicated in parseOperatorName and parseExpr.
4345 StringView OperatorName;
4346 if (consumeIf("aa")) OperatorName = "&&";
4347 else if (consumeIf("an")) OperatorName = "&";
4348 else if (consumeIf("aN")) OperatorName = "&=";
4349 else if (consumeIf("aS")) OperatorName = "=";
4350 else if (consumeIf("cm")) OperatorName = ",";
4351 else if (consumeIf("ds")) OperatorName = ".*";
4352 else if (consumeIf("dv")) OperatorName = "/";
4353 else if (consumeIf("dV")) OperatorName = "/=";
4354 else if (consumeIf("eo")) OperatorName = "^";
4355 else if (consumeIf("eO")) OperatorName = "^=";
4356 else if (consumeIf("eq")) OperatorName = "==";
4357 else if (consumeIf("ge")) OperatorName = ">=";
4358 else if (consumeIf("gt")) OperatorName = ">";
4359 else if (consumeIf("le")) OperatorName = "<=";
4360 else if (consumeIf("ls")) OperatorName = "<<";
4361 else if (consumeIf("lS")) OperatorName = "<<=";
4362 else if (consumeIf("lt")) OperatorName = "<";
4363 else if (consumeIf("mi")) OperatorName = "-";
4364 else if (consumeIf("mI")) OperatorName = "-=";
4365 else if (consumeIf("ml")) OperatorName = "*";
4366 else if (consumeIf("mL")) OperatorName = "*=";
4367 else if (consumeIf("ne")) OperatorName = "!=";
4368 else if (consumeIf("oo")) OperatorName = "||";
4369 else if (consumeIf("or")) OperatorName = "|";
4370 else if (consumeIf("oR")) OperatorName = "|=";
4371 else if (consumeIf("pl")) OperatorName = "+";
4372 else if (consumeIf("pL")) OperatorName = "+=";
4373 else if (consumeIf("rm")) OperatorName = "%";
4374 else if (consumeIf("rM")) OperatorName = "%=";
4375 else if (consumeIf("rs")) OperatorName = ">>";
4376 else if (consumeIf("rS")) OperatorName = ">>=";
4377 else return nullptr;
4378
4379 Node *Pack = getDerived().parseExpr(), *Init = nullptr;
4380 if (Pack == nullptr)
4381 return nullptr;
4382 if (HasInitializer) {
4383 Init = getDerived().parseExpr();
4384 if (Init == nullptr)
4385 return nullptr;
4386 }
4387
4388 if (IsLeftFold && Init)
4389 std::swap(Pack, Init);
4390
4391 return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
4392}
4393
4394// <expression> ::= <unary operator-name> <expression>
4395// ::= <binary operator-name> <expression> <expression>
4396// ::= <ternary operator-name> <expression> <expression> <expression>
4397// ::= cl <expression>+ E # call
4398// ::= cv <type> <expression> # conversion with one argument
4399// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
4400// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
4401// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
4402// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
4403// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
4404// ::= [gs] dl <expression> # delete expression
4405// ::= [gs] da <expression> # delete[] expression
4406// ::= pp_ <expression> # prefix ++
4407// ::= mm_ <expression> # prefix --
4408// ::= ti <type> # typeid (type)
4409// ::= te <expression> # typeid (expression)
4410// ::= dc <type> <expression> # dynamic_cast<type> (expression)
4411// ::= sc <type> <expression> # static_cast<type> (expression)
4412// ::= cc <type> <expression> # const_cast<type> (expression)
4413// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
4414// ::= st <type> # sizeof (a type)
4415// ::= sz <expression> # sizeof (an expression)
4416// ::= at <type> # alignof (a type)
4417// ::= az <expression> # alignof (an expression)
4418// ::= nx <expression> # noexcept (expression)
4419// ::= <template-param>
4420// ::= <function-param>
4421// ::= dt <expression> <unresolved-name> # expr.name
4422// ::= pt <expression> <unresolved-name> # expr->name
4423// ::= ds <expression> <expression> # expr.*expr
4424// ::= sZ <template-param> # size of a parameter pack
4425// ::= sZ <function-param> # size of a function parameter pack
4426// ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template
4427// ::= sp <expression> # pack expansion
4428// ::= tw <expression> # throw expression
4429// ::= tr # throw with no operand (rethrow)
4430// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
4431// # freestanding dependent name (e.g., T::x),
4432// # objectless nonstatic member reference
4433// ::= fL <binary-operator-name> <expression> <expression>
4434// ::= fR <binary-operator-name> <expression> <expression>
4435// ::= fl <binary-operator-name> <expression>
4436// ::= fr <binary-operator-name> <expression>
4437// ::= <expr-primary>
4438template <typename Derived, typename Alloc>
4439Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
4440 bool Global = consumeIf("gs");
4441 if (numLeft() < 2)
4442 return nullptr;
4443
4444 switch (*First) {
4445 case 'L':
4446 return getDerived().parseExprPrimary();
4447 case 'T':
4448 return getDerived().parseTemplateParam();
4449 case 'f': {
4450 // Disambiguate a fold expression from a <function-param>.
4451 if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
4452 return getDerived().parseFunctionParam();
4453 return getDerived().parseFoldExpr();
4454 }
4455 case 'a':
4456 switch (First[1]) {
4457 case 'a':
4458 First += 2;
4459 return getDerived().parseBinaryExpr("&&");
4460 case 'd':
4461 First += 2;
4462 return getDerived().parsePrefixExpr("&");
4463 case 'n':
4464 First += 2;
4465 return getDerived().parseBinaryExpr("&");
4466 case 'N':
4467 First += 2;
4468 return getDerived().parseBinaryExpr("&=");
4469 case 'S':
4470 First += 2;
4471 return getDerived().parseBinaryExpr("=");
4472 case 't': {
4473 First += 2;
4474 Node *Ty = getDerived().parseType();
4475 if (Ty == nullptr)
4476 return nullptr;
4477 return make<EnclosingExpr>("alignof (", Ty, ")");
4478 }
4479 case 'z': {
4480 First += 2;
4481 Node *Ty = getDerived().parseExpr();
4482 if (Ty == nullptr)
4483 return nullptr;
4484 return make<EnclosingExpr>("alignof (", Ty, ")");
4485 }
4486 }
4487 return nullptr;
4488 case 'c':
4489 switch (First[1]) {
4490 // cc <type> <expression> # const_cast<type>(expression)
4491 case 'c': {
4492 First += 2;
4493 Node *Ty = getDerived().parseType();
4494 if (Ty == nullptr)
4495 return Ty;
4496 Node *Ex = getDerived().parseExpr();
4497 if (Ex == nullptr)
4498 return Ex;
4499 return make<CastExpr>("const_cast", Ty, Ex);
4500 }
4501 // cl <expression>+ E # call
4502 case 'l': {
4503 First += 2;
4504 Node *Callee = getDerived().parseExpr();
4505 if (Callee == nullptr)
4506 return Callee;
4507 size_t ExprsBegin = Names.size();
4508 while (!consumeIf('E')) {
4509 Node *E = getDerived().parseExpr();
4510 if (E == nullptr)
4511 return E;
4512 Names.push_back(E);
4513 }
4514 return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
4515 }
4516 case 'm':
4517 First += 2;
4518 return getDerived().parseBinaryExpr(",");
4519 case 'o':
4520 First += 2;
4521 return getDerived().parsePrefixExpr("~");
4522 case 'v':
4523 return getDerived().parseConversionExpr();
4524 }
4525 return nullptr;
4526 case 'd':
4527 switch (First[1]) {
4528 case 'a': {
4529 First += 2;
4530 Node *Ex = getDerived().parseExpr();
4531 if (Ex == nullptr)
4532 return Ex;
4533 return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
4534 }
4535 case 'c': {
4536 First += 2;
4537 Node *T = getDerived().parseType();
4538 if (T == nullptr)
4539 return T;
4540 Node *Ex = getDerived().parseExpr();
4541 if (Ex == nullptr)
4542 return Ex;
4543 return make<CastExpr>("dynamic_cast", T, Ex);
4544 }
4545 case 'e':
4546 First += 2;
4547 return getDerived().parsePrefixExpr("*");
4548 case 'l': {
4549 First += 2;
4550 Node *E = getDerived().parseExpr();
4551 if (E == nullptr)
4552 return E;
4553 return make<DeleteExpr>(E, Global, /*is_array=*/false);
4554 }
4555 case 'n':
4556 return getDerived().parseUnresolvedName();
4557 case 's': {
4558 First += 2;
4559 Node *LHS = getDerived().parseExpr();
4560 if (LHS == nullptr)
4561 return nullptr;
4562 Node *RHS = getDerived().parseExpr();
4563 if (RHS == nullptr)
4564 return nullptr;
4565 return make<MemberExpr>(LHS, ".*", RHS);
4566 }
4567 case 't': {
4568 First += 2;
4569 Node *LHS = getDerived().parseExpr();
4570 if (LHS == nullptr)
4571 return LHS;
4572 Node *RHS = getDerived().parseExpr();
4573 if (RHS == nullptr)
4574 return nullptr;
4575 return make<MemberExpr>(LHS, ".", RHS);
4576 }
4577 case 'v':
4578 First += 2;
4579 return getDerived().parseBinaryExpr("/");
4580 case 'V':
4581 First += 2;
4582 return getDerived().parseBinaryExpr("/=");
4583 }
4584 return nullptr;
4585 case 'e':
4586 switch (First[1]) {
4587 case 'o':
4588 First += 2;
4589 return getDerived().parseBinaryExpr("^");
4590 case 'O':
4591 First += 2;
4592 return getDerived().parseBinaryExpr("^=");
4593 case 'q':
4594 First += 2;
4595 return getDerived().parseBinaryExpr("==");
4596 }
4597 return nullptr;
4598 case 'g':
4599 switch (First[1]) {
4600 case 'e':
4601 First += 2;
4602 return getDerived().parseBinaryExpr(">=");
4603 case 't':
4604 First += 2;
4605 return getDerived().parseBinaryExpr(">");
4606 }
4607 return nullptr;
4608 case 'i':
4609 switch (First[1]) {
4610 case 'x': {
4611 First += 2;
4612 Node *Base = getDerived().parseExpr();
4613 if (Base == nullptr)
4614 return nullptr;
4615 Node *Index = getDerived().parseExpr();
4616 if (Index == nullptr)
4617 return Index;
4618 return make<ArraySubscriptExpr>(Base, Index);
4619 }
4620 case 'l': {
4621 First += 2;
4622 size_t InitsBegin = Names.size();
4623 while (!consumeIf('E')) {
4624 Node *E = getDerived().parseBracedExpr();
4625 if (E == nullptr)
4626 return nullptr;
4627 Names.push_back(E);
4628 }
4629 return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
4630 }
4631 }
4632 return nullptr;
4633 case 'l':
4634 switch (First[1]) {
4635 case 'e':
4636 First += 2;
4637 return getDerived().parseBinaryExpr("<=");
4638 case 's':
4639 First += 2;
4640 return getDerived().parseBinaryExpr("<<");
4641 case 'S':
4642 First += 2;
4643 return getDerived().parseBinaryExpr("<<=");
4644 case 't':
4645 First += 2;
4646 return getDerived().parseBinaryExpr("<");
4647 }
4648 return nullptr;
4649 case 'm':
4650 switch (First[1]) {
4651 case 'i':
4652 First += 2;
4653 return getDerived().parseBinaryExpr("-");
4654 case 'I':
4655 First += 2;
4656 return getDerived().parseBinaryExpr("-=");
4657 case 'l':
4658 First += 2;
4659 return getDerived().parseBinaryExpr("*");
4660 case 'L':
4661 First += 2;
4662 return getDerived().parseBinaryExpr("*=");
4663 case 'm':
4664 First += 2;
4665 if (consumeIf('_'))
4666 return getDerived().parsePrefixExpr("--");
4667 Node *Ex = getDerived().parseExpr();
4668 if (Ex == nullptr)
4669 return nullptr;
4670 return make<PostfixExpr>(Ex, "--");
4671 }
4672 return nullptr;
4673 case 'n':
4674 switch (First[1]) {
4675 case 'a':
4676 case 'w':
4677 return getDerived().parseNewExpr();
4678 case 'e':
4679 First += 2;
4680 return getDerived().parseBinaryExpr("!=");
4681 case 'g':
4682 First += 2;
4683 return getDerived().parsePrefixExpr("-");
4684 case 't':
4685 First += 2;
4686 return getDerived().parsePrefixExpr("!");
4687 case 'x':
4688 First += 2;
4689 Node *Ex = getDerived().parseExpr();
4690 if (Ex == nullptr)
4691 return Ex;
4692 return make<EnclosingExpr>("noexcept (", Ex, ")");
4693 }
4694 return nullptr;
4695 case 'o':
4696 switch (First[1]) {
4697 case 'n':
4698 return getDerived().parseUnresolvedName();
4699 case 'o':
4700 First += 2;
4701 return getDerived().parseBinaryExpr("||");
4702 case 'r':
4703 First += 2;
4704 return getDerived().parseBinaryExpr("|");
4705 case 'R':
4706 First += 2;
4707 return getDerived().parseBinaryExpr("|=");
4708 }
4709 return nullptr;
4710 case 'p':
4711 switch (First[1]) {
4712 case 'm':
4713 First += 2;
4714 return getDerived().parseBinaryExpr("->*");
4715 case 'l':
4716 First += 2;
4717 return getDerived().parseBinaryExpr("+");
4718 case 'L':
4719 First += 2;
4720 return getDerived().parseBinaryExpr("+=");
4721 case 'p': {
4722 First += 2;
4723 if (consumeIf('_'))
4724 return getDerived().parsePrefixExpr("++");
4725 Node *Ex = getDerived().parseExpr();
4726 if (Ex == nullptr)
4727 return Ex;
4728 return make<PostfixExpr>(Ex, "++");
4729 }
4730 case 's':
4731 First += 2;
4732 return getDerived().parsePrefixExpr("+");
4733 case 't': {
4734 First += 2;
4735 Node *L = getDerived().parseExpr();
4736 if (L == nullptr)
4737 return nullptr;
4738 Node *R = getDerived().parseExpr();
4739 if (R == nullptr)
4740 return nullptr;
4741 return make<MemberExpr>(L, "->", R);
4742 }
4743 }
4744 return nullptr;
4745 case 'q':
4746 if (First[1] == 'u') {
4747 First += 2;
4748 Node *Cond = getDerived().parseExpr();
4749 if (Cond == nullptr)
4750 return nullptr;
4751 Node *LHS = getDerived().parseExpr();
4752 if (LHS == nullptr)
4753 return nullptr;
4754 Node *RHS = getDerived().parseExpr();
4755 if (RHS == nullptr)
4756 return nullptr;
4757 return make<ConditionalExpr>(Cond, LHS, RHS);
4758 }
4759 return nullptr;
4760 case 'r':
4761 switch (First[1]) {
4762 case 'c': {
4763 First += 2;
4764 Node *T = getDerived().parseType();
4765 if (T == nullptr)
4766 return T;
4767 Node *Ex = getDerived().parseExpr();
4768 if (Ex == nullptr)
4769 return Ex;
4770 return make<CastExpr>("reinterpret_cast", T, Ex);
4771 }
4772 case 'm':
4773 First += 2;
4774 return getDerived().parseBinaryExpr("%");
4775 case 'M':
4776 First += 2;
4777 return getDerived().parseBinaryExpr("%=");
4778 case 's':
4779 First += 2;
4780 return getDerived().parseBinaryExpr(">>");
4781 case 'S':
4782 First += 2;
4783 return getDerived().parseBinaryExpr(">>=");
4784 }
4785 return nullptr;
4786 case 's':
4787 switch (First[1]) {
4788 case 'c': {
4789 First += 2;
4790 Node *T = getDerived().parseType();
4791 if (T == nullptr)
4792 return T;
4793 Node *Ex = getDerived().parseExpr();
4794 if (Ex == nullptr)
4795 return Ex;
4796 return make<CastExpr>("static_cast", T, Ex);
4797 }
4798 case 'p': {
4799 First += 2;
4800 Node *Child = getDerived().parseExpr();
4801 if (Child == nullptr)
4802 return nullptr;
4803 return make<ParameterPackExpansion>(Child);
4804 }
4805 case 'r':
4806 return getDerived().parseUnresolvedName();
4807 case 't': {
4808 First += 2;
4809 Node *Ty = getDerived().parseType();
4810 if (Ty == nullptr)
4811 return Ty;
4812 return make<EnclosingExpr>("sizeof (", Ty, ")");
4813 }
4814 case 'z': {
4815 First += 2;
4816 Node *Ex = getDerived().parseExpr();
4817 if (Ex == nullptr)
4818 return Ex;
4819 return make<EnclosingExpr>("sizeof (", Ex, ")");
4820 }
4821 case 'Z':
4822 First += 2;
4823 if (look() == 'T') {
4824 Node *R = getDerived().parseTemplateParam();
4825 if (R == nullptr)
4826 return nullptr;
4827 return make<SizeofParamPackExpr>(R);
4828 } else if (look() == 'f') {
4829 Node *FP = getDerived().parseFunctionParam();
4830 if (FP == nullptr)
4831 return nullptr;
4832 return make<EnclosingExpr>("sizeof... (", FP, ")");
4833 }
4834 return nullptr;
4835 case 'P': {
4836 First += 2;
4837 size_t ArgsBegin = Names.size();
4838 while (!consumeIf('E')) {
4839 Node *Arg = getDerived().parseTemplateArg();
4840 if (Arg == nullptr)
4841 return nullptr;
4842 Names.push_back(Arg);
4843 }
4844 auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
4845 if (!Pack)
4846 return nullptr;
4847 return make<EnclosingExpr>("sizeof... (", Pack, ")");
4848 }
4849 }
4850 return nullptr;
4851 case 't':
4852 switch (First[1]) {
4853 case 'e': {
4854 First += 2;
4855 Node *Ex = getDerived().parseExpr();
4856 if (Ex == nullptr)
4857 return Ex;
4858 return make<EnclosingExpr>("typeid (", Ex, ")");
4859 }
4860 case 'i': {
4861 First += 2;
4862 Node *Ty = getDerived().parseType();
4863 if (Ty == nullptr)
4864 return Ty;
4865 return make<EnclosingExpr>("typeid (", Ty, ")");
4866 }
4867 case 'l': {
4868 First += 2;
4869 Node *Ty = getDerived().parseType();
4870 if (Ty == nullptr)
4871 return nullptr;
4872 size_t InitsBegin = Names.size();
4873 while (!consumeIf('E')) {
4874 Node *E = getDerived().parseBracedExpr();
4875 if (E == nullptr)
4876 return nullptr;
4877 Names.push_back(E);
4878 }
4879 return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
4880 }
4881 case 'r':
4882 First += 2;
4883 return make<NameType>("throw");
4884 case 'w': {
4885 First += 2;
4886 Node *Ex = getDerived().parseExpr();
4887 if (Ex == nullptr)
4888 return nullptr;
4889 return make<ThrowExpr>(Ex);
4890 }
4891 }
4892 return nullptr;
4893 case '1':
4894 case '2':
4895 case '3':
4896 case '4':
4897 case '5':
4898 case '6':
4899 case '7':
4900 case '8':
4901 case '9':
4902 return getDerived().parseUnresolvedName();
4903 }
4904
4905 if (consumeIf("u8__uuidoft")) {
4906 Node *Ty = getDerived().parseType();
4907 if (!Ty)
4908 return nullptr;
4909 return make<UUIDOfExpr>(Ty);
4910 }
4911
4912 if (consumeIf("u8__uuidofz")) {
4913 Node *Ex = getDerived().parseExpr();
4914 if (!Ex)
4915 return nullptr;
4916 return make<UUIDOfExpr>(Ex);
4917 }
4918
4919 return nullptr;
4920}
4921
4922// <call-offset> ::= h <nv-offset> _
4923// ::= v <v-offset> _
4924//
4925// <nv-offset> ::= <offset number>
4926// # non-virtual base override
4927//
4928// <v-offset> ::= <offset number> _ <virtual offset number>
4929// # virtual base override, with vcall offset
4930template <typename Alloc, typename Derived>
4931bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() {
4932 // Just scan through the call offset, we never add this information into the
4933 // output.
4934 if (consumeIf('h'))
4935 return parseNumber(true).empty() || !consumeIf('_');
4936 if (consumeIf('v'))
4937 return parseNumber(true).empty() || !consumeIf('_') ||
4938 parseNumber(true).empty() || !consumeIf('_');
4939 return true;
4940}
4941
4942// <special-name> ::= TV <type> # virtual table
4943// ::= TT <type> # VTT structure (construction vtable index)
4944// ::= TI <type> # typeinfo structure
4945// ::= TS <type> # typeinfo name (null-terminated byte string)
4946// ::= Tc <call-offset> <call-offset> <base encoding>
4947// # base is the nominal target function of thunk
4948// # first call-offset is 'this' adjustment
4949// # second call-offset is result adjustment
4950// ::= T <call-offset> <base encoding>
4951// # base is the nominal target function of thunk
4952// ::= GV <object name> # Guard variable for one-time initialization
4953// # No <type>
4954// ::= TW <object name> # Thread-local wrapper
4955// ::= TH <object name> # Thread-local initialization
4956// ::= GR <object name> _ # First temporary
4957// ::= GR <object name> <seq-id> _ # Subsequent temporaries
4958// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
4959// extension ::= GR <object name> # reference temporary for object
4960template <typename Derived, typename Alloc>
4961Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
4962 switch (look()) {
4963 case 'T':
4964 switch (look(1)) {
4965 // TV <type> # virtual table
4966 case 'V': {
4967 First += 2;
4968 Node *Ty = getDerived().parseType();
4969 if (Ty == nullptr)
4970 return nullptr;
4971 return make<SpecialName>("vtable for ", Ty);
4972 }
4973 // TT <type> # VTT structure (construction vtable index)
4974 case 'T': {
4975 First += 2;
4976 Node *Ty = getDerived().parseType();
4977 if (Ty == nullptr)
4978 return nullptr;
4979 return make<SpecialName>("VTT for ", Ty);
4980 }
4981 // TI <type> # typeinfo structure
4982 case 'I': {
4983 First += 2;
4984 Node *Ty = getDerived().parseType();
4985 if (Ty == nullptr)
4986 return nullptr;
4987 return make<SpecialName>("typeinfo for ", Ty);
4988 }
4989 // TS <type> # typeinfo name (null-terminated byte string)
4990 case 'S': {
4991 First += 2;
4992 Node *Ty = getDerived().parseType();
4993 if (Ty == nullptr)
4994 return nullptr;
4995 return make<SpecialName>("typeinfo name for ", Ty);
4996 }
4997 // Tc <call-offset> <call-offset> <base encoding>
4998 case 'c': {
4999 First += 2;
5000 if (parseCallOffset() || parseCallOffset())
5001 return nullptr;
5002 Node *Encoding = getDerived().parseEncoding();
5003 if (Encoding == nullptr)
5004 return nullptr;
5005 return make<SpecialName>("covariant return thunk to ", Encoding);
5006 }
5007 // extension ::= TC <first type> <number> _ <second type>
5008 // # construction vtable for second-in-first
5009 case 'C': {
5010 First += 2;
5011 Node *FirstType = getDerived().parseType();
5012 if (FirstType == nullptr)
5013 return nullptr;
5014 if (parseNumber(true).empty() || !consumeIf('_'))
5015 return nullptr;
5016 Node *SecondType = getDerived().parseType();
5017 if (SecondType == nullptr)
5018 return nullptr;
5019 return make<CtorVtableSpecialName>(SecondType, FirstType);
5020 }
5021 // TW <object name> # Thread-local wrapper
5022 case 'W': {
5023 First += 2;
5024 Node *Name = getDerived().parseName();
5025 if (Name == nullptr)
5026 return nullptr;
5027 return make<SpecialName>("thread-local wrapper routine for ", Name);
5028 }
5029 // TH <object name> # Thread-local initialization
5030 case 'H': {
5031 First += 2;
5032 Node *Name = getDerived().parseName();
5033 if (Name == nullptr)
5034 return nullptr;
5035 return make<SpecialName>("thread-local initialization routine for ", Name);
5036 }
5037 // T <call-offset> <base encoding>
5038 default: {
5039 ++First;
5040 bool IsVirt = look() == 'v';
5041 if (parseCallOffset())
5042 return nullptr;
5043 Node *BaseEncoding = getDerived().parseEncoding();
5044 if (BaseEncoding == nullptr)
5045 return nullptr;
5046 if (IsVirt)
5047 return make<SpecialName>("virtual thunk to ", BaseEncoding);
5048 else
5049 return make<SpecialName>("non-virtual thunk to ", BaseEncoding);
5050 }
5051 }
5052 case 'G':
5053 switch (look(1)) {
5054 // GV <object name> # Guard variable for one-time initialization
5055 case 'V': {
5056 First += 2;
5057 Node *Name = getDerived().parseName();
5058 if (Name == nullptr)
5059 return nullptr;
5060 return make<SpecialName>("guard variable for ", Name);
5061 }
5062 // GR <object name> # reference temporary for object
5063 // GR <object name> _ # First temporary
5064 // GR <object name> <seq-id> _ # Subsequent temporaries
5065 case 'R': {
5066 First += 2;
5067 Node *Name = getDerived().parseName();
5068 if (Name == nullptr)
5069 return nullptr;
5070 size_t Count;
5071 bool ParsedSeqId = !parseSeqId(&Count);
5072 if (!consumeIf('_') && ParsedSeqId)
5073 return nullptr;
5074 return make<SpecialName>("reference temporary for ", Name);
5075 }
5076 }
5077 }
5078 return nullptr;
5079}
5080
5081// <encoding> ::= <function name> <bare-function-type>
5082// ::= <data name>
5083// ::= <special-name>
5084template <typename Derived, typename Alloc>
5085Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
5086 if (look() == 'G' || look() == 'T')
5087 return getDerived().parseSpecialName();
5088
5089 auto IsEndOfEncoding = [&] {
5090 // The set of chars that can potentially follow an <encoding> (none of which
5091 // can start a <type>). Enumerating these allows us to avoid speculative
5092 // parsing.
5093 return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';
5094 };
5095
5096 NameState NameInfo(this);
5097 Node *Name = getDerived().parseName(&NameInfo);
5098 if (Name == nullptr)
5099 return nullptr;
5100
5101 if (resolveForwardTemplateRefs(NameInfo))
5102 return nullptr;
5103
5104 if (IsEndOfEncoding())
5105 return Name;
5106
5107 Node *Attrs = nullptr;
5108 if (consumeIf("Ua9enable_ifI")) {
5109 size_t BeforeArgs = Names.size();
5110 while (!consumeIf('E')) {
5111 Node *Arg = getDerived().parseTemplateArg();
5112 if (Arg == nullptr)
5113 return nullptr;
5114 Names.push_back(Arg);
5115 }
5116 Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));
5117 if (!Attrs)
5118 return nullptr;
5119 }
5120
5121 Node *ReturnType = nullptr;
5122 if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
5123 ReturnType = getDerived().parseType();
5124 if (ReturnType == nullptr)
5125 return nullptr;
5126 }
5127
5128 if (consumeIf('v'))
5129 return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
5130 Attrs, NameInfo.CVQualifiers,
5131 NameInfo.ReferenceQualifier);
5132
5133 size_t ParamsBegin = Names.size();
5134 do {
5135 Node *Ty = getDerived().parseType();
5136 if (Ty == nullptr)
5137 return nullptr;
5138 Names.push_back(Ty);
5139 } while (!IsEndOfEncoding());
5140
5141 return make<FunctionEncoding>(ReturnType, Name,
5142 popTrailingNodeArray(ParamsBegin),
5143 Attrs, NameInfo.CVQualifiers,
5144 NameInfo.ReferenceQualifier);
5145}
5146
5147template <class Float>
5148struct FloatData;
5149
5150template <>
5151struct FloatData<float>
5152{
5153 static const size_t mangled_size = 8;
5154 static const size_t max_demangled_size = 24;
5155 static constexpr const char* spec = "%af";
5156};
5157
5158template <>
5159struct FloatData<double>
5160{
5161 static const size_t mangled_size = 16;
5162 static const size_t max_demangled_size = 32;
5163 static constexpr const char* spec = "%a";
5164};
5165
5166template <>
5167struct FloatData<long double>
5168{
5169#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
5170 defined(__wasm__)
5171 static const size_t mangled_size = 32;
5172#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
5173 static const size_t mangled_size = 16;
5174#else
5175 static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
5176#endif
5177 static const size_t max_demangled_size = 40;
5178 static constexpr const char *spec = "%LaL";
5179};
5180
5181template <typename Alloc, typename Derived>
5182template <class Float>
5183Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() {
5184 const size_t N = FloatData<Float>::mangled_size;
5185 if (numLeft() <= N)
5186 return nullptr;
5187 StringView Data(First, First + N);
5188 for (char C : Data)
5189 if (!std::isxdigit(C))
5190 return nullptr;
5191 First += N;
5192 if (!consumeIf('E'))
5193 return nullptr;
5194 return make<FloatLiteralImpl<Float>>(Data);
5195}
5196
5197// <seq-id> ::= <0-9A-Z>+
5198template <typename Alloc, typename Derived>
5199bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) {
5200 if (!(look() >= '0' && look() <= '9') &&
5201 !(look() >= 'A' && look() <= 'Z'))
5202 return true;
5203
5204 size_t Id = 0;
5205 while (true) {
5206 if (look() >= '0' && look() <= '9') {
5207 Id *= 36;
5208 Id += static_cast<size_t>(look() - '0');
5209 } else if (look() >= 'A' && look() <= 'Z') {
5210 Id *= 36;
5211 Id += static_cast<size_t>(look() - 'A') + 10;
5212 } else {
5213 *Out = Id;
5214 return false;
5215 }
5216 ++First;
5217 }
5218}
5219
5220// <substitution> ::= S <seq-id> _
5221// ::= S_
5222// <substitution> ::= Sa # ::std::allocator
5223// <substitution> ::= Sb # ::std::basic_string
5224// <substitution> ::= Ss # ::std::basic_string < char,
5225// ::std::char_traits<char>,
5226// ::std::allocator<char> >
5227// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
5228// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
5229// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
5230template <typename Derived, typename Alloc>
5231Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
5232 if (!consumeIf('S'))
5233 return nullptr;
5234
5235 if (std::islower(look())) {
5236 Node *SpecialSub;
5237 switch (look()) {
5238 case 'a':
5239 ++First;
5240 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
5241 break;
5242 case 'b':
5243 ++First;
5244 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
5245 break;
5246 case 's':
5247 ++First;
5248 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
5249 break;
5250 case 'i':
5251 ++First;
5252 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
5253 break;
5254 case 'o':
5255 ++First;
5256 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
5257 break;
5258 case 'd':
5259 ++First;
5260 SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
5261 break;
5262 default:
5263 return nullptr;
5264 }
5265 if (!SpecialSub)
5266 return nullptr;
5267 // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
5268 // has ABI tags, the tags are appended to the substitution; the result is a
5269 // substitutable component.
5270 Node *WithTags = getDerived().parseAbiTags(SpecialSub);
5271 if (WithTags != SpecialSub) {
5272 Subs.push_back(WithTags);
5273 SpecialSub = WithTags;
5274 }
5275 return SpecialSub;
5276 }
5277
5278 // ::= S_
5279 if (consumeIf('_')) {
5280 if (Subs.empty())
5281 return nullptr;
5282 return Subs[0];
5283 }
5284
5285 // ::= S <seq-id> _
5286 size_t Index = 0;
5287 if (parseSeqId(&Index))
5288 return nullptr;
5289 ++Index;
5290 if (!consumeIf('_') || Index >= Subs.size())
5291 return nullptr;
5292 return Subs[Index];
5293}
5294
5295// <template-param> ::= T_ # first template parameter
5296// ::= T <parameter-2 non-negative number> _
5297// ::= TL <level-1> __
5298// ::= TL <level-1> _ <parameter-2 non-negative number> _
5299template <typename Derived, typename Alloc>
5300Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
5301 if (!consumeIf('T'))
5302 return nullptr;
5303
5304 size_t Level = 0;
5305 if (consumeIf('L')) {
5306 if (parsePositiveInteger(&Level))
5307 return nullptr;
5308 ++Level;
5309 if (!consumeIf('_'))
5310 return nullptr;
5311 }
5312
5313 size_t Index = 0;
5314 if (!consumeIf('_')) {
5315 if (parsePositiveInteger(&Index))
5316 return nullptr;
5317 ++Index;
5318 if (!consumeIf('_'))
5319 return nullptr;
5320 }
5321
5322 // If we're in a context where this <template-param> refers to a
5323 // <template-arg> further ahead in the mangled name (currently just conversion
5324 // operator types), then we should only look it up in the right context.
5325 // This can only happen at the outermost level.
5326 if (PermitForwardTemplateReferences && Level == 0) {
5327 Node *ForwardRef = make<ForwardTemplateReference>(Index);
5328 if (!ForwardRef)
5329 return nullptr;
5330 assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
5331 ForwardTemplateRefs.push_back(
5332 static_cast<ForwardTemplateReference *>(ForwardRef));
5333 return ForwardRef;
5334 }
5335
5336 if (Level >= TemplateParams.size() || !TemplateParams[Level] ||
5337 Index >= TemplateParams[Level]->size()) {
5338 // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter
5339 // list are mangled as the corresponding artificial template type parameter.
5340 if (ParsingLambdaParamsAtLevel == Level && Level <= TemplateParams.size()) {
5341 // This will be popped by the ScopedTemplateParamList in
5342 // parseUnnamedTypeName.
5343 if (Level == TemplateParams.size())
5344 TemplateParams.push_back(nullptr);
5345 return make<NameType>("auto");
5346 }
5347
5348 return nullptr;
5349 }
5350
5351 return (*TemplateParams[Level])[Index];
5352}
5353
5354// <template-param-decl> ::= Ty # type parameter
5355// ::= Tn <type> # non-type parameter
5356// ::= Tt <template-param-decl>* E # template parameter
5357// ::= Tp <template-param-decl> # parameter pack
5358template <typename Derived, typename Alloc>
5359Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
5360 auto InventTemplateParamName = [&](TemplateParamKind Kind) {
5361 unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
5362 Node *N = make<SyntheticTemplateParamName>(Kind, Index);
5363 if (N) TemplateParams.back()->push_back(N);
5364 return N;
5365 };
5366
5367 if (consumeIf("Ty")) {
5368 Node *Name = InventTemplateParamName(TemplateParamKind::Type);
5369 if (!Name)
5370 return nullptr;
5371 return make<TypeTemplateParamDecl>(Name);
5372 }
5373
5374 if (consumeIf("Tn")) {
5375 Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
5376 if (!Name)
5377 return nullptr;
5378 Node *Type = parseType();
5379 if (!Type)
5380 return nullptr;
5381 return make<NonTypeTemplateParamDecl>(Name, Type);
5382 }
5383
5384 if (consumeIf("Tt")) {
5385 Node *Name = InventTemplateParamName(TemplateParamKind::Template);
5386 if (!Name)
5387 return nullptr;
5388 size_t ParamsBegin = Names.size();
5389 ScopedTemplateParamList TemplateTemplateParamParams(this);
5390 while (!consumeIf("E")) {
5391 Node *P = parseTemplateParamDecl();
5392 if (!P)
5393 return nullptr;
5394 Names.push_back(P);
5395 }
5396 NodeArray Params = popTrailingNodeArray(ParamsBegin);
5397 return make<TemplateTemplateParamDecl>(Name, Params);
5398 }
5399
5400 if (consumeIf("Tp")) {
5401 Node *P = parseTemplateParamDecl();
5402 if (!P)
5403 return nullptr;
5404 return make<TemplateParamPackDecl>(P);
5405 }
5406
5407 return nullptr;
5408}
5409
5410// <template-arg> ::= <type> # type or template
5411// ::= X <expression> E # expression
5412// ::= <expr-primary> # simple expressions
5413// ::= J <template-arg>* E # argument pack
5414// ::= LZ <encoding> E # extension
5415template <typename Derived, typename Alloc>
5416Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
5417 switch (look()) {
5418 case 'X': {
5419 ++First;
5420 Node *Arg = getDerived().parseExpr();
5421 if (Arg == nullptr || !consumeIf('E'))
5422 return nullptr;
5423 return Arg;
5424 }
5425 case 'J': {
5426 ++First;
5427 size_t ArgsBegin = Names.size();
5428 while (!consumeIf('E')) {
5429 Node *Arg = getDerived().parseTemplateArg();
5430 if (Arg == nullptr)
5431 return nullptr;
5432 Names.push_back(Arg);
5433 }
5434 NodeArray Args = popTrailingNodeArray(ArgsBegin);
5435 return make<TemplateArgumentPack>(Args);
5436 }
5437 case 'L': {
5438 // ::= LZ <encoding> E # extension
5439 if (look(1) == 'Z') {
5440 First += 2;
5441 Node *Arg = getDerived().parseEncoding();
5442 if (Arg == nullptr || !consumeIf('E'))
5443 return nullptr;
5444 return Arg;
5445 }
5446 // ::= <expr-primary> # simple expressions
5447 return getDerived().parseExprPrimary();
5448 }
5449 default:
5450 return getDerived().parseType();
5451 }
5452}
5453
5454// <template-args> ::= I <template-arg>* E
5455// extension, the abi says <template-arg>+
5456template <typename Derived, typename Alloc>
5457Node *
5458AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
5459 if (!consumeIf('I'))
5460 return nullptr;
5461
5462 // <template-params> refer to the innermost <template-args>. Clear out any
5463 // outer args that we may have inserted into TemplateParams.
5464 if (TagTemplates) {
5465 TemplateParams.clear();
5466 TemplateParams.push_back(&OuterTemplateParams);
5467 OuterTemplateParams.clear();
5468 }
5469
5470 size_t ArgsBegin = Names.size();
5471 while (!consumeIf('E')) {
5472 if (TagTemplates) {
5473 auto OldParams = std::move(TemplateParams);
5474 Node *Arg = getDerived().parseTemplateArg();
5475 TemplateParams = std::move(OldParams);
5476 if (Arg == nullptr)
5477 return nullptr;
5478 Names.push_back(Arg);
5479 Node *TableEntry = Arg;
5480 if (Arg->getKind() == Node::KTemplateArgumentPack) {
5481 TableEntry = make<ParameterPack>(
5482 static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
5483 if (!TableEntry)
5484 return nullptr;
5485 }
5486 TemplateParams.back()->push_back(TableEntry);
5487 } else {
5488 Node *Arg = getDerived().parseTemplateArg();
5489 if (Arg == nullptr)
5490 return nullptr;
5491 Names.push_back(Arg);
5492 }
5493 }
5494 return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
5495}
5496
5497// <mangled-name> ::= _Z <encoding>
5498// ::= <type>
5499// extension ::= ___Z <encoding> _block_invoke
5500// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
5501// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
5502template <typename Derived, typename Alloc>
5503Node *AbstractManglingParser<Derived, Alloc>::parse() {
5504 if (consumeIf("_Z") || consumeIf("__Z")) {
5505 Node *Encoding = getDerived().parseEncoding();
5506 if (Encoding == nullptr)
5507 return nullptr;
5508 if (look() == '.') {
5509 Encoding = make<DotSuffix>(Encoding, StringView(First, Last));
5510 First = Last;
5511 }
5512 if (numLeft() != 0)
5513 return nullptr;
5514 return Encoding;
5515 }
5516
5517 if (consumeIf("___Z") || consumeIf("____Z")) {
5518 Node *Encoding = getDerived().parseEncoding();
5519 if (Encoding == nullptr || !consumeIf("_block_invoke"))
5520 return nullptr;
5521 bool RequireNumber = consumeIf('_');
5522 if (parseNumber().empty() && RequireNumber)
5523 return nullptr;
5524 if (look() == '.')
5525 First = Last;
5526 if (numLeft() != 0)
5527 return nullptr;
5528 return make<SpecialName>("invocation function for block in ", Encoding);
5529 }
5530
5531 Node *Ty = getDerived().parseType();
5532 if (numLeft() != 0)
5533 return nullptr;
5534 return Ty;
5535}
5536
5537template <typename Alloc>
5538struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
5539 using AbstractManglingParser<ManglingParser<Alloc>,
5540 Alloc>::AbstractManglingParser;
5541};
5542
5543DEMANGLE_NAMESPACE_END
5544
5545#endif // DEMANGLE_ITANIUMDEMANGLE_H
lib/libcxxabi/src/demangle/README.txt created+52
...@@ -0,0 +1,52 @@
1Itanium Name Demangler Library
2==============================
3
4Introduction
5------------
6
7This directory contains the generic itanium name demangler library. The main
8purpose of the library is to demangle C++ symbols, i.e. convert the string
9"_Z1fv" into "f()". You can also use the CRTP base ManglingParser to perform
10some simple analysis on the mangled name, or (in LLVM) use the opaque
11ItaniumPartialDemangler to query the demangled AST.
12
13Why are there multiple copies of the this library in the source tree?
14---------------------------------------------------------------------
15
16This directory is mirrored between libcxxabi/demangle and
17llvm/include/llvm/Demangle. The simple reason for this is that both projects
18need to demangle symbols, but neither can depend on each other. libcxxabi needs
19the demangler to implement __cxa_demangle, which is part of the itanium ABI
20spec. LLVM needs a copy for a bunch of places, but doesn't want to use the
21system's __cxa_demangle because it a) might not be available (i.e., on Windows),
22and b) probably isn't that up-to-date on the latest language features.
23
24The copy of the demangler in LLVM has some extra stuff that aren't needed in
25libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), which depend on the
26shared generic components. Despite these differences, we want to keep the "core"
27generic demangling library identical between both copies to simplify development
28and testing.
29
30If you're working on the generic library, then do the work first in libcxxabi,
31then run the cp-to-llvm.sh script in src/demangle. This script takes as an
32argument the path to llvm, and re-copies the changes you made to libcxxabi over.
33Note that this script just blindly overwrites all changes to the generic library
34in llvm, so be careful.
35
36Because the core demangler needs to work in libcxxabi, everything needs to be
37declared in an anonymous namespace (see DEMANGLE_NAMESPACE_BEGIN), and you can't
38introduce any code that depends on the libcxx dylib.
39
40Hopefully, when LLVM becomes a monorepo, we can de-duplicate this code, and have
41both LLVM and libcxxabi depend on a shared demangler library.
42
43Testing
44-------
45
46The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
47llvm/unittest/Demangle. The llvm directory should only get tests for stuff not
48included in the core library. In the future though, we should probably move all
49the tests to LLVM.
50
51It is also a really good idea to run libFuzzer after non-trivial changes, see
52libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html.
lib/libcxxabi/src/demangle/StringView.h created+126
...@@ -0,0 +1,126 @@
1//===--- StringView.h -------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// FIXME: Use std::string_view instead when we support C++17.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef DEMANGLE_STRINGVIEW_H
14#define DEMANGLE_STRINGVIEW_H
15
16#include "DemangleConfig.h"
17#include <algorithm>
18#include <cassert>
19#include <cstring>
20
21DEMANGLE_NAMESPACE_BEGIN
22
23class StringView {
24 const char *First;
25 const char *Last;
26
27public:
28 static const size_t npos = ~size_t(0);
29
30 template <size_t N>
31 StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
32 StringView(const char *First_, const char *Last_)
33 : First(First_), Last(Last_) {}
34 StringView(const char *First_, size_t Len)
35 : First(First_), Last(First_ + Len) {}
36 StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
37 StringView() : First(nullptr), Last(nullptr) {}
38
39 StringView substr(size_t From) const {
40 return StringView(begin() + From, size() - From);
41 }
42
43 size_t find(char C, size_t From = 0) const {
44 size_t FindBegin = std::min(From, size());
45 // Avoid calling memchr with nullptr.
46 if (FindBegin < size()) {
47 // Just forward to memchr, which is faster than a hand-rolled loop.
48 if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
49 return size_t(static_cast<const char *>(P) - First);
50 }
51 return npos;
52 }
53
54 StringView substr(size_t From, size_t To) const {
55 if (To >= size())
56 To = size() - 1;
57 if (From >= size())
58 From = size() - 1;
59 return StringView(First + From, First + To);
60 }
61
62 StringView dropFront(size_t N = 1) const {
63 if (N >= size())
64 N = size();
65 return StringView(First + N, Last);
66 }
67
68 StringView dropBack(size_t N = 1) const {
69 if (N >= size())
70 N = size();
71 return StringView(First, Last - N);
72 }
73
74 char front() const {
75 assert(!empty());
76 return *begin();
77 }
78
79 char back() const {
80 assert(!empty());
81 return *(end() - 1);
82 }
83
84 char popFront() {
85 assert(!empty());
86 return *First++;
87 }
88
89 bool consumeFront(char C) {
90 if (!startsWith(C))
91 return false;
92 *this = dropFront(1);
93 return true;
94 }
95
96 bool consumeFront(StringView S) {
97 if (!startsWith(S))
98 return false;
99 *this = dropFront(S.size());
100 return true;
101 }
102
103 bool startsWith(char C) const { return !empty() && *begin() == C; }
104
105 bool startsWith(StringView Str) const {
106 if (Str.size() > size())
107 return false;
108 return std::equal(Str.begin(), Str.end(), begin());
109 }
110
111 const char &operator[](size_t Idx) const { return *(begin() + Idx); }
112
113 const char *begin() const { return First; }
114 const char *end() const { return Last; }
115 size_t size() const { return static_cast<size_t>(Last - First); }
116 bool empty() const { return First == Last; }
117};
118
119inline bool operator==(const StringView &LHS, const StringView &RHS) {
120 return LHS.size() == RHS.size() &&
121 std::equal(LHS.begin(), LHS.end(), RHS.begin());
122}
123
124DEMANGLE_NAMESPACE_END
125
126#endif
lib/libcxxabi/src/demangle/Utility.h created+191
...@@ -0,0 +1,191 @@
1//===--- Utility.h ----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Provide some utility classes for use in the demangler(s).
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef DEMANGLE_UTILITY_H
14#define DEMANGLE_UTILITY_H
15
16#include "StringView.h"
17#include <cstdint>
18#include <cstdlib>
19#include <cstring>
20#include <iterator>
21#include <limits>
22
23DEMANGLE_NAMESPACE_BEGIN
24
25// Stream that AST nodes write their string representation into after the AST
26// has been parsed.
27class OutputStream {
28 char *Buffer = nullptr;
29 size_t CurrentPosition = 0;
30 size_t BufferCapacity = 0;
31
32 // Ensure there is at least n more positions in buffer.
33 void grow(size_t N) {
34 if (N + CurrentPosition >= BufferCapacity) {
35 BufferCapacity *= 2;
36 if (BufferCapacity < N + CurrentPosition)
37 BufferCapacity = N + CurrentPosition;
38 Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
39 if (Buffer == nullptr)
40 std::terminate();
41 }
42 }
43
44 void writeUnsigned(uint64_t N, bool isNeg = false) {
45 // Handle special case...
46 if (N == 0) {
47 *this << '0';
48 return;
49 }
50
51 char Temp[21];
52 char *TempPtr = std::end(Temp);
53
54 while (N) {
55 *--TempPtr = '0' + char(N % 10);
56 N /= 10;
57 }
58
59 // Add negative sign...
60 if (isNeg)
61 *--TempPtr = '-';
62 this->operator<<(StringView(TempPtr, std::end(Temp)));
63 }
64
65public:
66 OutputStream(char *StartBuf, size_t Size)
67 : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
68 OutputStream() = default;
69 void reset(char *Buffer_, size_t BufferCapacity_) {
70 CurrentPosition = 0;
71 Buffer = Buffer_;
72 BufferCapacity = BufferCapacity_;
73 }
74
75 /// If a ParameterPackExpansion (or similar type) is encountered, the offset
76 /// into the pack that we're currently printing.
77 unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
78 unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
79
80 OutputStream &operator+=(StringView R) {
81 size_t Size = R.size();
82 if (Size == 0)
83 return *this;
84 grow(Size);
85 std::memmove(Buffer + CurrentPosition, R.begin(), Size);
86 CurrentPosition += Size;
87 return *this;
88 }
89
90 OutputStream &operator+=(char C) {
91 grow(1);
92 Buffer[CurrentPosition++] = C;
93 return *this;
94 }
95
96 OutputStream &operator<<(StringView R) { return (*this += R); }
97
98 OutputStream &operator<<(char C) { return (*this += C); }
99
100 OutputStream &operator<<(long long N) {
101 if (N < 0)
102 writeUnsigned(static_cast<unsigned long long>(-N), true);
103 else
104 writeUnsigned(static_cast<unsigned long long>(N));
105 return *this;
106 }
107
108 OutputStream &operator<<(unsigned long long N) {
109 writeUnsigned(N, false);
110 return *this;
111 }
112
113 OutputStream &operator<<(long N) {
114 return this->operator<<(static_cast<long long>(N));
115 }
116
117 OutputStream &operator<<(unsigned long N) {
118 return this->operator<<(static_cast<unsigned long long>(N));
119 }
120
121 OutputStream &operator<<(int N) {
122 return this->operator<<(static_cast<long long>(N));
123 }
124
125 OutputStream &operator<<(unsigned int N) {
126 return this->operator<<(static_cast<unsigned long long>(N));
127 }
128
129 size_t getCurrentPosition() const { return CurrentPosition; }
130 void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
131
132 char back() const {
133 return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
134 }
135
136 bool empty() const { return CurrentPosition == 0; }
137
138 char *getBuffer() { return Buffer; }
139 char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
140 size_t getBufferCapacity() const { return BufferCapacity; }
141};
142
143template <class T> class SwapAndRestore {
144 T &Restore;
145 T OriginalValue;
146 bool ShouldRestore = true;
147
148public:
149 SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
150
151 SwapAndRestore(T &Restore_, T NewVal)
152 : Restore(Restore_), OriginalValue(Restore) {
153 Restore = std::move(NewVal);
154 }
155 ~SwapAndRestore() {
156 if (ShouldRestore)
157 Restore = std::move(OriginalValue);
158 }
159
160 void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
161
162 void restoreNow(bool Force) {
163 if (!Force && !ShouldRestore)
164 return;
165
166 Restore = std::move(OriginalValue);
167 ShouldRestore = false;
168 }
169
170 SwapAndRestore(const SwapAndRestore &) = delete;
171 SwapAndRestore &operator=(const SwapAndRestore &) = delete;
172};
173
174inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
175 size_t InitSize) {
176 size_t BufferSize;
177 if (Buf == nullptr) {
178 Buf = static_cast<char *>(std::malloc(InitSize));
179 if (Buf == nullptr)
180 return false;
181 BufferSize = InitSize;
182 } else
183 BufferSize = *N;
184
185 S.reset(Buf, BufferSize);
186 return true;
187}
188
189DEMANGLE_NAMESPACE_END
190
191#endif
lib/libcxxabi/src/demangle/cp-to-llvm.sh created+27
...@@ -0,0 +1,27 @@
1#!/bin/bash
2
3# Copies the 'demangle' library, excluding 'DemangleConfig.h', to llvm. If no
4# llvm directory is specified, then assume a monorepo layout.
5
6set -e
7
8FILES="ItaniumDemangle.h StringView.h Utility.h README.txt"
9LLVM_DEMANGLE_DIR=$1
10
11if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then
12 LLVM_DEMANGLE_DIR="../../../llvm/include/llvm/Demangle"
13fi
14
15if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
16 echo "No such directory: $LLVM_DEMANGLE_DIR" >&2
17 exit 1
18fi
19
20read -p "This will overwrite the copies of $FILES in $LLVM_DEMANGLE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
21echo
22
23if [[ $ANSWER =~ ^[Yy]$ ]]; then
24 for I in $FILES ; do
25 cp $I $LLVM_DEMANGLE_DIR/$I
26 done
27fi
lib/libcxxabi/src/fallback_malloc.cpp created+259
...@@ -0,0 +1,259 @@
1//===------------------------ fallback_malloc.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
10// is only defined when libc aligned allocation is not available.
11#define _LIBCPP_BUILDING_LIBRARY
12#include "fallback_malloc.h"
13
14#include <__threading_support>
15#ifndef _LIBCXXABI_HAS_NO_THREADS
16#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
17#pragma comment(lib, "pthread")
18#endif
19#endif
20
21#include <stdlib.h> // for malloc, calloc, free
22#include <string.h> // for memset
23
24// A small, simple heap manager based (loosely) on
25// the startup heap manager from FreeBSD, optimized for space.
26//
27// Manages a fixed-size memory pool, supports malloc and free only.
28// No support for realloc.
29//
30// Allocates chunks in multiples of four bytes, with a four byte header
31// for each chunk. The overhead of each chunk is kept low by keeping pointers
32// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
33
34namespace {
35
36// When POSIX threads are not available, make the mutex operations a nop
37#ifndef _LIBCXXABI_HAS_NO_THREADS
38_LIBCPP_SAFE_STATIC
39static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
40#else
41static void* heap_mutex = 0;
42#endif
43
44class mutexor {
45public:
46#ifndef _LIBCXXABI_HAS_NO_THREADS
47 mutexor(std::__libcpp_mutex_t* m) : mtx_(m) {
48 std::__libcpp_mutex_lock(mtx_);
49 }
50 ~mutexor() { std::__libcpp_mutex_unlock(mtx_); }
51#else
52 mutexor(void*) {}
53 ~mutexor() {}
54#endif
55private:
56 mutexor(const mutexor& rhs);
57 mutexor& operator=(const mutexor& rhs);
58#ifndef _LIBCXXABI_HAS_NO_THREADS
59 std::__libcpp_mutex_t* mtx_;
60#endif
61};
62
63static const size_t HEAP_SIZE = 512;
64char heap[HEAP_SIZE] __attribute__((aligned));
65
66typedef unsigned short heap_offset;
67typedef unsigned short heap_size;
68
69struct heap_node {
70 heap_offset next_node; // offset into heap
71 heap_size len; // size in units of "sizeof(heap_node)"
72};
73
74static const heap_node* list_end =
75 (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap
76static heap_node* freelist = NULL;
77
78heap_node* node_from_offset(const heap_offset offset) {
79 return (heap_node*)(heap + (offset * sizeof(heap_node)));
80}
81
82heap_offset offset_from_node(const heap_node* ptr) {
83 return static_cast<heap_offset>(
84 static_cast<size_t>(reinterpret_cast<const char*>(ptr) - heap) /
85 sizeof(heap_node));
86}
87
88void init_heap() {
89 freelist = (heap_node*)heap;
90 freelist->next_node = offset_from_node(list_end);
91 freelist->len = HEAP_SIZE / sizeof(heap_node);
92}
93
94// How big a chunk we allocate
95size_t alloc_size(size_t len) {
96 return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1;
97}
98
99bool is_fallback_ptr(void* ptr) {
100 return ptr >= heap && ptr < (heap + HEAP_SIZE);
101}
102
103void* fallback_malloc(size_t len) {
104 heap_node *p, *prev;
105 const size_t nelems = alloc_size(len);
106 mutexor mtx(&heap_mutex);
107
108 if (NULL == freelist)
109 init_heap();
110
111 // Walk the free list, looking for a "big enough" chunk
112 for (p = freelist, prev = 0; p && p != list_end;
113 prev = p, p = node_from_offset(p->next_node)) {
114
115 if (p->len > nelems) { // chunk is larger, shorten, and return the tail
116 heap_node* q;
117
118 p->len = static_cast<heap_size>(p->len - nelems);
119 q = p + p->len;
120 q->next_node = 0;
121 q->len = static_cast<heap_size>(nelems);
122 return (void*)(q + 1);
123 }
124
125 if (p->len == nelems) { // exact size match
126 if (prev == 0)
127 freelist = node_from_offset(p->next_node);
128 else
129 prev->next_node = p->next_node;
130 p->next_node = 0;
131 return (void*)(p + 1);
132 }
133 }
134 return NULL; // couldn't find a spot big enough
135}
136
137// Return the start of the next block
138heap_node* after(struct heap_node* p) { return p + p->len; }
139
140void fallback_free(void* ptr) {
141 struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk
142 struct heap_node *p, *prev;
143
144 mutexor mtx(&heap_mutex);
145
146#ifdef DEBUG_FALLBACK_MALLOC
147 std::cout << "Freeing item at " << offset_from_node(cp) << " of size "
148 << cp->len << std::endl;
149#endif
150
151 for (p = freelist, prev = 0; p && p != list_end;
152 prev = p, p = node_from_offset(p->next_node)) {
153#ifdef DEBUG_FALLBACK_MALLOC
154 std::cout << " p, cp, after (p), after(cp) " << offset_from_node(p) << ' '
155 << offset_from_node(cp) << ' ' << offset_from_node(after(p))
156 << ' ' << offset_from_node(after(cp)) << std::endl;
157#endif
158 if (after(p) == cp) {
159#ifdef DEBUG_FALLBACK_MALLOC
160 std::cout << " Appending onto chunk at " << offset_from_node(p)
161 << std::endl;
162#endif
163 p->len = static_cast<heap_size>(
164 p->len + cp->len); // make the free heap_node larger
165 return;
166 } else if (after(cp) == p) { // there's a free heap_node right after
167#ifdef DEBUG_FALLBACK_MALLOC
168 std::cout << " Appending free chunk at " << offset_from_node(p)
169 << std::endl;
170#endif
171 cp->len = static_cast<heap_size>(cp->len + p->len);
172 if (prev == 0) {
173 freelist = cp;
174 cp->next_node = p->next_node;
175 } else
176 prev->next_node = offset_from_node(cp);
177 return;
178 }
179 }
180// Nothing to merge with, add it to the start of the free list
181#ifdef DEBUG_FALLBACK_MALLOC
182 std::cout << " Making new free list entry " << offset_from_node(cp)
183 << std::endl;
184#endif
185 cp->next_node = offset_from_node(freelist);
186 freelist = cp;
187}
188
189#ifdef INSTRUMENT_FALLBACK_MALLOC
190size_t print_free_list() {
191 struct heap_node *p, *prev;
192 heap_size total_free = 0;
193 if (NULL == freelist)
194 init_heap();
195
196 for (p = freelist, prev = 0; p && p != list_end;
197 prev = p, p = node_from_offset(p->next_node)) {
198 std::cout << (prev == 0 ? "" : " ") << "Offset: " << offset_from_node(p)
199 << "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
200 total_free += p->len;
201 }
202 std::cout << "Total Free space: " << total_free << std::endl;
203 return total_free;
204}
205#endif
206} // end unnamed namespace
207
208namespace __cxxabiv1 {
209
210struct __attribute__((aligned)) __aligned_type {};
211
212void* __aligned_malloc_with_fallback(size_t size) {
213#if defined(_WIN32)
214 if (void* dest = _aligned_malloc(size, alignof(__aligned_type)))
215 return dest;
216#elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
217 if (void* dest = ::malloc(size))
218 return dest;
219#else
220 if (size == 0)
221 size = 1;
222 void* dest;
223 if (::posix_memalign(&dest, __alignof(__aligned_type), size) == 0)
224 return dest;
225#endif
226 return fallback_malloc(size);
227}
228
229void* __calloc_with_fallback(size_t count, size_t size) {
230 void* ptr = ::calloc(count, size);
231 if (NULL != ptr)
232 return ptr;
233 // if calloc fails, fall back to emergency stash
234 ptr = fallback_malloc(size * count);
235 if (NULL != ptr)
236 ::memset(ptr, 0, size * count);
237 return ptr;
238}
239
240void __aligned_free_with_fallback(void* ptr) {
241 if (is_fallback_ptr(ptr))
242 fallback_free(ptr);
243 else {
244#if defined(_WIN32)
245 ::_aligned_free(ptr);
246#else
247 ::free(ptr);
248#endif
249 }
250}
251
252void __free_with_fallback(void* ptr) {
253 if (is_fallback_ptr(ptr))
254 fallback_free(ptr);
255 else
256 ::free(ptr);
257}
258
259} // namespace __cxxabiv1
lib/libcxxabi/src/fallback_malloc.h created+28
...@@ -0,0 +1,28 @@
1//===------------------------- fallback_malloc.h --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _FALLBACK_MALLOC_H
10#define _FALLBACK_MALLOC_H
11
12#include "__cxxabi_config.h"
13#include <stddef.h> // for size_t
14
15namespace __cxxabiv1 {
16
17// Allocate some memory from _somewhere_
18_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size);
19
20// Allocate and zero-initialize memory from _somewhere_
21_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size);
22
23_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr);
24_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr);
25
26} // namespace __cxxabiv1
27
28#endif
lib/libcxxabi/src/include/atomic_support.h created+210
...@@ -0,0 +1,210 @@
1//===----------------------------------------------------------------------===////
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===////
8
9// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead
10// of duplicating the file in libc++abi we should require that the libc++
11// sources are available when building libc++abi.
12
13#ifndef ATOMIC_SUPPORT_H
14#define ATOMIC_SUPPORT_H
15
16#include "__config"
17#include "memory" // for __libcpp_relaxed_load
18
19#if defined(__clang__) && __has_builtin(__atomic_load_n) \
20 && __has_builtin(__atomic_store_n) \
21 && __has_builtin(__atomic_add_fetch) \
22 && __has_builtin(__atomic_exchange_n) \
23 && __has_builtin(__atomic_compare_exchange_n) \
24 && defined(__ATOMIC_RELAXED) \
25 && defined(__ATOMIC_CONSUME) \
26 && defined(__ATOMIC_ACQUIRE) \
27 && defined(__ATOMIC_RELEASE) \
28 && defined(__ATOMIC_ACQ_REL) \
29 && defined(__ATOMIC_SEQ_CST)
30# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
31#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
32# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
33#endif
34
35#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
36# if defined(_LIBCPP_WARNING)
37 _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
38# else
39# warning Building libc++ without __atomic builtins is unsupported
40# endif
41#endif
42
43_LIBCPP_BEGIN_NAMESPACE_STD
44
45namespace {
46
47#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
48
49enum __libcpp_atomic_order {
50 _AO_Relaxed = __ATOMIC_RELAXED,
51 _AO_Consume = __ATOMIC_CONSUME,
52 _AO_Acquire = __ATOMIC_ACQUIRE,
53 _AO_Release = __ATOMIC_RELEASE,
54 _AO_Acq_Rel = __ATOMIC_ACQ_REL,
55 _AO_Seq = __ATOMIC_SEQ_CST
56};
57
58template <class _ValueType, class _FromType>
59inline _LIBCPP_INLINE_VISIBILITY
60void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
61 int __order = _AO_Seq)
62{
63 __atomic_store_n(__dest, __val, __order);
64}
65
66template <class _ValueType, class _FromType>
67inline _LIBCPP_INLINE_VISIBILITY
68void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
69{
70 __atomic_store_n(__dest, __val, _AO_Relaxed);
71}
72
73template <class _ValueType>
74inline _LIBCPP_INLINE_VISIBILITY
75_ValueType __libcpp_atomic_load(_ValueType const* __val,
76 int __order = _AO_Seq)
77{
78 return __atomic_load_n(__val, __order);
79}
80
81template <class _ValueType, class _AddType>
82inline _LIBCPP_INLINE_VISIBILITY
83_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
84 int __order = _AO_Seq)
85{
86 return __atomic_add_fetch(__val, __a, __order);
87}
88
89template <class _ValueType>
90inline _LIBCPP_INLINE_VISIBILITY
91_ValueType __libcpp_atomic_exchange(_ValueType* __target,
92 _ValueType __value, int __order = _AO_Seq)
93{
94 return __atomic_exchange_n(__target, __value, __order);
95}
96
97template <class _ValueType>
98inline _LIBCPP_INLINE_VISIBILITY
99bool __libcpp_atomic_compare_exchange(_ValueType* __val,
100 _ValueType* __expected, _ValueType __after,
101 int __success_order = _AO_Seq,
102 int __fail_order = _AO_Seq)
103{
104 return __atomic_compare_exchange_n(__val, __expected, __after, true,
105 __success_order, __fail_order);
106}
107
108#else // _LIBCPP_HAS_NO_THREADS
109
110enum __libcpp_atomic_order {
111 _AO_Relaxed,
112 _AO_Consume,
113 _AO_Acquire,
114 _AO_Release,
115 _AO_Acq_Rel,
116 _AO_Seq
117};
118
119template <class _ValueType, class _FromType>
120inline _LIBCPP_INLINE_VISIBILITY
121void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
122 int = 0)
123{
124 *__dest = __val;
125}
126
127template <class _ValueType, class _FromType>
128inline _LIBCPP_INLINE_VISIBILITY
129void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
130{
131 *__dest = __val;
132}
133
134template <class _ValueType>
135inline _LIBCPP_INLINE_VISIBILITY
136_ValueType __libcpp_atomic_load(_ValueType const* __val,
137 int = 0)
138{
139 return *__val;
140}
141
142template <class _ValueType, class _AddType>
143inline _LIBCPP_INLINE_VISIBILITY
144_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
145 int = 0)
146{
147 return *__val += __a;
148}
149
150template <class _ValueType>
151inline _LIBCPP_INLINE_VISIBILITY
152_ValueType __libcpp_atomic_exchange(_ValueType* __target,
153 _ValueType __value, int = _AO_Seq)
154{
155 _ValueType old = *__target;
156 *__target = __value;
157 return old;
158}
159
160template <class _ValueType>
161inline _LIBCPP_INLINE_VISIBILITY
162bool __libcpp_atomic_compare_exchange(_ValueType* __val,
163 _ValueType* __expected, _ValueType __after,
164 int = 0, int = 0)
165{
166 if (*__val == *__expected) {
167 *__val = __after;
168 return true;
169 }
170 *__expected = *__val;
171 return false;
172}
173
174#endif // _LIBCPP_HAS_NO_THREADS
175
176} // end namespace
177
178_LIBCPP_END_NAMESPACE_STD
179
180namespace {
181
182template <class IntType>
183class AtomicInt {
184public:
185 using MemoryOrder = std::__libcpp_atomic_order;
186
187 explicit AtomicInt(IntType *b) : b(b) {}
188 AtomicInt(AtomicInt const&) = delete;
189 AtomicInt& operator=(AtomicInt const&) = delete;
190
191 IntType load(MemoryOrder ord) {
192 return std::__libcpp_atomic_load(b, ord);
193 }
194 void store(IntType val, MemoryOrder ord) {
195 std::__libcpp_atomic_store(b, val, ord);
196 }
197 IntType exchange(IntType new_val, MemoryOrder ord) {
198 return std::__libcpp_atomic_exchange(b, new_val, ord);
199 }
200 bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
201 return std::__libcpp_atomic_compare_exchange(b, expected, desired, ord_success, ord_failure);
202 }
203
204private:
205 IntType *b;
206};
207
208} // end namespace
209
210#endif // ATOMIC_SUPPORT_H
lib/libcxxabi/src/include/refstring.h created+131
...@@ -0,0 +1,131 @@
1//===------------------------ __refstring ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of
10// duplicating the file in libc++abi we should require that the libc++ sources
11// are available when building libc++abi.
12
13#ifndef _LIBCPPABI_REFSTRING_H
14#define _LIBCPPABI_REFSTRING_H
15
16#include <__config>
17#include <stdexcept>
18#include <cstddef>
19#include <cstring>
20#ifdef __APPLE__
21#include <dlfcn.h>
22#include <mach-o/dyld.h>
23#endif
24#include "atomic_support.h"
25
26_LIBCPP_BEGIN_NAMESPACE_STD
27
28namespace __refstring_imp { namespace {
29typedef int count_t;
30
31struct _Rep_base {
32 std::size_t len;
33 std::size_t cap;
34 count_t count;
35};
36
37inline _Rep_base* rep_from_data(const char *data_) noexcept {
38 char *data = const_cast<char *>(data_);
39 return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base));
40}
41
42inline char * data_from_rep(_Rep_base *rep) noexcept {
43 char *data = reinterpret_cast<char *>(rep);
44 return data + sizeof(*rep);
45}
46
47#if defined(__APPLE__)
48inline
49const char* compute_gcc_empty_string_storage() _NOEXCEPT
50{
51 void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
52 if (handle == nullptr)
53 return nullptr;
54 void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE");
55 if (sym == nullptr)
56 return nullptr;
57 return data_from_rep(reinterpret_cast<_Rep_base *>(sym));
58}
59
60inline
61const char*
62get_gcc_empty_string_storage() _NOEXCEPT
63{
64 static const char* p = compute_gcc_empty_string_storage();
65 return p;
66}
67#endif
68
69}} // namespace __refstring_imp
70
71using namespace __refstring_imp;
72
73inline
74__libcpp_refstring::__libcpp_refstring(const char* msg) {
75 std::size_t len = strlen(msg);
76 _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1));
77 rep->len = len;
78 rep->cap = len;
79 rep->count = 0;
80 char *data = data_from_rep(rep);
81 std::memcpy(data, msg, len + 1);
82 __imp_ = data;
83}
84
85inline
86__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
87 : __imp_(s.__imp_)
88{
89 if (__uses_refcount())
90 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
91}
92
93inline
94__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT {
95 bool adjust_old_count = __uses_refcount();
96 struct _Rep_base *old_rep = rep_from_data(__imp_);
97 __imp_ = s.__imp_;
98 if (__uses_refcount())
99 __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
100 if (adjust_old_count)
101 {
102 if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
103 {
104 ::operator delete(old_rep);
105 }
106 }
107 return *this;
108}
109
110inline
111__libcpp_refstring::~__libcpp_refstring() {
112 if (__uses_refcount()) {
113 _Rep_base* rep = rep_from_data(__imp_);
114 if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
115 ::operator delete(rep);
116 }
117 }
118}
119
120inline
121bool __libcpp_refstring::__uses_refcount() const {
122#ifdef __APPLE__
123 return __imp_ != get_gcc_empty_string_storage();
124#else
125 return true;
126#endif
127}
128
129_LIBCPP_END_NAMESPACE_STD
130
131#endif //_LIBCPPABI_REFSTRING_H
lib/libcxxabi/src/private_typeinfo.cpp created+1291
...@@ -0,0 +1,1291 @@
1//===----------------------- private_typeinfo.cpp -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "private_typeinfo.h"
10
11// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more
12// forgiving when type_info's mistakenly have hidden visibility and thus
13// multiple type_infos can exist for a single type.
14//
15// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where
16// there is a detected inconsistency in the type_info hierarchy during a
17// dynamic_cast, then the equality operation will fall back to using strcmp
18// on type_info names to determine type_info equality.
19//
20// This change happens *only* under dynamic_cast, and only when
21// dynamic_cast is faced with the choice: abort, or possibly give back the
22// wrong answer. If when the dynamic_cast is done with this fallback
23// algorithm and an inconsistency is still detected, dynamic_cast will call
24// abort with an appropriate message.
25//
26// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
27// printf-like function called syslog:
28//
29// void syslog(int facility_priority, const char* format, ...);
30//
31// If you want this functionality but your platform doesn't have syslog,
32// just implement it in terms of fprintf(stderr, ...).
33//
34// _LIBCXX_DYNAMIC_FALLBACK is currently off by default.
35
36// On Windows, typeids are different between DLLs and EXEs, so comparing
37// type_info* will work for typeids from the same compiled file but fail
38// for typeids from a DLL and an executable. Among other things, exceptions
39// are not caught by handlers since can_catch() returns false.
40//
41// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls
42// is_equal() with use_strcmp=false so the string names are not compared.
43
44#include <string.h>
45
46#ifdef _LIBCXX_DYNAMIC_FALLBACK
47#include "abort_message.h"
48#include <sys/syslog.h>
49#endif
50
51static inline
52bool
53is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp)
54{
55 // Use std::type_info's default comparison unless we've explicitly asked
56 // for strcmp.
57 if (!use_strcmp)
58 return *x == *y;
59 // Still allow pointer equality to short circut.
60 return x == y || strcmp(x->name(), y->name()) == 0;
61}
62
63namespace __cxxabiv1
64{
65
66// __shim_type_info
67
68__shim_type_info::~__shim_type_info()
69{
70}
71
72void __shim_type_info::noop1() const {}
73void __shim_type_info::noop2() const {}
74
75// __fundamental_type_info
76
77// This miraculously (compiler magic) emits the type_info's for:
78// 1. all of the fundamental types
79// 2. pointers to all of the fundamental types
80// 3. pointers to all of the const fundamental types
81__fundamental_type_info::~__fundamental_type_info()
82{
83}
84
85// __array_type_info
86
87__array_type_info::~__array_type_info()
88{
89}
90
91// __function_type_info
92
93__function_type_info::~__function_type_info()
94{
95}
96
97// __enum_type_info
98
99__enum_type_info::~__enum_type_info()
100{
101}
102
103// __class_type_info
104
105__class_type_info::~__class_type_info()
106{
107}
108
109// __si_class_type_info
110
111__si_class_type_info::~__si_class_type_info()
112{
113}
114
115// __vmi_class_type_info
116
117__vmi_class_type_info::~__vmi_class_type_info()
118{
119}
120
121// __pbase_type_info
122
123__pbase_type_info::~__pbase_type_info()
124{
125}
126
127// __pointer_type_info
128
129__pointer_type_info::~__pointer_type_info()
130{
131}
132
133// __pointer_to_member_type_info
134
135__pointer_to_member_type_info::~__pointer_to_member_type_info()
136{
137}
138
139// can_catch
140
141// A handler is a match for an exception object of type E if
142// 1. The handler is of type cv T or cv T& and E and T are the same type
143// (ignoring the top-level cv-qualifiers), or
144// 2. the handler is of type cv T or cv T& and T is an unambiguous public
145// base class of E, or
146// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be
147// converted to the type of the handler by either or both of
148// A. a standard pointer conversion (4.10) not involving conversions to
149// pointers to private or protected or ambiguous classes
150// B. a qualification conversion
151// 4. the handler is a pointer or pointer to member type and E is
152// std::nullptr_t.
153
154// adjustedPtr:
155//
156// catch (A& a) : adjustedPtr == &a
157// catch (A* a) : adjustedPtr == a
158// catch (A** a) : adjustedPtr == a
159//
160// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)
161// catch (D2* d2) : adjustedPtr == d2
162// catch (D2*& d2) : adjustedPtr == d2
163//
164// catch (...) : adjustedPtr == & of the exception
165//
166// If the thrown type is nullptr_t and the caught type is a pointer to
167// member type, adjustedPtr points to a statically-allocated null pointer
168// representation of that type.
169
170// Handles bullet 1
171bool
172__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,
173 void*&) const
174{
175 return is_equal(this, thrown_type, false);
176}
177
178bool
179__array_type_info::can_catch(const __shim_type_info*, void*&) const
180{
181 // We can get here if someone tries to catch an array by reference.
182 // However if someone tries to throw an array, it immediately gets
183 // converted to a pointer, which will not convert back to an array
184 // at the catch clause. So this can never catch anything.
185 return false;
186}
187
188bool
189__function_type_info::can_catch(const __shim_type_info*, void*&) const
190{
191 // We can get here if someone tries to catch a function by reference.
192 // However if someone tries to throw a function, it immediately gets
193 // converted to a pointer, which will not convert back to a function
194 // at the catch clause. So this can never catch anything.
195 return false;
196}
197
198// Handles bullet 1
199bool
200__enum_type_info::can_catch(const __shim_type_info* thrown_type,
201 void*&) const
202{
203 return is_equal(this, thrown_type, false);
204}
205
206#ifdef __clang__
207#pragma clang diagnostic push
208#pragma clang diagnostic ignored "-Wmissing-field-initializers"
209#endif
210
211// Handles bullets 1 and 2
212bool
213__class_type_info::can_catch(const __shim_type_info* thrown_type,
214 void*& adjustedPtr) const
215{
216 // bullet 1
217 if (is_equal(this, thrown_type, false))
218 return true;
219 const __class_type_info* thrown_class_type =
220 dynamic_cast<const __class_type_info*>(thrown_type);
221 if (thrown_class_type == 0)
222 return false;
223 // bullet 2
224 __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
225 info.number_of_dst_type = 1;
226 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
227 if (info.path_dst_ptr_to_static_ptr == public_path)
228 {
229 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
230 return true;
231 }
232 return false;
233}
234
235#ifdef __clang__
236#pragma clang diagnostic pop
237#endif
238
239void
240__class_type_info::process_found_base_class(__dynamic_cast_info* info,
241 void* adjustedPtr,
242 int path_below) const
243{
244 if (info->dst_ptr_leading_to_static_ptr == 0)
245 {
246 // First time here
247 info->dst_ptr_leading_to_static_ptr = adjustedPtr;
248 info->path_dst_ptr_to_static_ptr = path_below;
249 info->number_to_static_ptr = 1;
250 }
251 else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
252 {
253 // We've been here before. Update path to "most public"
254 if (info->path_dst_ptr_to_static_ptr == not_public_path)
255 info->path_dst_ptr_to_static_ptr = path_below;
256 }
257 else
258 {
259 // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
260 // to a static_type
261 info->number_to_static_ptr += 1;
262 info->path_dst_ptr_to_static_ptr = not_public_path;
263 info->search_done = true;
264 }
265}
266
267void
268__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
269 void* adjustedPtr,
270 int path_below) const
271{
272 if (is_equal(this, info->static_type, false))
273 process_found_base_class(info, adjustedPtr, path_below);
274}
275
276void
277__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
278 void* adjustedPtr,
279 int path_below) const
280{
281 if (is_equal(this, info->static_type, false))
282 process_found_base_class(info, adjustedPtr, path_below);
283 else
284 __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
285}
286
287void
288__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
289 void* adjustedPtr,
290 int path_below) const
291{
292 ptrdiff_t offset_to_base = 0;
293 if (adjustedPtr != nullptr)
294 {
295 offset_to_base = __offset_flags >> __offset_shift;
296 if (__offset_flags & __virtual_mask)
297 {
298 const char* vtable = *static_cast<const char*const*>(adjustedPtr);
299 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
300 }
301 }
302 __base_type->has_unambiguous_public_base(
303 info,
304 static_cast<char*>(adjustedPtr) + offset_to_base,
305 (__offset_flags & __public_mask) ? path_below : not_public_path);
306}
307
308void
309__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
310 void* adjustedPtr,
311 int path_below) const
312{
313 if (is_equal(this, info->static_type, false))
314 process_found_base_class(info, adjustedPtr, path_below);
315 else
316 {
317 typedef const __base_class_type_info* Iter;
318 const Iter e = __base_info + __base_count;
319 Iter p = __base_info;
320 p->has_unambiguous_public_base(info, adjustedPtr, path_below);
321 if (++p < e)
322 {
323 do
324 {
325 p->has_unambiguous_public_base(info, adjustedPtr, path_below);
326 if (info->search_done)
327 break;
328 } while (++p < e);
329 }
330 }
331}
332
333// Handles bullet 1 for both pointers and member pointers
334bool
335__pbase_type_info::can_catch(const __shim_type_info* thrown_type,
336 void*&) const
337{
338 bool use_strcmp = this->__flags & (__incomplete_class_mask |
339 __incomplete_mask);
340 if (!use_strcmp) {
341 const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>(
342 thrown_type);
343 if (!thrown_pbase) return false;
344 use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask |
345 __incomplete_mask);
346 }
347 return is_equal(this, thrown_type, use_strcmp);
348}
349
350#ifdef __clang__
351#pragma clang diagnostic push
352#pragma clang diagnostic ignored "-Wmissing-field-initializers"
353#endif
354
355// Handles bullets 1, 3 and 4
356// NOTE: It might not be safe to adjust the pointer if it is not not a pointer
357// type. Only adjust the pointer after we know it is safe to do so.
358bool
359__pointer_type_info::can_catch(const __shim_type_info* thrown_type,
360 void*& adjustedPtr) const
361{
362 // bullet 4
363 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
364 adjustedPtr = nullptr;
365 return true;
366 }
367
368 // bullet 1
369 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) {
370 if (adjustedPtr != NULL)
371 adjustedPtr = *static_cast<void**>(adjustedPtr);
372 return true;
373 }
374 // bullet 3
375 const __pointer_type_info* thrown_pointer_type =
376 dynamic_cast<const __pointer_type_info*>(thrown_type);
377 if (thrown_pointer_type == 0)
378 return false;
379 // Do the dereference adjustment
380 if (adjustedPtr != NULL)
381 adjustedPtr = *static_cast<void**>(adjustedPtr);
382 // bullet 3B and 3C
383 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)
384 return false;
385 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)
386 return false;
387 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
388 return true;
389 // bullet 3A
390 if (is_equal(__pointee, &typeid(void), false)) {
391 // pointers to functions cannot be converted to void*.
392 // pointers to member functions are not handled here.
393 const __function_type_info* thrown_function =
394 dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee);
395 return (thrown_function == nullptr);
396 }
397 // Handle pointer to pointer
398 const __pointer_type_info* nested_pointer_type =
399 dynamic_cast<const __pointer_type_info*>(__pointee);
400 if (nested_pointer_type) {
401 if (~__flags & __const_mask) return false;
402 return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee);
403 }
404
405 // Handle pointer to pointer to member
406 const __pointer_to_member_type_info* member_ptr_type =
407 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
408 if (member_ptr_type) {
409 if (~__flags & __const_mask) return false;
410 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
411 }
412
413 // Handle pointer to class type
414 const __class_type_info* catch_class_type =
415 dynamic_cast<const __class_type_info*>(__pointee);
416 if (catch_class_type == 0)
417 return false;
418 const __class_type_info* thrown_class_type =
419 dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
420 if (thrown_class_type == 0)
421 return false;
422 __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
423 info.number_of_dst_type = 1;
424 thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
425 if (info.path_dst_ptr_to_static_ptr == public_path)
426 {
427 if (adjustedPtr != NULL)
428 adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
429 return true;
430 }
431 return false;
432}
433
434bool __pointer_type_info::can_catch_nested(
435 const __shim_type_info* thrown_type) const
436{
437 const __pointer_type_info* thrown_pointer_type =
438 dynamic_cast<const __pointer_type_info*>(thrown_type);
439 if (thrown_pointer_type == 0)
440 return false;
441 // bullet 3B
442 if (thrown_pointer_type->__flags & ~__flags)
443 return false;
444 if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
445 return true;
446 // If the pointed to types differ then the catch type must be const
447 // qualified.
448 if (~__flags & __const_mask)
449 return false;
450
451 // Handle pointer to pointer
452 const __pointer_type_info* nested_pointer_type =
453 dynamic_cast<const __pointer_type_info*>(__pointee);
454 if (nested_pointer_type) {
455 return nested_pointer_type->can_catch_nested(
456 thrown_pointer_type->__pointee);
457 }
458
459 // Handle pointer to pointer to member
460 const __pointer_to_member_type_info* member_ptr_type =
461 dynamic_cast<const __pointer_to_member_type_info*>(__pointee);
462 if (member_ptr_type) {
463 return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee);
464 }
465
466 return false;
467}
468
469bool __pointer_to_member_type_info::can_catch(
470 const __shim_type_info* thrown_type, void*& adjustedPtr) const {
471 // bullet 4
472 if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) {
473 // We assume that the pointer to member representation is the same for
474 // all pointers to data members and for all pointers to member functions.
475 struct X {};
476 if (dynamic_cast<const __function_type_info*>(__pointee)) {
477 static int (X::*const null_ptr_rep)() = nullptr;
478 adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep);
479 } else {
480 static int X::*const null_ptr_rep = nullptr;
481 adjustedPtr = const_cast<int X::**>(&null_ptr_rep);
482 }
483 return true;
484 }
485
486 // bullet 1
487 if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
488 return true;
489
490 const __pointer_to_member_type_info* thrown_pointer_type =
491 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
492 if (thrown_pointer_type == 0)
493 return false;
494 if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask)
495 return false;
496 if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask)
497 return false;
498 if (!is_equal(__pointee, thrown_pointer_type->__pointee, false))
499 return false;
500 if (is_equal(__context, thrown_pointer_type->__context, false))
501 return true;
502
503 // [except.handle] does not allow the pointer-to-member conversions mentioned
504 // in [mem.conv] to take place. For this reason we don't check Derived->Base
505 // for Derived->Base conversions.
506
507 return false;
508}
509
510bool __pointer_to_member_type_info::can_catch_nested(
511 const __shim_type_info* thrown_type) const
512{
513 const __pointer_to_member_type_info* thrown_member_ptr_type =
514 dynamic_cast<const __pointer_to_member_type_info*>(thrown_type);
515 if (thrown_member_ptr_type == 0)
516 return false;
517 if (~__flags & thrown_member_ptr_type->__flags)
518 return false;
519 if (!is_equal(__pointee, thrown_member_ptr_type->__pointee, false))
520 return false;
521 if (!is_equal(__context, thrown_member_ptr_type->__context, false))
522 return false;
523 return true;
524}
525
526#ifdef __clang__
527#pragma clang diagnostic pop
528#endif
529
530#ifdef __clang__
531#pragma clang diagnostic push
532#pragma clang diagnostic ignored "-Wmissing-field-initializers"
533#endif
534
535// __dynamic_cast
536
537// static_ptr: pointer to an object of type static_type; nonnull, and since the
538// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
539// static_ptr is &v in the expression dynamic_cast<T>(v).
540// static_type: static type of the object pointed to by static_ptr.
541// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
542// src2dst_offset: a static hint about the location of the
543// source subobject with respect to the complete object;
544// special negative values are:
545// -1: no hint
546// -2: static_type is not a public base of dst_type
547// -3: static_type is a multiple public base type but never a
548// virtual base type
549// otherwise, the static_type type is a unique public nonvirtual
550// base type of dst_type at offset src2dst_offset from the
551// origin of dst_type.
552//
553// (dynamic_ptr, dynamic_type) are the run time type of the complete object
554// referred to by static_ptr and a pointer to it. These can be found from
555// static_ptr for polymorphic types.
556// static_type is guaranteed to be a polymorphic type.
557//
558// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
559// node of the tree represents a base class/object of its parent (or parents) below.
560// Each node is uniquely represented by a pointer to the object, and a pointer
561// to a type_info - its type. Different nodes may have the same pointer and
562// different nodes may have the same type. But only one node has a specific
563// (pointer-value, type) pair. In C++ two objects of the same type can not
564// share the same address.
565//
566// There are two flavors of nodes which have the type dst_type:
567// 1. Those that are derived from (below) (static_ptr, static_type).
568// 2. Those that are not derived from (below) (static_ptr, static_type).
569//
570// Invariants of the DAG:
571//
572// There is at least one path from the root (dynamic_ptr, dynamic_type) to
573// the node (static_ptr, static_type). This path may or may not be public.
574// There may be more than one such path (some public some not). Such a path may
575// or may not go through a node having type dst_type.
576//
577// No node of type T appears above a node of the same type. That means that
578// there is only one node with dynamic_type. And if dynamic_type == dst_type,
579// then there is only one dst_type in the DAG.
580//
581// No node of type dst_type appears above a node of type static_type. Such
582// DAG's are possible in C++, but the compiler computes those dynamic_casts at
583// compile time, and only calls __dynamic_cast when dst_type lies below
584// static_type in the DAG.
585//
586// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
587// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.
588//
589// Returns:
590//
591// If there is exactly one dst_type of flavor 1, and
592// If there is a public path from that dst_type to (static_ptr, static_type), or
593// If there are 0 dst_types of flavor 2, and there is a public path from
594// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
595// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
596// a pointer to that dst_type.
597// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
598// if there is a public path from (dynamic_ptr, dynamic_type) to
599// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
600// to the one dst_type, then return a pointer to that one dst_type.
601// Else return nullptr.
602//
603// If dynamic_type == dst_type, then the above algorithm collapses to the
604// following cheaper algorithm:
605//
606// If there is a public path from (dynamic_ptr, dynamic_type) to
607// (static_ptr, static_type), then return dynamic_ptr.
608// Else return nullptr.
609
610extern "C" _LIBCXXABI_FUNC_VIS void *
611__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
612 const __class_type_info *dst_type,
613 std::ptrdiff_t src2dst_offset) {
614 // Possible future optimization: Take advantage of src2dst_offset
615
616 // Get (dynamic_ptr, dynamic_type) from static_ptr
617 void **vtable = *static_cast<void ** const *>(static_ptr);
618 ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
619 const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
620 const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
621
622 // Initialize answer to nullptr. This will be changed from the search
623 // results if a non-null answer is found. Regardless, this is what will
624 // be returned.
625 const void* dst_ptr = 0;
626 // Initialize info struct for this search.
627 __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
628
629 // Find out if we can use a giant short cut in the search
630 if (is_equal(dynamic_type, dst_type, false))
631 {
632 // Using giant short cut. Add that information to info.
633 info.number_of_dst_type = 1;
634 // Do the search
635 dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
636#ifdef _LIBCXX_DYNAMIC_FALLBACK
637 // The following if should always be false because we should definitely
638 // find (static_ptr, static_type), either on a public or private path
639 if (info.path_dst_ptr_to_static_ptr == unknown)
640 {
641 // We get here only if there is some kind of visibility problem
642 // in client code.
643 syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
644 "should have public visibility. At least one of them is hidden. %s"
645 ", %s.\n", static_type->name(), dynamic_type->name());
646 // Redo the search comparing type_info's using strcmp
647 info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
648 info.number_of_dst_type = 1;
649 dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
650 }
651#endif // _LIBCXX_DYNAMIC_FALLBACK
652 // Query the search.
653 if (info.path_dst_ptr_to_static_ptr == public_path)
654 dst_ptr = dynamic_ptr;
655 }
656 else
657 {
658 // Not using giant short cut. Do the search
659 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
660 #ifdef _LIBCXX_DYNAMIC_FALLBACK
661 // The following if should always be false because we should definitely
662 // find (static_ptr, static_type), either on a public or private path
663 if (info.path_dst_ptr_to_static_ptr == unknown &&
664 info.path_dynamic_ptr_to_static_ptr == unknown)
665 {
666 syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
667 "has hidden visibility or is defined in more than one translation "
668 "unit. They should all have public visibility. "
669 "%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
670 dst_type->name());
671 // Redo the search comparing type_info's using strcmp
672 info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
673 dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
674 }
675#endif // _LIBCXX_DYNAMIC_FALLBACK
676 // Query the search.
677 switch (info.number_to_static_ptr)
678 {
679 case 0:
680 if (info.number_to_dst_ptr == 1 &&
681 info.path_dynamic_ptr_to_static_ptr == public_path &&
682 info.path_dynamic_ptr_to_dst_ptr == public_path)
683 dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
684 break;
685 case 1:
686 if (info.path_dst_ptr_to_static_ptr == public_path ||
687 (
688 info.number_to_dst_ptr == 0 &&
689 info.path_dynamic_ptr_to_static_ptr == public_path &&
690 info.path_dynamic_ptr_to_dst_ptr == public_path
691 )
692 )
693 dst_ptr = info.dst_ptr_leading_to_static_ptr;
694 break;
695 }
696 }
697 return const_cast<void*>(dst_ptr);
698}
699
700#ifdef __clang__
701#pragma clang diagnostic pop
702#endif
703
704// Call this function when you hit a static_type which is a base (above) a dst_type.
705// Let caller know you hit a static_type. But only start recording details if
706// this is (static_ptr, static_type) -- the node we are casting from.
707// If this is (static_ptr, static_type)
708// Record the path (public or not) from the dst_type to here. There may be
709// multiple paths from the same dst_type to here, record the "most public" one.
710// Record the dst_ptr as pointing to (static_ptr, static_type).
711// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
712// then mark this dyanmic_cast as ambiguous and stop the search.
713void
714__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,
715 const void* dst_ptr,
716 const void* current_ptr,
717 int path_below) const
718{
719 // Record that we found a static_type
720 info->found_any_static_type = true;
721 if (current_ptr == info->static_ptr)
722 {
723 // Record that we found (static_ptr, static_type)
724 info->found_our_static_ptr = true;
725 if (info->dst_ptr_leading_to_static_ptr == 0)
726 {
727 // First time here
728 info->dst_ptr_leading_to_static_ptr = dst_ptr;
729 info->path_dst_ptr_to_static_ptr = path_below;
730 info->number_to_static_ptr = 1;
731 // If there is only one dst_type in the entire tree and the path from
732 // there to here is public then we are done!
733 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
734 info->search_done = true;
735 }
736 else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)
737 {
738 // We've been here before. Update path to "most public"
739 if (info->path_dst_ptr_to_static_ptr == not_public_path)
740 info->path_dst_ptr_to_static_ptr = path_below;
741 // If there is only one dst_type in the entire tree and the path from
742 // there to here is public then we are done!
743 if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
744 info->search_done = true;
745 }
746 else
747 {
748 // We've detected an ambiguous cast from (static_ptr, static_type)
749 // to a dst_type
750 info->number_to_static_ptr += 1;
751 info->search_done = true;
752 }
753 }
754}
755
756// Call this function when you hit a static_type which is not a base (above) a dst_type.
757// If this is (static_ptr, static_type)
758// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be
759// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.
760void
761__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
762 const void* current_ptr,
763 int path_below) const
764{
765 if (current_ptr == info->static_ptr)
766 {
767 // Record the most public path from (dynamic_ptr, dynamic_type) to
768 // (static_ptr, static_type)
769 if (info->path_dynamic_ptr_to_static_ptr != public_path)
770 info->path_dynamic_ptr_to_static_ptr = path_below;
771 }
772}
773
774// Call this function when searching below a dst_type node. This function searches
775// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.
776// If it finds a static_type node, there is no need to further search base classes
777// above.
778// If it finds a dst_type node it should search base classes using search_above_dst
779// to find out if this dst_type points to (static_ptr, static_type) or not.
780// Either way, the dst_type is recorded as one of two "flavors": one that does
781// or does not point to (static_ptr, static_type).
782// If this is neither a static_type nor a dst_type node, continue searching
783// base classes above.
784// All the hoopla surrounding the search code is doing nothing but looking for
785// excuses to stop the search prematurely (break out of the for-loop). That is,
786// the algorithm below is simply an optimization of this:
787// void
788// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
789// const void* current_ptr,
790// int path_below) const
791// {
792// typedef const __base_class_type_info* Iter;
793// if (this == info->static_type)
794// process_static_type_below_dst(info, current_ptr, path_below);
795// else if (this == info->dst_type)
796// {
797// // Record the most public access path that got us here
798// if (info->path_dynamic_ptr_to_dst_ptr != public_path)
799// info->path_dynamic_ptr_to_dst_ptr = path_below;
800// bool does_dst_type_point_to_our_static_type = false;
801// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)
802// {
803// p->search_above_dst(info, current_ptr, current_ptr, public_path);
804// if (info->found_our_static_ptr)
805// does_dst_type_point_to_our_static_type = true;
806// // break out early here if you can detect it doesn't matter if you do
807// }
808// if (!does_dst_type_point_to_our_static_type)
809// {
810// // We found a dst_type that doesn't point to (static_ptr, static_type)
811// // So record the address of this dst_ptr and increment the
812// // count of the number of such dst_types found in the tree.
813// info->dst_ptr_not_leading_to_static_ptr = current_ptr;
814// info->number_to_dst_ptr += 1;
815// }
816// }
817// else
818// {
819// // This is not a static_type and not a dst_type.
820// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
821// {
822// p->search_below_dst(info, current_ptr, public_path);
823// // break out early here if you can detect it doesn't matter if you do
824// }
825// }
826// }
827void
828__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
829 const void* current_ptr,
830 int path_below,
831 bool use_strcmp) const
832{
833 typedef const __base_class_type_info* Iter;
834 if (is_equal(this, info->static_type, use_strcmp))
835 process_static_type_below_dst(info, current_ptr, path_below);
836 else if (is_equal(this, info->dst_type, use_strcmp))
837 {
838 // We've been here before if we've recorded current_ptr in one of these
839 // two places:
840 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
841 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
842 {
843 // We've seen this node before, and therefore have already searched
844 // its base classes above.
845 // Update path to here that is "most public".
846 if (path_below == public_path)
847 info->path_dynamic_ptr_to_dst_ptr = public_path;
848 }
849 else // We have haven't been here before
850 {
851 // Record the access path that got us here
852 // If there is more than one dst_type this path doesn't matter.
853 info->path_dynamic_ptr_to_dst_ptr = path_below;
854 bool does_dst_type_point_to_our_static_type = false;
855 // Only search above here if dst_type derives from static_type, or
856 // if it is unknown if dst_type derives from static_type.
857 if (info->is_dst_type_derived_from_static_type != no)
858 {
859 // Set up flags to record results from all base classes
860 bool is_dst_type_derived_from_static_type = false;
861
862 // We've found a dst_type with a potentially public path to here.
863 // We have to assume the path is public because it may become
864 // public later (if we get back to here with a public path).
865 // We can stop looking above if:
866 // 1. We've found a public path to (static_ptr, static_type).
867 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
868 // This is detected at the (static_ptr, static_type).
869 // 3. We can prove that there is no public path to (static_ptr, static_type)
870 // above here.
871 const Iter e = __base_info + __base_count;
872 for (Iter p = __base_info; p < e; ++p)
873 {
874 // Zero out found flags
875 info->found_our_static_ptr = false;
876 info->found_any_static_type = false;
877 p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
878 if (info->search_done)
879 break;
880 if (info->found_any_static_type)
881 {
882 is_dst_type_derived_from_static_type = true;
883 if (info->found_our_static_ptr)
884 {
885 does_dst_type_point_to_our_static_type = true;
886 // If we found what we're looking for, stop looking above.
887 if (info->path_dst_ptr_to_static_ptr == public_path)
888 break;
889 // We found a private path to (static_ptr, static_type)
890 // If there is no diamond then there is only one path
891 // to (static_ptr, static_type) and we just found it.
892 if (!(__flags & __diamond_shaped_mask))
893 break;
894 }
895 else
896 {
897 // If we found a static_type that isn't the one we're looking
898 // for, and if there are no repeated types above here,
899 // then stop looking.
900 if (!(__flags & __non_diamond_repeat_mask))
901 break;
902 }
903 }
904 }
905 // If we found no static_type,s then dst_type doesn't derive
906 // from static_type, else it does. Record this result so that
907 // next time we hit a dst_type we will know not to search above
908 // it if it doesn't derive from static_type.
909 if (is_dst_type_derived_from_static_type)
910 info->is_dst_type_derived_from_static_type = yes;
911 else
912 info->is_dst_type_derived_from_static_type = no;
913 }
914 if (!does_dst_type_point_to_our_static_type)
915 {
916 // We found a dst_type that doesn't point to (static_ptr, static_type)
917 // So record the address of this dst_ptr and increment the
918 // count of the number of such dst_types found in the tree.
919 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
920 info->number_to_dst_ptr += 1;
921 // If there exists another dst with a private path to
922 // (static_ptr, static_type), then the cast from
923 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
924 // so stop search.
925 if (info->number_to_static_ptr == 1 &&
926 info->path_dst_ptr_to_static_ptr == not_public_path)
927 info->search_done = true;
928 }
929 }
930 }
931 else
932 {
933 // This is not a static_type and not a dst_type.
934 const Iter e = __base_info + __base_count;
935 Iter p = __base_info;
936 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
937 if (++p < e)
938 {
939 if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
940 {
941 // If there are multiple paths to a base above from here, or if
942 // a dst_type pointing to (static_ptr, static_type) has been found,
943 // then there is no way to break out of this loop early unless
944 // something below detects the search is done.
945 do
946 {
947 if (info->search_done)
948 break;
949 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
950 } while (++p < e);
951 }
952 else if (__flags & __non_diamond_repeat_mask)
953 {
954 // There are not multiple paths to any base class from here and a
955 // dst_type pointing to (static_ptr, static_type) has not yet been
956 // found.
957 do
958 {
959 if (info->search_done)
960 break;
961 // If we just found a dst_type with a public path to (static_ptr, static_type),
962 // then the only reason to continue the search is to make sure
963 // no other dst_type points to (static_ptr, static_type).
964 // If !diamond, then we don't need to search here.
965 if (info->number_to_static_ptr == 1 &&
966 info->path_dst_ptr_to_static_ptr == public_path)
967 break;
968 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
969 } while (++p < e);
970 }
971 else
972 {
973 // There are no repeated types above this node.
974 // There are no nodes with multiple parents above this node.
975 // no dst_type has been found to (static_ptr, static_type)
976 do
977 {
978 if (info->search_done)
979 break;
980 // If we just found a dst_type with a public path to (static_ptr, static_type),
981 // then the only reason to continue the search is to make sure sure
982 // no other dst_type points to (static_ptr, static_type).
983 // If !diamond, then we don't need to search here.
984 // if we just found a dst_type with a private path to (static_ptr, static_type),
985 // then we're only looking for a public path to (static_ptr, static_type)
986 // and to check for other dst_types.
987 // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
988 // and not a dst_type under here.
989 if (info->number_to_static_ptr == 1)
990 break;
991 p->search_below_dst(info, current_ptr, path_below, use_strcmp);
992 } while (++p < e);
993 }
994 }
995 }
996}
997
998// This is the same algorithm as __vmi_class_type_info::search_below_dst but
999// simplified to the case that there is only a single base class.
1000void
1001__si_class_type_info::search_below_dst(__dynamic_cast_info* info,
1002 const void* current_ptr,
1003 int path_below,
1004 bool use_strcmp) const
1005{
1006 if (is_equal(this, info->static_type, use_strcmp))
1007 process_static_type_below_dst(info, current_ptr, path_below);
1008 else if (is_equal(this, info->dst_type, use_strcmp))
1009 {
1010 // We've been here before if we've recorded current_ptr in one of these
1011 // two places:
1012 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
1013 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
1014 {
1015 // We've seen this node before, and therefore have already searched
1016 // its base classes above.
1017 // Update path to here that is "most public".
1018 if (path_below == public_path)
1019 info->path_dynamic_ptr_to_dst_ptr = public_path;
1020 }
1021 else // We have haven't been here before
1022 {
1023 // Record the access path that got us here
1024 // If there is more than one dst_type this path doesn't matter.
1025 info->path_dynamic_ptr_to_dst_ptr = path_below;
1026 bool does_dst_type_point_to_our_static_type = false;
1027 // Only search above here if dst_type derives from static_type, or
1028 // if it is unknown if dst_type derives from static_type.
1029 if (info->is_dst_type_derived_from_static_type != no)
1030 {
1031 // Set up flags to record results from all base classes
1032 bool is_dst_type_derived_from_static_type = false;
1033 // Zero out found flags
1034 info->found_our_static_ptr = false;
1035 info->found_any_static_type = false;
1036 __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp);
1037 if (info->found_any_static_type)
1038 {
1039 is_dst_type_derived_from_static_type = true;
1040 if (info->found_our_static_ptr)
1041 does_dst_type_point_to_our_static_type = true;
1042 }
1043 // If we found no static_type,s then dst_type doesn't derive
1044 // from static_type, else it does. Record this result so that
1045 // next time we hit a dst_type we will know not to search above
1046 // it if it doesn't derive from static_type.
1047 if (is_dst_type_derived_from_static_type)
1048 info->is_dst_type_derived_from_static_type = yes;
1049 else
1050 info->is_dst_type_derived_from_static_type = no;
1051 }
1052 if (!does_dst_type_point_to_our_static_type)
1053 {
1054 // We found a dst_type that doesn't point to (static_ptr, static_type)
1055 // So record the address of this dst_ptr and increment the
1056 // count of the number of such dst_types found in the tree.
1057 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
1058 info->number_to_dst_ptr += 1;
1059 // If there exists another dst with a private path to
1060 // (static_ptr, static_type), then the cast from
1061 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
1062 if (info->number_to_static_ptr == 1 &&
1063 info->path_dst_ptr_to_static_ptr == not_public_path)
1064 info->search_done = true;
1065 }
1066 }
1067 }
1068 else
1069 {
1070 // This is not a static_type and not a dst_type
1071 __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp);
1072 }
1073}
1074
1075// This is the same algorithm as __vmi_class_type_info::search_below_dst but
1076// simplified to the case that there is no base class.
1077void
1078__class_type_info::search_below_dst(__dynamic_cast_info* info,
1079 const void* current_ptr,
1080 int path_below,
1081 bool use_strcmp) const
1082{
1083 if (is_equal(this, info->static_type, use_strcmp))
1084 process_static_type_below_dst(info, current_ptr, path_below);
1085 else if (is_equal(this, info->dst_type, use_strcmp))
1086 {
1087 // We've been here before if we've recorded current_ptr in one of these
1088 // two places:
1089 if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
1090 current_ptr == info->dst_ptr_not_leading_to_static_ptr)
1091 {
1092 // We've seen this node before, and therefore have already searched
1093 // its base classes above.
1094 // Update path to here that is "most public".
1095 if (path_below == public_path)
1096 info->path_dynamic_ptr_to_dst_ptr = public_path;
1097 }
1098 else // We have haven't been here before
1099 {
1100 // Record the access path that got us here
1101 // If there is more than one dst_type this path doesn't matter.
1102 info->path_dynamic_ptr_to_dst_ptr = path_below;
1103 // We found a dst_type that doesn't point to (static_ptr, static_type)
1104 // So record the address of this dst_ptr and increment the
1105 // count of the number of such dst_types found in the tree.
1106 info->dst_ptr_not_leading_to_static_ptr = current_ptr;
1107 info->number_to_dst_ptr += 1;
1108 // If there exists another dst with a private path to
1109 // (static_ptr, static_type), then the cast from
1110 // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
1111 if (info->number_to_static_ptr == 1 &&
1112 info->path_dst_ptr_to_static_ptr == not_public_path)
1113 info->search_done = true;
1114 // We found that dst_type does not derive from static_type
1115 info->is_dst_type_derived_from_static_type = no;
1116 }
1117 }
1118}
1119
1120// Call this function when searching above a dst_type node. This function searches
1121// for a public path to (static_ptr, static_type).
1122// This function is guaranteed not to find a node of type dst_type.
1123// Theoretically this is a very simple function which just stops if it finds a
1124// static_type node: All the hoopla surrounding the search code is doing
1125// nothing but looking for excuses to stop the search prematurely (break out of
1126// the for-loop). That is, the algorithm below is simply an optimization of this:
1127// void
1128// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
1129// const void* dst_ptr,
1130// const void* current_ptr,
1131// int path_below) const
1132// {
1133// if (this == info->static_type)
1134// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1135// else
1136// {
1137// typedef const __base_class_type_info* Iter;
1138// // This is not a static_type and not a dst_type
1139// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
1140// {
1141// p->search_above_dst(info, dst_ptr, current_ptr, public_path);
1142// // break out early here if you can detect it doesn't matter if you do
1143// }
1144// }
1145// }
1146void
1147__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
1148 const void* dst_ptr,
1149 const void* current_ptr,
1150 int path_below,
1151 bool use_strcmp) const
1152{
1153 if (is_equal(this, info->static_type, use_strcmp))
1154 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1155 else
1156 {
1157 typedef const __base_class_type_info* Iter;
1158 // This is not a static_type and not a dst_type
1159 // Save flags so they can be restored when returning to nodes below.
1160 bool found_our_static_ptr = info->found_our_static_ptr;
1161 bool found_any_static_type = info->found_any_static_type;
1162 // We've found a dst_type below with a path to here. If the path
1163 // to here is not public, there may be another path to here that
1164 // is public. So we have to assume that the path to here is public.
1165 // We can stop looking above if:
1166 // 1. We've found a public path to (static_ptr, static_type).
1167 // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
1168 // This is detected at the (static_ptr, static_type).
1169 // 3. We can prove that there is no public path to (static_ptr, static_type)
1170 // above here.
1171 const Iter e = __base_info + __base_count;
1172 Iter p = __base_info;
1173 // Zero out found flags
1174 info->found_our_static_ptr = false;
1175 info->found_any_static_type = false;
1176 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1177 found_our_static_ptr |= info->found_our_static_ptr;
1178 found_any_static_type |= info->found_any_static_type;
1179 if (++p < e)
1180 {
1181 do
1182 {
1183 if (info->search_done)
1184 break;
1185 if (info->found_our_static_ptr)
1186 {
1187 // If we found what we're looking for, stop looking above.
1188 if (info->path_dst_ptr_to_static_ptr == public_path)
1189 break;
1190 // We found a private path to (static_ptr, static_type)
1191 // If there is no diamond then there is only one path
1192 // to (static_ptr, static_type) from here and we just found it.
1193 if (!(__flags & __diamond_shaped_mask))
1194 break;
1195 }
1196 else if (info->found_any_static_type)
1197 {
1198 // If we found a static_type that isn't the one we're looking
1199 // for, and if there are no repeated types above here,
1200 // then stop looking.
1201 if (!(__flags & __non_diamond_repeat_mask))
1202 break;
1203 }
1204 // Zero out found flags
1205 info->found_our_static_ptr = false;
1206 info->found_any_static_type = false;
1207 p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1208 found_our_static_ptr |= info->found_our_static_ptr;
1209 found_any_static_type |= info->found_any_static_type;
1210 } while (++p < e);
1211 }
1212 // Restore flags
1213 info->found_our_static_ptr = found_our_static_ptr;
1214 info->found_any_static_type = found_any_static_type;
1215 }
1216}
1217
1218// This is the same algorithm as __vmi_class_type_info::search_above_dst but
1219// simplified to the case that there is only a single base class.
1220void
1221__si_class_type_info::search_above_dst(__dynamic_cast_info* info,
1222 const void* dst_ptr,
1223 const void* current_ptr,
1224 int path_below,
1225 bool use_strcmp) const
1226{
1227 if (is_equal(this, info->static_type, use_strcmp))
1228 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1229 else
1230 __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
1231}
1232
1233// This is the same algorithm as __vmi_class_type_info::search_above_dst but
1234// simplified to the case that there is no base class.
1235void
1236__class_type_info::search_above_dst(__dynamic_cast_info* info,
1237 const void* dst_ptr,
1238 const void* current_ptr,
1239 int path_below,
1240 bool use_strcmp) const
1241{
1242 if (is_equal(this, info->static_type, use_strcmp))
1243 process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
1244}
1245
1246// The search functions for __base_class_type_info are simply convenience
1247// functions for adjusting the current_ptr and path_below as the search is
1248// passed up to the base class node.
1249
1250void
1251__base_class_type_info::search_above_dst(__dynamic_cast_info* info,
1252 const void* dst_ptr,
1253 const void* current_ptr,
1254 int path_below,
1255 bool use_strcmp) const
1256{
1257 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
1258 if (__offset_flags & __virtual_mask)
1259 {
1260 const char* vtable = *static_cast<const char*const*>(current_ptr);
1261 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
1262 }
1263 __base_type->search_above_dst(info, dst_ptr,
1264 static_cast<const char*>(current_ptr) + offset_to_base,
1265 (__offset_flags & __public_mask) ?
1266 path_below :
1267 not_public_path,
1268 use_strcmp);
1269}
1270
1271void
1272__base_class_type_info::search_below_dst(__dynamic_cast_info* info,
1273 const void* current_ptr,
1274 int path_below,
1275 bool use_strcmp) const
1276{
1277 ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
1278 if (__offset_flags & __virtual_mask)
1279 {
1280 const char* vtable = *static_cast<const char*const*>(current_ptr);
1281 offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
1282 }
1283 __base_type->search_below_dst(info,
1284 static_cast<const char*>(current_ptr) + offset_to_base,
1285 (__offset_flags & __public_mask) ?
1286 path_below :
1287 not_public_path,
1288 use_strcmp);
1289}
1290
1291} // __cxxabiv1
lib/libcxxabi/src/private_typeinfo.h created+251
...@@ -0,0 +1,251 @@
1//===------------------------ private_typeinfo.h --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef __PRIVATE_TYPEINFO_H_
10#define __PRIVATE_TYPEINFO_H_
11
12#include "__cxxabi_config.h"
13
14#include <typeinfo>
15#include <stddef.h>
16
17namespace __cxxabiv1 {
18
19class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info {
20public:
21 _LIBCXXABI_HIDDEN virtual ~__shim_type_info();
22
23 _LIBCXXABI_HIDDEN virtual void noop1() const;
24 _LIBCXXABI_HIDDEN virtual void noop2() const;
25 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type,
26 void *&adjustedPtr) const = 0;
27};
28
29class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info {
30public:
31 _LIBCXXABI_HIDDEN virtual ~__fundamental_type_info();
32 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
33 void *&) const;
34};
35
36class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info {
37public:
38 _LIBCXXABI_HIDDEN virtual ~__array_type_info();
39 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
40 void *&) const;
41};
42
43class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info {
44public:
45 _LIBCXXABI_HIDDEN virtual ~__function_type_info();
46 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
47 void *&) const;
48};
49
50class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
51public:
52 _LIBCXXABI_HIDDEN virtual ~__enum_type_info();
53 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
54 void *&) const;
55};
56
57enum
58{
59 unknown = 0,
60 public_path,
61 not_public_path,
62 yes,
63 no
64};
65
66class _LIBCXXABI_TYPE_VIS __class_type_info;
67
68struct _LIBCXXABI_HIDDEN __dynamic_cast_info
69{
70// const data supplied to the search:
71
72 const __class_type_info* dst_type;
73 const void* static_ptr;
74 const __class_type_info* static_type;
75 ptrdiff_t src2dst_offset;
76
77// Data that represents the answer:
78
79 // pointer to a dst_type which has (static_ptr, static_type) above it
80 const void* dst_ptr_leading_to_static_ptr;
81 // pointer to a dst_type which does not have (static_ptr, static_type) above it
82 const void* dst_ptr_not_leading_to_static_ptr;
83
84 // The following three paths are either unknown, public_path or not_public_path.
85 // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
86 int path_dst_ptr_to_static_ptr;
87 // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
88 // when there is no dst_type along the path
89 int path_dynamic_ptr_to_static_ptr;
90 // access of path from (dynamic_ptr, dynamic_type) to dst_type
91 // (not used if there is a (static_ptr, static_type) above a dst_type).
92 int path_dynamic_ptr_to_dst_ptr;
93
94 // Number of dst_types below (static_ptr, static_type)
95 int number_to_static_ptr;
96 // Number of dst_types not below (static_ptr, static_type)
97 int number_to_dst_ptr;
98
99// Data that helps stop the search before the entire tree is searched:
100
101 // is_dst_type_derived_from_static_type is either unknown, yes or no.
102 int is_dst_type_derived_from_static_type;
103 // Number of dst_type in tree. If 0, then that means unknown.
104 int number_of_dst_type;
105 // communicates to a dst_type node that (static_ptr, static_type) was found
106 // above it.
107 bool found_our_static_ptr;
108 // communicates to a dst_type node that a static_type was found
109 // above it, but it wasn't (static_ptr, static_type)
110 bool found_any_static_type;
111 // Set whenever a search can be stopped
112 bool search_done;
113};
114
115// Has no base class
116class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info {
117public:
118 _LIBCXXABI_HIDDEN virtual ~__class_type_info();
119
120 _LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *,
121 const void *,
122 const void *, int) const;
123 _LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *,
124 const void *, int) const;
125 _LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *,
126 int) const;
127 _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
128 const void *, const void *,
129 int, bool) const;
130 _LIBCXXABI_HIDDEN virtual void
131 search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
132 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
133 void *&) const;
134 _LIBCXXABI_HIDDEN virtual void
135 has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
136};
137
138// Has one non-virtual public base class at offset zero
139class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info {
140public:
141 const __class_type_info *__base_type;
142
143 _LIBCXXABI_HIDDEN virtual ~__si_class_type_info();
144
145 _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
146 const void *, const void *,
147 int, bool) const;
148 _LIBCXXABI_HIDDEN virtual void
149 search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
150 _LIBCXXABI_HIDDEN virtual void
151 has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
152};
153
154struct _LIBCXXABI_HIDDEN __base_class_type_info
155{
156public:
157 const __class_type_info* __base_type;
158 long __offset_flags;
159
160 enum __offset_flags_masks
161 {
162 __virtual_mask = 0x1,
163 __public_mask = 0x2, // base is public
164 __offset_shift = 8
165 };
166
167 void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const;
168 void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const;
169 void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
170};
171
172// Has one or more base classes
173class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info {
174public:
175 unsigned int __flags;
176 unsigned int __base_count;
177 __base_class_type_info __base_info[1];
178
179 enum __flags_masks {
180 __non_diamond_repeat_mask = 0x1, // has two or more distinct base class
181 // objects of the same type
182 __diamond_shaped_mask = 0x2 // has base class object with two or
183 // more derived objects
184 };
185
186 _LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info();
187
188 _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *,
189 const void *, const void *,
190 int, bool) const;
191 _LIBCXXABI_HIDDEN virtual void
192 search_below_dst(__dynamic_cast_info *, const void *, int, bool) const;
193 _LIBCXXABI_HIDDEN virtual void
194 has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const;
195};
196
197class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info {
198public:
199 unsigned int __flags;
200 const __shim_type_info *__pointee;
201
202 enum __masks {
203 __const_mask = 0x1,
204 __volatile_mask = 0x2,
205 __restrict_mask = 0x4,
206 __incomplete_mask = 0x8,
207 __incomplete_class_mask = 0x10,
208 __transaction_safe_mask = 0x20,
209 // This implements the following proposal from cxx-abi-dev (not yet part of
210 // the ABI document):
211 //
212 // http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html
213 //
214 // This is necessary for support of http://wg21.link/p0012, which permits
215 // throwing noexcept function and member function pointers and catching
216 // them as non-noexcept pointers.
217 __noexcept_mask = 0x40,
218
219 // Flags that cannot be removed by a standard conversion.
220 __no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask,
221 // Flags that cannot be added by a standard conversion.
222 __no_add_flags_mask = __transaction_safe_mask | __noexcept_mask
223 };
224
225 _LIBCXXABI_HIDDEN virtual ~__pbase_type_info();
226 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
227 void *&) const;
228};
229
230class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info {
231public:
232 _LIBCXXABI_HIDDEN virtual ~__pointer_type_info();
233 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
234 void *&) const;
235 _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
236};
237
238class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info
239 : public __pbase_type_info {
240public:
241 const __class_type_info *__context;
242
243 _LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info();
244 _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *,
245 void *&) const;
246 _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const;
247};
248
249} // __cxxabiv1
250
251#endif // __PRIVATE_TYPEINFO_H_
lib/libcxxabi/src/stdlib_exception.cpp created+71
...@@ -0,0 +1,71 @@
1//===---------------------------- exception.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#define _LIBCPP_BUILDING_LIBRARY
10#include <new>
11#include <exception>
12
13namespace std
14{
15
16// exception
17
18exception::~exception() _NOEXCEPT
19{
20}
21
22const char* exception::what() const _NOEXCEPT
23{
24 return "std::exception";
25}
26
27// bad_exception
28
29bad_exception::~bad_exception() _NOEXCEPT
30{
31}
32
33const char* bad_exception::what() const _NOEXCEPT
34{
35 return "std::bad_exception";
36}
37
38
39// bad_alloc
40
41bad_alloc::bad_alloc() _NOEXCEPT
42{
43}
44
45bad_alloc::~bad_alloc() _NOEXCEPT
46{
47}
48
49const char*
50bad_alloc::what() const _NOEXCEPT
51{
52 return "std::bad_alloc";
53}
54
55// bad_array_new_length
56
57bad_array_new_length::bad_array_new_length() _NOEXCEPT
58{
59}
60
61bad_array_new_length::~bad_array_new_length() _NOEXCEPT
62{
63}
64
65const char*
66bad_array_new_length::what() const _NOEXCEPT
67{
68 return "bad_array_new_length";
69}
70
71} // std
lib/libcxxabi/src/stdlib_stdexcept.cpp created+47
...@@ -0,0 +1,47 @@
1//===------------------------ stdexcept.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "include/refstring.h"
10#include "stdexcept"
11#include "new"
12#include <cstdlib>
13#include <cstring>
14#include <cstdint>
15#include <cstddef>
16
17static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
18
19namespace std // purposefully not using versioning namespace
20{
21
22logic_error::~logic_error() _NOEXCEPT {}
23
24const char*
25logic_error::what() const _NOEXCEPT
26{
27 return __imp_.c_str();
28}
29
30runtime_error::~runtime_error() _NOEXCEPT {}
31
32const char*
33runtime_error::what() const _NOEXCEPT
34{
35 return __imp_.c_str();
36}
37
38domain_error::~domain_error() _NOEXCEPT {}
39invalid_argument::~invalid_argument() _NOEXCEPT {}
40length_error::~length_error() _NOEXCEPT {}
41out_of_range::~out_of_range() _NOEXCEPT {}
42
43range_error::~range_error() _NOEXCEPT {}
44overflow_error::~overflow_error() _NOEXCEPT {}
45underflow_error::~underflow_error() _NOEXCEPT {}
46
47} // std
lib/libcxxabi/src/stdlib_typeinfo.cpp created+52
...@@ -0,0 +1,52 @@
1//===----------------------------- typeinfo.cpp ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <typeinfo>
10
11namespace std
12{
13
14// type_info
15
16type_info::~type_info()
17{
18}
19
20// bad_cast
21
22bad_cast::bad_cast() _NOEXCEPT
23{
24}
25
26bad_cast::~bad_cast() _NOEXCEPT
27{
28}
29
30const char*
31bad_cast::what() const _NOEXCEPT
32{
33 return "std::bad_cast";
34}
35
36// bad_typeid
37
38bad_typeid::bad_typeid() _NOEXCEPT
39{
40}
41
42bad_typeid::~bad_typeid() _NOEXCEPT
43{
44}
45
46const char*
47bad_typeid::what() const _NOEXCEPT
48{
49 return "std::bad_typeid";
50}
51
52} // std
lib/std/io/serialization.zig+1-1
...@@ -209,7 +209,7 @@ pub fn deserializer(...@@ -209,7 +209,7 @@ pub fn deserializer(
209/// to the serializer struct.209/// to the serializer struct.
210pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime OutStreamType: type) type {210pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime OutStreamType: type) type {
211 return struct {211 return struct {
212 out_stream: if (packing == .Bit) BitOutStream(endian, OutStreamType) else OutStreamType,212 out_stream: if (packing == .Bit) io.BitOutStream(endian, OutStreamType) else OutStreamType,
213213
214 const Self = @This();214 const Self = @This();
215 pub const Error = OutStreamType.Error;215 pub const Error = OutStreamType.Error;
lib/std/os/linux/tls.zig+135-117
...@@ -1,8 +1,9 @@...@@ -1,8 +1,9 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;
2const os = std.os;3const os = std.os;
3const mem = std.mem;4const mem = std.mem;
4const elf = std.elf;5const elf = std.elf;
5const builtin = @import("builtin");6const math = std.math;
6const assert = std.debug.assert;7const assert = std.debug.assert;
78
8// This file implements the two TLS variants [1] used by ELF-based systems.9// This file implements the two TLS variants [1] used by ELF-based systems.
...@@ -57,28 +58,16 @@ const tls_tcb_size = switch (builtin.arch) {...@@ -57,28 +58,16 @@ const tls_tcb_size = switch (builtin.arch) {
57 // ARM EABI mandates enough space for two pointers: the first one points to58 // ARM EABI mandates enough space for two pointers: the first one points to
58 // the DTV while the second one is unspecified but reserved59 // the DTV while the second one is unspecified but reserved
59 .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),60 .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
61 // One pointer-sized word that points either to the DTV or the TCB itself
60 else => @sizeOf(usize),62 else => @sizeOf(usize),
61};63};
6264
63// Controls if the TCB should be aligned according to the TLS segment p_align
64const tls_tcb_align_size = switch (builtin.arch) {
65 .arm, .armeb, .aarch64, .aarch64_be => true,
66 else => false,
67};
68
69// Controls if the TP points to the end of the TCB instead of its beginning65// Controls if the TP points to the end of the TCB instead of its beginning
70const tls_tp_points_past_tcb = switch (builtin.arch) {66const tls_tp_points_past_tcb = switch (builtin.arch) {
71 .riscv32, .riscv64, .mipsel, .powerpc64, .powerpc64le => true,67 .riscv32, .riscv64, .mipsel, .powerpc64, .powerpc64le => true,
72 else => false,68 else => false,
73};69};
7470
75// Check if the architecture-specific parameters look correct
76comptime {
77 if (tls_tcb_align_size and tls_variant != TLSVariant.VariantI) {
78 @compileError("tls_tcb_align_size is only meaningful for variant I TLS");
79 }
80}
81
82// Some architectures add some offset to the tp and dtv addresses in order to71// Some architectures add some offset to the tp and dtv addresses in order to
83// make the generated code more efficient72// make the generated code more efficient
8473
...@@ -94,32 +83,36 @@ const tls_dtv_offset = switch (builtin.arch) {...@@ -94,32 +83,36 @@ const tls_dtv_offset = switch (builtin.arch) {
94};83};
9584
96// Per-thread storage for Zig's use85// Per-thread storage for Zig's use
97const CustomData = packed struct {};86const CustomData = struct {
87 dummy: usize,
88};
9889
99// Dynamic Thread Vector90// Dynamic Thread Vector
100const DTV = packed struct {91const DTV = extern struct {
101 entries: usize,92 entries: usize,
102 tls_block: [1]usize,93 tls_block: [1][*]u8,
103};94};
10495
105// Holds all the information about the process TLS image96// Holds all the information about the process TLS image
106const TLSImage = struct {97const TLSImage = struct {
107 data_src: []u8,98 init_data: []const u8,
108 alloc_size: usize,99 alloc_size: usize,
100 alloc_align: usize,
109 tcb_offset: usize,101 tcb_offset: usize,
110 dtv_offset: usize,102 dtv_offset: usize,
111 data_offset: usize,103 data_offset: usize,
104 data_size: usize,
112 // Only used on the i386 architecture105 // Only used on the i386 architecture
113 gdt_entry_number: usize,106 gdt_entry_number: usize,
114};107};
115108
116pub var tls_image: ?TLSImage = null;109pub var tls_image: TLSImage = undefined;
117110
118pub fn setThreadPointer(addr: usize) void {111pub fn setThreadPointer(addr: usize) void {
119 switch (builtin.arch) {112 switch (builtin.arch) {
120 .i386 => {113 .i386 => {
121 var user_desc = std.os.linux.user_desc{114 var user_desc = std.os.linux.user_desc{
122 .entry_number = tls_image.?.gdt_entry_number,115 .entry_number = tls_image.gdt_entry_number,
123 .base_addr = addr,116 .base_addr = addr,
124 .limit = 0xfffff,117 .limit = 0xfffff,
125 .seg_32bit = 1,118 .seg_32bit = 1,
...@@ -134,7 +127,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -134,7 +127,7 @@ pub fn setThreadPointer(addr: usize) void {
134127
135 const gdt_entry_number = user_desc.entry_number;128 const gdt_entry_number = user_desc.entry_number;
136 // We have to keep track of our slot as it's also needed for clone()129 // We have to keep track of our slot as it's also needed for clone()
137 tls_image.?.gdt_entry_number = gdt_entry_number;130 tls_image.gdt_entry_number = gdt_entry_number;
138 // Update the %gs selector131 // Update the %gs selector
139 asm volatile ("movl %[gs_val], %%gs"132 asm volatile ("movl %[gs_val], %%gs"
140 :133 :
...@@ -171,7 +164,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -171,7 +164,7 @@ pub fn setThreadPointer(addr: usize) void {
171 }164 }
172}165}
173166
174pub fn initTLS() ?*elf.Phdr {167fn initTLS() void {
175 var tls_phdr: ?*elf.Phdr = null;168 var tls_phdr: ?*elf.Phdr = null;
176 var img_base: usize = 0;169 var img_base: usize = 0;
177170
...@@ -195,124 +188,149 @@ pub fn initTLS() ?*elf.Phdr {...@@ -195,124 +188,149 @@ pub fn initTLS() ?*elf.Phdr {
195 // Sanity check188 // Sanity check
196 assert(at_phent == @sizeOf(elf.Phdr));189 assert(at_phent == @sizeOf(elf.Phdr));
197190
198 // Search the TLS section191 // Find the TLS section
199 const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum];192 const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum];
200193
201 var gnu_stack: ?*elf.Phdr = null;
202
203 for (phdrs) |*phdr| {194 for (phdrs) |*phdr| {
204 switch (phdr.p_type) {195 switch (phdr.p_type) {
205 elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr,196 elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr,
206 elf.PT_TLS => tls_phdr = phdr,197 elf.PT_TLS => tls_phdr = phdr,
207 elf.PT_GNU_STACK => gnu_stack = phdr,198 else => {},
208 else => continue,
209 }199 }
210 }200 }
211201
212 if (tls_phdr) |phdr| {202 // If the cpu is ARM-based, check if it supports the TLS register
213 // If the cpu is arm-based, check if it supports the TLS register203 if (comptime builtin.arch.isARM() and at_hwcap & std.os.linux.HWCAP_TLS == 0) {
214 if (builtin.arch == .arm and at_hwcap & std.os.linux.HWCAP_TLS == 0) {204 // If the CPU does not support TLS via a coprocessor register,
215 // If the CPU does not support TLS via a coprocessor register,205 // a kernel helper function can be used instead on certain linux kernels.
216 // a kernel helper function can be used instead on certain linux kernels.206 // See linux/arch/arm/include/asm/tls.h and musl/src/thread/arm/__set_thread_area.c.
217 // See linux/arch/arm/include/asm/tls.h and musl/src/thread/arm/__set_thread_area.c.207 @panic("TODO: Implement ARM fallback TLS functionality");
218 @panic("TODO: Implement ARM fallback TLS functionality");208 }
219 }
220209
221 // Offsets into the allocated TLS area210 var tls_align_factor: usize = undefined;
222 var tcb_offset: usize = undefined;211 var tls_data: []const u8 = undefined;
223 var dtv_offset: usize = undefined;212 var tls_data_alloc_size: usize = undefined;
224 var data_offset: usize = undefined;213 if (tls_phdr) |phdr| {
225 var thread_data_offset: usize = undefined;214 // The effective size in memory is represented by p_memsz, the length of
226 // Compute the total size of the ABI-specific data plus our own control215 // the data stored in the PT_TLS segment is p_filesz and may be less
227 // structures216 // than the former
228 const alloc_size = switch (tls_variant) {217 tls_align_factor = phdr.p_align;
229 .VariantI => blk: {218 tls_data = @intToPtr([*]u8, img_base + phdr.p_vaddr)[0..phdr.p_filesz];
230 var l: usize = 0;219 tls_data_alloc_size = phdr.p_memsz;
231 dtv_offset = l;220 } else {
232 l += @sizeOf(DTV);221 tls_align_factor = @alignOf(*usize);
233 thread_data_offset = l;222 tls_data = &[_]u8{};
234 l += @sizeOf(CustomData);223 tls_data_alloc_size = 0;
235 l = mem.alignForward(l, phdr.p_align);
236 tcb_offset = l;
237 if (tls_tcb_align_size) {
238 l += mem.alignForward(tls_tcb_size, phdr.p_align);
239 } else {
240 l += tls_tcb_size;
241 }
242 data_offset = l;
243 l += phdr.p_memsz;
244 break :blk l;
245 },
246 .VariantII => blk: {
247 var l: usize = 0;
248 data_offset = l;
249 l += phdr.p_memsz;
250 l = mem.alignForward(l, phdr.p_align);
251 tcb_offset = l;
252 l += tls_tcb_size;
253 thread_data_offset = l;
254 l += @sizeOf(CustomData);
255 dtv_offset = l;
256 l += @sizeOf(DTV);
257 break :blk l;
258 },
259 };
260
261 tls_image = TLSImage{
262 .data_src = @intToPtr([*]u8, phdr.p_vaddr + img_base)[0..phdr.p_filesz],
263 .alloc_size = alloc_size,
264 .tcb_offset = tcb_offset,
265 .dtv_offset = dtv_offset,
266 .data_offset = data_offset,
267 .gdt_entry_number = @bitCast(usize, @as(isize, -1)),
268 };
269 }224 }
270225
271 return gnu_stack;226 // Offsets into the allocated TLS area
227 var tcb_offset: usize = undefined;
228 var dtv_offset: usize = undefined;
229 var data_offset: usize = undefined;
230 // Compute the total size of the ABI-specific data plus our own control
231 // structures. All the offset calculated here assume a well-aligned base
232 // address.
233 const alloc_size = switch (tls_variant) {
234 .VariantI => blk: {
235 var l: usize = 0;
236 dtv_offset = l;
237 l += @sizeOf(DTV);
238 // Add some padding here so that the thread pointer (tcb_offset) is
239 // aligned to p_align and the CustomData structure can be found by
240 // simply subtracting its @sizeOf from the tp value
241 const delta = (l + @sizeOf(CustomData)) & (tls_align_factor - 1);
242 if (delta > 0)
243 l += tls_align_factor - delta;
244 l += @sizeOf(CustomData);
245 tcb_offset = l;
246 l += mem.alignForward(tls_tcb_size, tls_align_factor);
247 data_offset = l;
248 l += tls_data_alloc_size;
249 break :blk l;
250 },
251 .VariantII => blk: {
252 var l: usize = 0;
253 data_offset = l;
254 l += mem.alignForward(tls_data_alloc_size, tls_align_factor);
255 // The thread pointer is aligned to p_align
256 tcb_offset = l;
257 l += tls_tcb_size;
258 // The CustomData structure is right after the TCB with no padding
259 // in between so it can be easily found
260 l += @sizeOf(CustomData);
261 l = mem.alignForward(l, @alignOf(DTV));
262 dtv_offset = l;
263 l += @sizeOf(DTV);
264 break :blk l;
265 },
266 };
267
268 tls_image = TLSImage{
269 .init_data = tls_data,
270 .alloc_size = alloc_size,
271 .alloc_align = tls_align_factor,
272 .tcb_offset = tcb_offset,
273 .dtv_offset = dtv_offset,
274 .data_offset = data_offset,
275 .data_size = tls_data_alloc_size,
276 .gdt_entry_number = @bitCast(usize, @as(isize, -1)),
277 };
272}278}
273279
274pub fn copyTLS(addr: usize) usize {280inline fn alignPtrCast(comptime T: type, ptr: [*]u8) *T {
275 const tls_img = tls_image.?;281 return @ptrCast(*T, @alignCast(@alignOf(*T), ptr));
282}
276283
277 // Be paranoid, clear the area we're going to use284/// Initializes all the fields of the static TLS area and returns the computed
278 @memset(@intToPtr([*]u8, addr), 0, tls_img.alloc_size);285/// architecture-specific value of the thread-pointer register
286pub fn prepareTLS(area: []u8) usize {
287 // Clear the area we're going to use, just to be safe
288 mem.set(u8, area, 0);
279 // Prepare the DTV289 // Prepare the DTV
280 const dtv = @intToPtr(*DTV, addr + tls_img.dtv_offset);290 const dtv = alignPtrCast(DTV, area.ptr + tls_image.dtv_offset);
281 dtv.entries = 1;291 dtv.entries = 1;
282 dtv.tls_block[0] = addr + tls_img.data_offset + tls_dtv_offset;292 dtv.tls_block[0] = area.ptr + tls_dtv_offset + tls_image.data_offset;
283 // Set-up the TCB293 // Prepare the TCB
284 // Force the alignment to 1 byte as the TCB may start from a non-aligned294 const tcb_ptr = alignPtrCast([*]u8, area.ptr + tls_image.tcb_offset);
285 // address under the variant II model295 tcb_ptr.* = switch (tls_variant) {
286 const tcb_ptr = @intToPtr(*align(1) usize, addr + tls_img.tcb_offset);296 .VariantI => area.ptr + tls_image.dtv_offset,
287 if (tls_variant == TLSVariant.VariantI) {297 .VariantII => area.ptr + tls_image.tcb_offset,
288 tcb_ptr.* = addr + tls_img.dtv_offset;298 };
289 } else {
290 tcb_ptr.* = addr + tls_img.tcb_offset;
291 }
292 // Copy the data299 // Copy the data
293 @memcpy(@intToPtr([*]u8, addr + tls_img.data_offset), tls_img.data_src.ptr, tls_img.data_src.len);300 mem.copy(u8, area[tls_image.data_offset..], tls_image.init_data);
294301
295 // Return the corrected (if needed) value for the tp register302 // Return the corrected (if needed) value for the tp register
296 return addr + tls_tp_offset +303 return @ptrToInt(area.ptr) + tls_tp_offset +
297 if (tls_tp_points_past_tcb) tls_img.data_offset else tls_img.tcb_offset;304 if (tls_tp_points_past_tcb) tls_image.data_offset else tls_image.tcb_offset;
298}305}
299306
300var main_thread_tls_buffer: [256]u8 align(32) = undefined;307var main_thread_tls_buffer: [256]u8 = undefined;
301308
302pub fn allocateTLS(size: usize) usize {309pub fn initStaticTLS() void {
303 // Small TLS allocation, use our local buffer310 initTLS();
304 if (size < main_thread_tls_buffer.len) {311
305 return @ptrToInt(&main_thread_tls_buffer);312 const alloc_tls_area: []u8 = blk: {
306 }313 const full_alloc_size = tls_image.alloc_size + tls_image.alloc_align - 1;
314
315 // Fast path for the common case where the TLS data is really small,
316 // avoid an allocation and use our local buffer
317 if (full_alloc_size < main_thread_tls_buffer.len)
318 break :blk main_thread_tls_buffer[0..];
319
320 break :blk os.mmap(
321 null,
322 full_alloc_size,
323 os.PROT_READ | os.PROT_WRITE,
324 os.MAP_PRIVATE | os.MAP_ANONYMOUS,
325 -1,
326 0,
327 ) catch os.abort();
328 };
307329
308 const slice = os.mmap(330 // Make sure the slice is correctly aligned
309 null,331 const start = @ptrToInt(alloc_tls_area.ptr) & (tls_image.alloc_align - 1);
310 size,332 const tls_area = alloc_tls_area[start .. start + tls_image.alloc_size];
311 os.PROT_READ | os.PROT_WRITE,
312 os.MAP_PRIVATE | os.MAP_ANONYMOUS,
313 -1,
314 0,
315 ) catch @panic("out of memory");
316333
317 return @ptrToInt(slice.ptr);334 const tp_value = prepareTLS(tls_area);
335 setThreadPointer(tp_value);
318}336}
lib/std/special/compiler_rt/floatunditf.zig+5-5
...@@ -2,7 +2,7 @@ const builtin = @import("builtin");...@@ -2,7 +2,7 @@ const builtin = @import("builtin");
2const is_test = builtin.is_test;2const is_test = builtin.is_test;
3const std = @import("std");3const std = @import("std");
44
5pub fn __floatunditf(a: u128) callconv(.C) f128 {5pub fn __floatunditf(a: u64) callconv(.C) f128 {
6 @setRuntimeSafety(is_test);6 @setRuntimeSafety(is_test);
77
8 if (a == 0) {8 if (a == 0) {
...@@ -14,11 +14,11 @@ pub fn __floatunditf(a: u128) callconv(.C) f128 {...@@ -14,11 +14,11 @@ pub fn __floatunditf(a: u128) callconv(.C) f128 {
14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15 const implicit_bit = 1 << mantissa_bits;15 const implicit_bit = 1 << mantissa_bits;
1616
17 const exp = (u128.bit_count - 1) - @clz(u128, a);17 const exp: u128 = (u64.bit_count - 1) - @clz(u64, a);
18 const shift = mantissa_bits - @intCast(u7, exp);18 const shift: u7 = mantissa_bits - @intCast(u7, exp);
1919
20 var result: u128 align(16) = (a << shift) ^ implicit_bit;20 var result: u128 = (@intCast(u128, a) << shift) ^ implicit_bit;
21 result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;21 result += (exp + exponent_bias) << mantissa_bits;
2222
23 return @bitCast(f128, result);23 return @bitCast(f128, result);
24}24}
lib/std/special/compiler_rt/floatunditf_test.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const __floatunditf = @import("floatunditf.zig").__floatunditf;1const __floatunditf = @import("floatunditf.zig").__floatunditf;
22
3fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void {3fn test__floatunditf(a: u64, expected_hi: u64, expected_lo: u64) void {
4 const x = __floatunditf(a);4 const x = __floatunditf(a);
55
6 const x_repr = @bitCast(u128, x);6 const x_repr = @bitCast(u128, x);
lib/std/start.zig+1-7
...@@ -152,13 +152,7 @@ fn posixCallMainAndExit() noreturn {...@@ -152,13 +152,7 @@ fn posixCallMainAndExit() noreturn {
152 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));152 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
153 std.os.linux.elf_aux_maybe = auxv;153 std.os.linux.elf_aux_maybe = auxv;
154 // Initialize the TLS area154 // Initialize the TLS area
155 const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size");155 std.os.linux.tls.initStaticTLS();
156
157 if (std.os.linux.tls.tls_image) |tls_img| {
158 const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size);
159 const tp = std.os.linux.tls.copyTLS(tls_addr);
160 std.os.linux.tls.setThreadPointer(tp);
161 }
162156
163 // TODO This is disabled because what should we do when linking libc and this code157 // TODO This is disabled because what should we do when linking libc and this code
164 // does not execute? And also it's causing a test failure in stack traces in release modes.158 // does not execute? And also it's causing a test failure in stack traces in release modes.
lib/std/thread.zig+16-16
...@@ -286,11 +286,9 @@ pub const Thread = struct {...@@ -286,11 +286,9 @@ pub const Thread = struct {
286 }286 }
287 // Finally, the Thread Local Storage, if any.287 // Finally, the Thread Local Storage, if any.
288 if (!Thread.use_pthreads) {288 if (!Thread.use_pthreads) {
289 if (os.linux.tls.tls_image) |tls_img| {289 l = mem.alignForward(l, os.linux.tls.tls_image.alloc_align);
290 l = mem.alignForward(l, @alignOf(usize));290 tls_start_offset = l;
291 tls_start_offset = l;291 l += os.linux.tls.tls_image.alloc_size;
292 l += tls_img.alloc_size;
293 }
294 }292 }
295 // Round the size to the page size.293 // Round the size to the page size.
296 break :blk mem.alignForward(l, mem.page_size);294 break :blk mem.alignForward(l, mem.page_size);
...@@ -396,18 +394,21 @@ pub const Thread = struct {...@@ -396,18 +394,21 @@ pub const Thread = struct {
396 else => return os.unexpectedErrno(@intCast(usize, err)),394 else => return os.unexpectedErrno(@intCast(usize, err)),
397 }395 }
398 } else if (std.Target.current.os.tag == .linux) {396 } else if (std.Target.current.os.tag == .linux) {
399 var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |397 const flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES |
400 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |398 os.CLONE_SIGHAND | os.CLONE_THREAD | os.CLONE_SYSVSEM |
401 os.CLONE_DETACHED;399 os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
402 var newtls: usize = undefined;400 os.CLONE_DETACHED | os.CLONE_SETTLS;
403 // This structure is only needed when targeting i386401 // This structure is only needed when targeting i386
404 var user_desc: if (std.Target.current.cpu.arch == .i386) os.linux.user_desc else void = undefined;402 var user_desc: if (std.Target.current.cpu.arch == .i386) os.linux.user_desc else void = undefined;
405403
406 if (os.linux.tls.tls_image) |tls_img| {404 const tls_area = mmap_slice[tls_start_offset..];
405 const tp_value = os.linux.tls.prepareTLS(tls_area);
406
407 const newtls = blk: {
407 if (std.Target.current.cpu.arch == .i386) {408 if (std.Target.current.cpu.arch == .i386) {
408 user_desc = os.linux.user_desc{409 user_desc = os.linux.user_desc{
409 .entry_number = tls_img.gdt_entry_number,410 .entry_number = os.linux.tls.tls_image.gdt_entry_number,
410 .base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset),411 .base_addr = tp_value,
411 .limit = 0xfffff,412 .limit = 0xfffff,
412 .seg_32bit = 1,413 .seg_32bit = 1,
413 .contents = 0, // Data414 .contents = 0, // Data
...@@ -416,12 +417,11 @@ pub const Thread = struct {...@@ -416,12 +417,11 @@ pub const Thread = struct {
416 .seg_not_present = 0,417 .seg_not_present = 0,
417 .useable = 1,418 .useable = 1,
418 };419 };
419 newtls = @ptrToInt(&user_desc);420 break :blk @ptrToInt(&user_desc);
420 } else {421 } else {
421 newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset);422 break :blk tp_value;
422 }423 }
423 flags |= os.CLONE_SETTLS;424 };
424 }
425425
426 const rc = os.linux.clone(426 const rc = os.linux.clone(
427 MainFuncs.linuxThreadMain,427 MainFuncs.linuxThreadMain,
src-self-hosted/clang_options_data.zig+58-9
...@@ -80,7 +80,14 @@ sepd1("Xassembler"),...@@ -80,7 +80,14 @@ sepd1("Xassembler"),
80sepd1("Xclang"),80sepd1("Xclang"),
81sepd1("Xcuda-fatbinary"),81sepd1("Xcuda-fatbinary"),
82sepd1("Xcuda-ptxas"),82sepd1("Xcuda-ptxas"),
83sepd1("Xlinker"),83.{
84 .name = "Xlinker",
85 .syntax = .separate,
86 .zig_equivalent = .for_linker,
87 .pd1 = true,
88 .pd2 = false,
89 .psl = false,
90},
84sepd1("Xopenmp-target"),91sepd1("Xopenmp-target"),
85sepd1("Xpreprocessor"),92sepd1("Xpreprocessor"),
86flagpd1("Z"),93flagpd1("Z"),
...@@ -1563,7 +1570,7 @@ sepd1("Zlinker-input"),...@@ -1563,7 +1570,7 @@ sepd1("Zlinker-input"),
1563.{1570.{
1564 .name = "for-linker",1571 .name = "for-linker",
1565 .syntax = .separate,1572 .syntax = .separate,
1566 .zig_equivalent = .other,1573 .zig_equivalent = .for_linker,
1567 .pd1 = false,1574 .pd1 = false,
1568 .pd2 = true,1575 .pd2 = true,
1569 .psl = false,1576 .psl = false,
...@@ -2547,7 +2554,14 @@ flagpd1("femulated-tls"),...@@ -2547,7 +2554,14 @@ flagpd1("femulated-tls"),
2547flagpd1("fencode-extended-block-signature"),2554flagpd1("fencode-extended-block-signature"),
2548sepd1("ferror-limit"),2555sepd1("ferror-limit"),
2549flagpd1("fescaping-block-tail-calls"),2556flagpd1("fescaping-block-tail-calls"),
2550flagpd1("fexceptions"),2557.{
2558 .name = "fexceptions",
2559 .syntax = .flag,
2560 .zig_equivalent = .exceptions,
2561 .pd1 = true,
2562 .pd2 = false,
2563 .psl = false,
2564},
2551flagpd1("fexperimental-isel"),2565flagpd1("fexperimental-isel"),
2552flagpd1("fexperimental-new-constant-interpreter"),2566flagpd1("fexperimental-new-constant-interpreter"),
2553flagpd1("fexperimental-new-pass-manager"),2567flagpd1("fexperimental-new-pass-manager"),
...@@ -2751,7 +2765,14 @@ flagpd1("fno-elide-type"),...@@ -2751,7 +2765,14 @@ flagpd1("fno-elide-type"),
2751flagpd1("fno-eliminate-unused-debug-symbols"),2765flagpd1("fno-eliminate-unused-debug-symbols"),
2752flagpd1("fno-emulated-tls"),2766flagpd1("fno-emulated-tls"),
2753flagpd1("fno-escaping-block-tail-calls"),2767flagpd1("fno-escaping-block-tail-calls"),
2754flagpd1("fno-exceptions"),2768.{
2769 .name = "fno-exceptions",
2770 .syntax = .flag,
2771 .zig_equivalent = .no_exceptions,
2772 .pd1 = true,
2773 .pd2 = false,
2774 .psl = false,
2775},
2755flagpd1("fno-experimental-isel"),2776flagpd1("fno-experimental-isel"),
2756flagpd1("fno-experimental-new-pass-manager"),2777flagpd1("fno-experimental-new-pass-manager"),
2757flagpd1("fno-fast-math"),2778flagpd1("fno-fast-math"),
...@@ -2840,7 +2861,14 @@ flagpd1("fno-rewrite-includes"),...@@ -2840,7 +2861,14 @@ flagpd1("fno-rewrite-includes"),
2840flagpd1("fno-ropi"),2861flagpd1("fno-ropi"),
2841flagpd1("fno-rounding-math"),2862flagpd1("fno-rounding-math"),
2842flagpd1("fno-rtlib-add-rpath"),2863flagpd1("fno-rtlib-add-rpath"),
2843flagpd1("fno-rtti"),2864.{
2865 .name = "fno-rtti",
2866 .syntax = .flag,
2867 .zig_equivalent = .no_rtti,
2868 .pd1 = true,
2869 .pd2 = false,
2870 .psl = false,
2871},
2844flagpd1("fno-rtti-data"),2872flagpd1("fno-rtti-data"),
2845flagpd1("fno-rwpi"),2873flagpd1("fno-rwpi"),
2846flagpd1("fno-sanitize-address-poison-custom-array-cookie"),2874flagpd1("fno-sanitize-address-poison-custom-array-cookie"),
...@@ -2988,7 +3016,14 @@ flagpd1("fno-frontend-optimize"),...@@ -2988,7 +3016,14 @@ flagpd1("fno-frontend-optimize"),
2988flagpd1("fropi"),3016flagpd1("fropi"),
2989flagpd1("frounding-math"),3017flagpd1("frounding-math"),
2990flagpd1("frtlib-add-rpath"),3018flagpd1("frtlib-add-rpath"),
2991flagpd1("frtti"),3019.{
3020 .name = "frtti",
3021 .syntax = .flag,
3022 .zig_equivalent = .rtti,
3023 .pd1 = true,
3024 .pd2 = false,
3025 .psl = false,
3026},
2992flagpd1("frwpi"),3027flagpd1("frwpi"),
2993flagpd1("fsanitize-address-globals-dead-stripping"),3028flagpd1("fsanitize-address-globals-dead-stripping"),
2994flagpd1("fsanitize-address-poison-custom-array-cookie"),3029flagpd1("fsanitize-address-poison-custom-array-cookie"),
...@@ -3752,7 +3787,14 @@ flagpd1("nostdinc++"),...@@ -3752,7 +3787,14 @@ flagpd1("nostdinc++"),
3752 .psl = false,3787 .psl = false,
3753},3788},
3754flagpd1("nostdlibinc"),3789flagpd1("nostdlibinc"),
3755flagpd1("nostdlib++"),3790.{
3791 .name = "nostdlib++",
3792 .syntax = .flag,
3793 .zig_equivalent = .nostdlib_cpp,
3794 .pd1 = true,
3795 .pd2 = false,
3796 .psl = false,
3797},
3756flagpd1("nostdsysteminc"),3798flagpd1("nostdsysteminc"),
3757flagpd1("objcmt-atomic-property"),3799flagpd1("objcmt-atomic-property"),
3758flagpd1("objcmt-migrate-all"),3800flagpd1("objcmt-migrate-all"),
...@@ -4241,7 +4283,14 @@ flagpd1("fno-whole-file"),...@@ -4241,7 +4283,14 @@ flagpd1("fno-whole-file"),
4241flagpd1("fwhole-program"),4283flagpd1("fwhole-program"),
4242flagpd1("fno-whole-program"),4284flagpd1("fno-whole-program"),
4243flagpd1("whyload"),4285flagpd1("whyload"),
4244sepd1("z"),4286.{
4287 .name = "z",
4288 .syntax = .separate,
4289 .zig_equivalent = .linker_input_z,
4290 .pd1 = true,
4291 .pd2 = false,
4292 .psl = false,
4293},
4245joinpd1("fsanitize-undefined-strip-path-components="),4294joinpd1("fsanitize-undefined-strip-path-components="),
4246joinpd1("fopenmp-cuda-teams-reduction-recs-num="),4295joinpd1("fopenmp-cuda-teams-reduction-recs-num="),
4247joinpd1("analyzer-config-compatibility-mode="),4296joinpd1("analyzer-config-compatibility-mode="),
...@@ -4880,7 +4929,7 @@ jspd1("sub_umbrella"),...@@ -4880,7 +4929,7 @@ jspd1("sub_umbrella"),
4880.{4929.{
4881 .name = "for-linker=",4930 .name = "for-linker=",
4882 .syntax = .joined,4931 .syntax = .joined,
4883 .zig_equivalent = .other,4932 .zig_equivalent = .for_linker,
4884 .pd1 = false,4933 .pd1 = false,
4885 .pd2 = true,4934 .pd2 = true,
4886 .psl = false,4935 .psl = false,
src-self-hosted/print_targets.zig+1-1
...@@ -75,7 +75,7 @@ pub fn cmdTargets(...@@ -75,7 +75,7 @@ pub fn cmdTargets(
75 var dir = try std.fs.cwd().openDir(zig_lib_dir, .{});75 var dir = try std.fs.cwd().openDir(zig_lib_dir, .{});
76 defer dir.close();76 defer dir.close();
7777
78 const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024);78 const vers_txt = try dir.readFileAlloc(allocator, "libc" ++ std.fs.path.sep_str ++ "glibc" ++ std.fs.path.sep_str ++ "vers.txt", 10 * 1024);
79 defer allocator.free(vers_txt);79 defer allocator.free(vers_txt);
8080
81 var list = std.ArrayList(std.builtin.Version).init(allocator);81 var list = std.ArrayList(std.builtin.Version).init(allocator);
src-self-hosted/stage2.zig+101-11
...@@ -114,6 +114,7 @@ const Error = extern enum {...@@ -114,6 +114,7 @@ const Error = extern enum {
114 InvalidAbiVersion,114 InvalidAbiVersion,
115 InvalidOperatingSystemVersion,115 InvalidOperatingSystemVersion,
116 UnknownClangOption,116 UnknownClangOption,
117 NestedResponseFile,
117 PermissionDenied,118 PermissionDenied,
118 FileBusy,119 FileBusy,
119 Locked,120 Locked,
...@@ -1265,6 +1266,7 @@ pub const ClangArgIterator = extern struct {...@@ -1265,6 +1266,7 @@ pub const ClangArgIterator = extern struct {
1265 argv_ptr: [*]const [*:0]const u8,1266 argv_ptr: [*]const [*:0]const u8,
1266 argv_len: usize,1267 argv_len: usize,
1267 next_index: usize,1268 next_index: usize,
1269 root_args: ?*Args,
12681270
1269 // ABI warning1271 // ABI warning
1270 pub const ZigEquivalent = extern enum {1272 pub const ZigEquivalent = extern enum {
...@@ -1279,6 +1281,7 @@ pub const ClangArgIterator = extern struct {...@@ -1279,6 +1281,7 @@ pub const ClangArgIterator = extern struct {
1279 pic,1281 pic,
1280 no_pic,1282 no_pic,
1281 nostdlib,1283 nostdlib,
1284 nostdlib_cpp,
1282 shared,1285 shared,
1283 rdynamic,1286 rdynamic,
1284 wl,1287 wl,
...@@ -1288,9 +1291,21 @@ pub const ClangArgIterator = extern struct {...@@ -1288,9 +1291,21 @@ pub const ClangArgIterator = extern struct {
1288 sanitize,1291 sanitize,
1289 linker_script,1292 linker_script,
1290 verbose_cmds,1293 verbose_cmds,
1294 exceptions,
1295 no_exceptions,
1296 rtti,
1297 no_rtti,
1298 for_linker,
1299 linker_input_z,
1291 };1300 };
12921301
1293 fn init(argv: []const [*:0]const u8) ClangArgIterator {1302 const Args = struct {
1303 next_index: usize,
1304 argv_ptr: [*]const [*:0]const u8,
1305 argv_len: usize,
1306 };
1307
1308 pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
1294 return .{1309 return .{
1295 .next_index = 2, // `zig cc foo` this points to `foo`1310 .next_index = 2, // `zig cc foo` this points to `foo`
1296 .has_next = argv.len > 2,1311 .has_next = argv.len > 2,
...@@ -1301,22 +1316,74 @@ pub const ClangArgIterator = extern struct {...@@ -1301,22 +1316,74 @@ pub const ClangArgIterator = extern struct {
1301 .other_args_len = undefined,1316 .other_args_len = undefined,
1302 .argv_ptr = argv.ptr,1317 .argv_ptr = argv.ptr,
1303 .argv_len = argv.len,1318 .argv_len = argv.len,
1319 .root_args = null,
1304 };1320 };
1305 }1321 }
13061322
1307 fn next(self: *ClangArgIterator) !void {1323 pub fn next(self: *ClangArgIterator) !void {
1308 assert(self.has_next);1324 assert(self.has_next);
1309 assert(self.next_index < self.argv_len);1325 assert(self.next_index < self.argv_len);
1310 // In this state we know that the parameter we are looking at is a root parameter1326 // In this state we know that the parameter we are looking at is a root parameter
1311 // rather than an argument to a parameter.1327 // rather than an argument to a parameter.
1312 self.other_args_ptr = self.argv_ptr + self.next_index;1328 self.other_args_ptr = self.argv_ptr + self.next_index;
1313 self.other_args_len = 1; // We adjust this value below when necessary.1329 self.other_args_len = 1; // We adjust this value below when necessary.
1314 const arg = mem.span(self.argv_ptr[self.next_index]);1330 var arg = mem.span(self.argv_ptr[self.next_index]);
1315 self.next_index += 1;1331 self.incrementArgIndex();
1316 defer {1332
1317 if (self.next_index >= self.argv_len) self.has_next = false;1333 if (mem.startsWith(u8, arg, "@")) {
1318 }1334 if (self.root_args != null) return error.NestedResponseFile;
1335
1336 // This is a "compiler response file". We must parse the file and treat its
1337 // contents as command line parameters.
1338 const allocator = std.heap.c_allocator;
1339 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
1340 const resp_file_path = arg[1..];
1341 const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
1342 std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
1343 process.exit(1);
1344 };
1345 defer allocator.free(resp_contents);
1346 // TODO is there a specification for this file format? Let's find it and make this parsing more robust
1347 // at the very least I'm guessing this needs to handle quotes and `#` comments.
1348 var it = mem.tokenize(resp_contents, " \t\r\n");
1349 var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
1350 defer resp_arg_list.deinit();
1351 {
1352 errdefer {
1353 for (resp_arg_list.span()) |item| {
1354 allocator.free(mem.span(item));
1355 }
1356 }
1357 while (it.next()) |token| {
1358 const dupe_token = try mem.dupeZ(allocator, u8, token);
1359 errdefer allocator.free(dupe_token);
1360 try resp_arg_list.append(dupe_token);
1361 }
1362 const args = try allocator.create(Args);
1363 errdefer allocator.destroy(args);
1364 args.* = .{
1365 .next_index = self.next_index,
1366 .argv_ptr = self.argv_ptr,
1367 .argv_len = self.argv_len,
1368 };
1369 self.root_args = args;
1370 }
1371 const resp_arg_slice = resp_arg_list.toOwnedSlice();
1372 self.next_index = 0;
1373 self.argv_ptr = resp_arg_slice.ptr;
1374 self.argv_len = resp_arg_slice.len;
1375
1376 if (resp_arg_slice.len == 0) {
1377 self.resolveRespFileArgs();
1378 return;
1379 }
13191380
1381 self.has_next = true;
1382 self.other_args_ptr = self.argv_ptr + self.next_index;
1383 self.other_args_len = 1; // We adjust this value below when necessary.
1384 arg = mem.span(self.argv_ptr[self.next_index]);
1385 self.incrementArgIndex();
1386 }
1320 if (!mem.startsWith(u8, arg, "-")) {1387 if (!mem.startsWith(u8, arg, "-")) {
1321 self.zig_equivalent = .positional;1388 self.zig_equivalent = .positional;
1322 self.only_arg = arg.ptr;1389 self.only_arg = arg.ptr;
...@@ -1353,7 +1420,7 @@ pub const ClangArgIterator = extern struct {...@@ -1353,7 +1420,7 @@ pub const ClangArgIterator = extern struct {
1353 process.exit(1);1420 process.exit(1);
1354 }1421 }
1355 self.only_arg = self.argv_ptr[self.next_index];1422 self.only_arg = self.argv_ptr[self.next_index];
1356 self.next_index += 1;1423 self.incrementArgIndex();
1357 self.other_args_len += 1;1424 self.other_args_len += 1;
1358 self.zig_equivalent = clang_arg.zig_equivalent;1425 self.zig_equivalent = clang_arg.zig_equivalent;
13591426
...@@ -1375,7 +1442,7 @@ pub const ClangArgIterator = extern struct {...@@ -1375,7 +1442,7 @@ pub const ClangArgIterator = extern struct {
1375 process.exit(1);1442 process.exit(1);
1376 }1443 }
1377 self.second_arg = self.argv_ptr[self.next_index];1444 self.second_arg = self.argv_ptr[self.next_index];
1378 self.next_index += 1;1445 self.incrementArgIndex();
1379 self.other_args_len += 1;1446 self.other_args_len += 1;
1380 self.zig_equivalent = clang_arg.zig_equivalent;1447 self.zig_equivalent = clang_arg.zig_equivalent;
1381 break :find_clang_arg;1448 break :find_clang_arg;
...@@ -1387,7 +1454,7 @@ pub const ClangArgIterator = extern struct {...@@ -1387,7 +1454,7 @@ pub const ClangArgIterator = extern struct {
1387 process.exit(1);1454 process.exit(1);
1388 }1455 }
1389 self.only_arg = self.argv_ptr[self.next_index];1456 self.only_arg = self.argv_ptr[self.next_index];
1390 self.next_index += 1;1457 self.incrementArgIndex();
1391 self.other_args_len += 1;1458 self.other_args_len += 1;
1392 self.zig_equivalent = clang_arg.zig_equivalent;1459 self.zig_equivalent = clang_arg.zig_equivalent;
1393 break :find_clang_arg;1460 break :find_clang_arg;
...@@ -1407,6 +1474,28 @@ pub const ClangArgIterator = extern struct {...@@ -1407,6 +1474,28 @@ pub const ClangArgIterator = extern struct {
1407 process.exit(1);1474 process.exit(1);
1408 }1475 }
1409 }1476 }
1477
1478 fn incrementArgIndex(self: *ClangArgIterator) void {
1479 self.next_index += 1;
1480 self.resolveRespFileArgs();
1481 }
1482
1483 fn resolveRespFileArgs(self: *ClangArgIterator) void {
1484 const allocator = std.heap.c_allocator;
1485 if (self.next_index >= self.argv_len) {
1486 if (self.root_args) |root_args| {
1487 self.next_index = root_args.next_index;
1488 self.argv_ptr = root_args.argv_ptr;
1489 self.argv_len = root_args.argv_len;
1490
1491 allocator.destroy(root_args);
1492 self.root_args = null;
1493 }
1494 if (self.next_index >= self.argv_len) {
1495 self.has_next = false;
1496 }
1497 }
1498 }
1410};1499};
14111500
1412export fn stage2_clang_arg_iterator(1501export fn stage2_clang_arg_iterator(
...@@ -1419,7 +1508,8 @@ export fn stage2_clang_arg_iterator(...@@ -1419,7 +1508,8 @@ export fn stage2_clang_arg_iterator(
14191508
1420export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {1509export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
1421 it.next() catch |err| switch (err) {1510 it.next() catch |err| switch (err) {
1422 error.UnknownClangOption => return .UnknownClangOption,1511 error.NestedResponseFile => return .NestedResponseFile,
1512 error.OutOfMemory => return .OutOfMemory,
1423 };1513 };
1424 return .None;1514 return .None;
1425}1515}
src/all_types.hpp+3
...@@ -2019,6 +2019,7 @@ struct CodeGen {...@@ -2019,6 +2019,7 @@ struct CodeGen {
2019 ZigLLVMDICompileUnit *compile_unit;2019 ZigLLVMDICompileUnit *compile_unit;
2020 ZigLLVMDIFile *compile_unit_file;2020 ZigLLVMDIFile *compile_unit_file;
2021 LinkLib *libc_link_lib;2021 LinkLib *libc_link_lib;
2022 LinkLib *libcpp_link_lib;
2022 LLVMTargetDataRef target_data_ref;2023 LLVMTargetDataRef target_data_ref;
2023 LLVMTargetMachineRef target_machine;2024 LLVMTargetMachineRef target_machine;
2024 ZigLLVMDIFile *dummy_di_file;2025 ZigLLVMDIFile *dummy_di_file;
...@@ -2261,6 +2262,8 @@ struct CodeGen {...@@ -2261,6 +2262,8 @@ struct CodeGen {
2261 bool emit_asm;2262 bool emit_asm;
2262 bool emit_llvm_ir;2263 bool emit_llvm_ir;
2263 bool test_is_evented;2264 bool test_is_evented;
2265 bool cpp_rtti;
2266 bool cpp_exceptions;
2264 CodeModel code_model;2267 CodeModel code_model;
22652268
2266 Buf *root_out_name;2269 Buf *root_out_name;
src/analyze.cpp+6
...@@ -7756,10 +7756,14 @@ LinkLib *create_link_lib(Buf *name) {...@@ -7756,10 +7756,14 @@ LinkLib *create_link_lib(Buf *name) {
77567756
7757LinkLib *add_link_lib(CodeGen *g, Buf *name) {7757LinkLib *add_link_lib(CodeGen *g, Buf *name) {
7758 bool is_libc = buf_eql_str(name, "c");7758 bool is_libc = buf_eql_str(name, "c");
7759 bool is_libcpp = buf_eql_str(name, "c++") || buf_eql_str(name, "c++abi");
77597760
7760 if (is_libc && g->libc_link_lib != nullptr)7761 if (is_libc && g->libc_link_lib != nullptr)
7761 return g->libc_link_lib;7762 return g->libc_link_lib;
77627763
7764 if (is_libcpp && g->libcpp_link_lib != nullptr)
7765 return g->libcpp_link_lib;
7766
7763 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {7767 for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
7764 LinkLib *existing_lib = g->link_libs_list.at(i);7768 LinkLib *existing_lib = g->link_libs_list.at(i);
7765 if (buf_eql_buf(existing_lib->name, name)) {7769 if (buf_eql_buf(existing_lib->name, name)) {
...@@ -7772,6 +7776,8 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {...@@ -7772,6 +7776,8 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
77727776
7773 if (is_libc)7777 if (is_libc)
7774 g->libc_link_lib = link_lib;7778 g->libc_link_lib = link_lib;
7779 if (is_libcpp)
7780 g->libcpp_link_lib = link_lib;
77757781
7776 return link_lib;7782 return link_lib;
7777}7783}
src/analyze.hpp+1
...@@ -260,6 +260,7 @@ ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type);...@@ -260,6 +260,7 @@ ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type);
260enum CSourceKind {260enum CSourceKind {
261 CSourceKindAsm,261 CSourceKindAsm,
262 CSourceKindC,262 CSourceKindC,
263 CSourceKindCpp,
263};264};
264265
265void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c,266void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_path, bool translate_c,
src/codegen.cpp+36-1
...@@ -8448,6 +8448,8 @@ static bool detect_dynamic_link(CodeGen *g) {...@@ -8448,6 +8448,8 @@ static bool detect_dynamic_link(CodeGen *g) {
8448 LinkLib *link_lib = g->link_libs_list.at(i);8448 LinkLib *link_lib = g->link_libs_list.at(i);
8449 if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))8449 if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name)))
8450 continue;8450 continue;
8451 if (target_is_libcpp_lib_name(g->zig_target, buf_ptr(link_lib->name)))
8452 continue;
8451 return true;8453 return true;
8452 }8454 }
8453 return false;8455 return false;
...@@ -8700,6 +8702,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -8700,6 +8702,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
8700 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);8702 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
8701 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));8703 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
8702 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));8704 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
8705 buf_appendf(contents, "pub const link_libcpp = %s;\n", bool_to_str(g->libcpp_link_lib != nullptr));
8703 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));8706 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
8704 buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g)));8707 buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g)));
8705 buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic));8708 buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic));
...@@ -8781,6 +8784,8 @@ static Error define_builtin_compile_vars(CodeGen *g) {...@@ -8781,6 +8784,8 @@ static Error define_builtin_compile_vars(CodeGen *g) {
8781 cache_bool(&cache_hash, g->is_test_build);8784 cache_bool(&cache_hash, g->is_test_build);
8782 cache_bool(&cache_hash, g->is_single_threaded);8785 cache_bool(&cache_hash, g->is_single_threaded);
8783 cache_bool(&cache_hash, g->test_is_evented);8786 cache_bool(&cache_hash, g->test_is_evented);
8787 cache_bool(&cache_hash, g->cpp_rtti);
8788 cache_bool(&cache_hash, g->cpp_exceptions);
8784 cache_int(&cache_hash, g->code_model);8789 cache_int(&cache_hash, g->code_model);
8785 cache_int(&cache_hash, g->zig_target->is_native_os);8790 cache_int(&cache_hash, g->zig_target->is_native_os);
8786 cache_int(&cache_hash, g->zig_target->is_native_cpu);8791 cache_int(&cache_hash, g->zig_target->is_native_cpu);
...@@ -8798,6 +8803,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {...@@ -8798,6 +8803,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
8798 }8803 }
8799 cache_bool(&cache_hash, g->have_err_ret_tracing);8804 cache_bool(&cache_hash, g->have_err_ret_tracing);
8800 cache_bool(&cache_hash, g->libc_link_lib != nullptr);8805 cache_bool(&cache_hash, g->libc_link_lib != nullptr);
8806 cache_bool(&cache_hash, g->libcpp_link_lib != nullptr);
8801 cache_bool(&cache_hash, g->valgrind_support);8807 cache_bool(&cache_hash, g->valgrind_support);
8802 cache_bool(&cache_hash, g->link_eh_frame_hdr);8808 cache_bool(&cache_hash, g->link_eh_frame_hdr);
8803 cache_int(&cache_hash, detect_subsystem(g));8809 cache_int(&cache_hash, detect_subsystem(g));
...@@ -9179,7 +9185,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -9179,7 +9185,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
9179 }9185 }
91809186
9181 if (translate_c) {9187 if (translate_c) {
9182 if (source_kind == CSourceKindC) {9188 if (source_kind != CSourceKindAsm) {
9183 // this gives us access to preprocessing entities, presumably at9189 // this gives us access to preprocessing entities, presumably at
9184 // the cost of performance9190 // the cost of performance
9185 args.append("-Xclang");9191 args.append("-Xclang");
...@@ -9205,6 +9211,20 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -9205,6 +9211,20 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
9205 args.append(g->framework_dirs.at(i));9211 args.append(g->framework_dirs.at(i));
9206 }9212 }
92079213
9214 if (g->libcpp_link_lib != nullptr) {
9215 const char *libcxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
9216 buf_ptr(g->zig_lib_dir)));
9217
9218 args.append("-isystem");
9219 args.append(libcxx_include_path);
9220
9221 if (target_abi_is_musl(g->zig_target->abi)) {
9222 args.append("-D_LIBCPP_HAS_MUSL_LIBC");
9223 }
9224 args.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
9225 args.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
9226 }
9227
9208 // According to Rich Felker libc headers are supposed to go before C language headers.9228 // According to Rich Felker libc headers are supposed to go before C language headers.
9209 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics9229 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
9210 // and other compiler specific items.9230 // and other compiler specific items.
...@@ -9222,6 +9242,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -9222,6 +9242,7 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
92229242
9223 switch (source_kind) {9243 switch (source_kind) {
9224 case CSourceKindC:9244 case CSourceKindC:
9245 case CSourceKindCpp:
9225 if (g->zig_target->llvm_cpu_name != nullptr) {9246 if (g->zig_target->llvm_cpu_name != nullptr) {
9226 args.append("-Xclang");9247 args.append("-Xclang");
9227 args.append("-target-cpu");9248 args.append("-target-cpu");
...@@ -9238,6 +9259,14 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -9238,6 +9259,14 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
9238 case CSourceKindAsm:9259 case CSourceKindAsm:
9239 break;9260 break;
9240 }9261 }
9262 if (source_kind == CSourceKindCpp) {
9263 if (!g->cpp_rtti) {
9264 args.append("-fno-rtti");
9265 }
9266 if (!g->cpp_exceptions) {
9267 args.append("-fno-exceptions");
9268 }
9269 }
9241 for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) {9270 for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) {
9242 args.append(g->zig_target->llvm_cpu_features_asm_ptr[i]);9271 args.append(g->zig_target->llvm_cpu_features_asm_ptr[i]);
9243 }9272 }
...@@ -9685,6 +9714,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose...@@ -9685,6 +9714,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
9685 cache_bool(cache_hash, g->have_sanitize_c);9714 cache_bool(cache_hash, g->have_sanitize_c);
9686 cache_bool(cache_hash, want_valgrind_support(g));9715 cache_bool(cache_hash, want_valgrind_support(g));
9687 cache_bool(cache_hash, g->function_sections);9716 cache_bool(cache_hash, g->function_sections);
9717 cache_bool(cache_hash, g->cpp_rtti);
9718 cache_bool(cache_hash, g->cpp_exceptions);
9688 cache_int(cache_hash, g->code_model);9719 cache_int(cache_hash, g->code_model);
96899720
9690 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {9721 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
...@@ -10519,6 +10550,8 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10519,6 +10550,8 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10519 cache_bool(ch, g->emit_bin);10550 cache_bool(ch, g->emit_bin);
10520 cache_bool(ch, g->emit_llvm_ir);10551 cache_bool(ch, g->emit_llvm_ir);
10521 cache_bool(ch, g->emit_asm);10552 cache_bool(ch, g->emit_asm);
10553 cache_bool(ch, g->cpp_rtti);
10554 cache_bool(ch, g->cpp_exceptions);
10522 cache_usize(ch, g->version_major);10555 cache_usize(ch, g->version_major);
10523 cache_usize(ch, g->version_minor);10556 cache_usize(ch, g->version_minor);
10524 cache_usize(ch, g->version_patch);10557 cache_usize(ch, g->version_patch);
...@@ -10823,6 +10856,8 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o...@@ -10823,6 +10856,8 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
10823 parent_gen->build_mode, parent_gen->zig_lib_dir, libc, get_global_cache_dir(), false, child_progress_node);10856 parent_gen->build_mode, parent_gen->zig_lib_dir, libc, get_global_cache_dir(), false, child_progress_node);
10824 child_gen->root_out_name = buf_create_from_str(name);10857 child_gen->root_out_name = buf_create_from_str(name);
10825 child_gen->disable_gen_h = true;10858 child_gen->disable_gen_h = true;
10859 child_gen->cpp_rtti = parent_gen->cpp_rtti;
10860 child_gen->cpp_exceptions = parent_gen->cpp_exceptions;
10826 child_gen->want_stack_check = WantStackCheckDisabled;10861 child_gen->want_stack_check = WantStackCheckDisabled;
10827 child_gen->want_sanitize_c = WantCSanitizeDisabled;10862 child_gen->want_sanitize_c = WantCSanitizeDisabled;
10828 child_gen->verbose_tokenize = parent_gen->verbose_tokenize;10863 child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
src/error.cpp+1
...@@ -84,6 +84,7 @@ const char *err_str(Error err) {...@@ -84,6 +84,7 @@ const char *err_str(Error err) {
84 case ErrorInvalidAbiVersion: return "invalid C ABI version";84 case ErrorInvalidAbiVersion: return "invalid C ABI version";
85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
86 case ErrorUnknownClangOption: return "unknown Clang option";86 case ErrorUnknownClangOption: return "unknown Clang option";
87 case ErrorNestedResponseFile: return "nested response file";
87 case ErrorPermissionDenied: return "permission is denied";88 case ErrorPermissionDenied: return "permission is denied";
88 case ErrorFileBusy: return "file is busy";89 case ErrorFileBusy: return "file is busy";
89 case ErrorLocked: return "file is locked by another process";90 case ErrorLocked: return "file is locked by another process";
src/install_files.h+63
...@@ -1841,4 +1841,67 @@ static const char *ZIG_MUSL_COMPAT_TIME32_FILES[] = {...@@ -1841,4 +1841,67 @@ static const char *ZIG_MUSL_COMPAT_TIME32_FILES[] = {
1841"musl/compat/time32/wait3_time32.c",1841"musl/compat/time32/wait3_time32.c",
1842"musl/compat/time32/wait4_time32.c",1842"musl/compat/time32/wait4_time32.c",
1843};1843};
1844static const char *ZIG_LIBCXXABI_FILES[] = {
1845"src/abort_message.cpp",
1846"src/cxa_aux_runtime.cpp",
1847"src/cxa_default_handlers.cpp",
1848"src/cxa_demangle.cpp",
1849"src/cxa_exception.cpp",
1850"src/cxa_exception_storage.cpp",
1851"src/cxa_guard.cpp",
1852"src/cxa_handlers.cpp",
1853"src/cxa_noexception.cpp",
1854"src/cxa_personality.cpp",
1855"src/cxa_thread_atexit.cpp",
1856"src/cxa_unexpected.cpp",
1857"src/cxa_vector.cpp",
1858"src/cxa_virtual.cpp",
1859"src/fallback_malloc.cpp",
1860"src/private_typeinfo.cpp",
1861"src/stdlib_exception.cpp",
1862"src/stdlib_stdexcept.cpp",
1863"src/stdlib_typeinfo.cpp",
1864};
1865static const char *ZIG_LIBCXX_FILES[] = {
1866"src/algorithm.cpp",
1867"src/any.cpp",
1868"src/bind.cpp",
1869"src/charconv.cpp",
1870"src/chrono.cpp",
1871"src/condition_variable.cpp",
1872"src/condition_variable_destructor.cpp",
1873"src/debug.cpp",
1874"src/exception.cpp",
1875"src/experimental/memory_resource.cpp",
1876"src/filesystem/directory_iterator.cpp",
1877"src/filesystem/operations.cpp",
1878"src/functional.cpp",
1879"src/future.cpp",
1880"src/hash.cpp",
1881"src/ios.cpp",
1882"src/iostream.cpp",
1883"src/locale.cpp",
1884"src/memory.cpp",
1885"src/mutex.cpp",
1886"src/mutex_destructor.cpp",
1887"src/new.cpp",
1888"src/optional.cpp",
1889"src/random.cpp",
1890"src/regex.cpp",
1891"src/shared_mutex.cpp",
1892"src/stdexcept.cpp",
1893"src/string.cpp",
1894"src/strstream.cpp",
1895"src/support/solaris/xlocale.cpp",
1896"src/support/win32/locale_win32.cpp",
1897"src/support/win32/support.cpp",
1898"src/support/win32/thread_win32.cpp",
1899"src/system_error.cpp",
1900"src/thread.cpp",
1901"src/typeinfo.cpp",
1902"src/utility.cpp",
1903"src/valarray.cpp",
1904"src/variant.cpp",
1905"src/vector.cpp",
1906};
1844#endif1907#endif
src/link.cpp+164-4
...@@ -14,6 +14,8 @@...@@ -14,6 +14,8 @@
14#include "glibc.hpp"14#include "glibc.hpp"
1515
16static const char *msvcrt_common_src[] = {16static const char *msvcrt_common_src[] = {
17 "misc" OS_SEP "_create_locale.c",
18 "misc" OS_SEP "_free_locale.c",
17 "misc" OS_SEP "onexit_table.c",19 "misc" OS_SEP "onexit_table.c",
18 "misc" OS_SEP "register_tls_atexit.c",20 "misc" OS_SEP "register_tls_atexit.c",
19 "stdio" OS_SEP "acrt_iob_func.c",21 "stdio" OS_SEP "acrt_iob_func.c",
...@@ -632,12 +634,17 @@ static const char *build_libunwind(CodeGen *parent, Stage2ProgressNode *progress...@@ -632,12 +634,17 @@ static const char *build_libunwind(CodeGen *parent, Stage2ProgressNode *progress
632 }634 }
633 c_file->args.append("-I");635 c_file->args.append("-I");
634 c_file->args.append(path_from_libunwind(parent, "include"));636 c_file->args.append(path_from_libunwind(parent, "include"));
635 c_file->args.append("-fPIC");637 if (target_supports_fpic(parent->zig_target)) {
638 c_file->args.append("-fPIC");
639 }
636 c_file->args.append("-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS");640 c_file->args.append("-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS");
637 c_file->args.append("-Wa,--noexecstack");641 c_file->args.append("-Wa,--noexecstack");
638 if (parent->zig_target->is_native_os && parent->zig_target->is_native_cpu) {642
639 c_file->args.append("-D_LIBUNWIND_IS_NATIVE_ONLY");643 // This is intentionally always defined because the macro definition means, should it only
640 }644 // build for the target specified by compiler defines. Since we pass -target the compiler
645 // defines will be correct.
646 c_file->args.append("-D_LIBUNWIND_IS_NATIVE_ONLY");
647
641 if (parent->build_mode == BuildModeDebug) {648 if (parent->build_mode == BuildModeDebug) {
642 c_file->args.append("-D_DEBUG");649 c_file->args.append("-D_DEBUG");
643 }650 }
...@@ -1107,6 +1114,128 @@ static const char *build_musl(CodeGen *parent, Stage2ProgressNode *progress_node...@@ -1107,6 +1114,128 @@ static const char *build_musl(CodeGen *parent, Stage2ProgressNode *progress_node
1107 return buf_ptr(&child_gen->bin_file_output_path);1114 return buf_ptr(&child_gen->bin_file_output_path);
1108}1115}
11091116
1117static const char *build_libcxxabi(CodeGen *parent, Stage2ProgressNode *progress_node) {
1118 CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "c++abi", progress_node);
1119 codegen_add_link_lib(child_gen, buf_create_from_str("c"));
1120
1121 ZigList<CFile *> c_source_files = {0};
1122
1123 const char *cxxabi_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxxabi" OS_SEP "include",
1124 buf_ptr(parent->zig_lib_dir)));
1125 const char *cxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
1126 buf_ptr(parent->zig_lib_dir)));
1127
1128 for (size_t i = 0; i < array_length(ZIG_LIBCXXABI_FILES); i += 1) {
1129 const char *rel_src_path = ZIG_LIBCXXABI_FILES[i];
1130
1131 CFile *c_file = heap::c_allocator.create<CFile>();
1132 c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxxabi" OS_SEP "%s",
1133 buf_ptr(parent->zig_lib_dir), rel_src_path));
1134
1135 c_file->args.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
1136 c_file->args.append("-D_LIBCPP_DISABLE_EXTERN_TEMPLATE");
1137 c_file->args.append("-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS");
1138 c_file->args.append("-D_LIBCXXABI_BUILDING_LIBRARY");
1139 c_file->args.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
1140 c_file->args.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
1141
1142 if (target_abi_is_musl(parent->zig_target->abi)) {
1143 c_file->args.append("-D_LIBCPP_HAS_MUSL_LIBC");
1144 }
1145
1146 c_file->args.append("-I");
1147 c_file->args.append(cxxabi_include_path);
1148
1149 c_file->args.append("-I");
1150 c_file->args.append(cxx_include_path);
1151
1152 c_file->args.append("-O3");
1153 c_file->args.append("-DNDEBUG");
1154 if (target_supports_fpic(parent->zig_target)) {
1155 c_file->args.append("-fPIC");
1156 }
1157 c_file->args.append("-nostdinc++");
1158 c_file->args.append("-fstrict-aliasing");
1159 c_file->args.append("-funwind-tables");
1160 c_file->args.append("-D_DEBUG");
1161 c_file->args.append("-UNDEBUG");
1162 c_file->args.append("-std=c++11");
1163
1164 c_source_files.append(c_file);
1165 }
1166
1167
1168 child_gen->c_source_files = c_source_files;
1169 codegen_build_and_link(child_gen);
1170 return buf_ptr(&child_gen->bin_file_output_path);
1171}
1172
1173static const char *build_libcxx(CodeGen *parent, Stage2ProgressNode *progress_node) {
1174 CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "c++", progress_node);
1175 codegen_add_link_lib(child_gen, buf_create_from_str("c"));
1176
1177 ZigList<CFile *> c_source_files = {0};
1178
1179 const char *cxxabi_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxxabi" OS_SEP "include",
1180 buf_ptr(parent->zig_lib_dir)));
1181 const char *cxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
1182 buf_ptr(parent->zig_lib_dir)));
1183
1184 for (size_t i = 0; i < array_length(ZIG_LIBCXX_FILES); i += 1) {
1185 const char *rel_src_path = ZIG_LIBCXX_FILES[i];
1186
1187 Buf *src_path_buf = buf_create_from_str(rel_src_path);
1188 if (parent->zig_target->os == OsWindows) {
1189 // filesystem stuff isn't supported on Windows
1190 if (buf_starts_with_str(src_path_buf, "src/filesystem/")) {
1191 continue;
1192 }
1193 } else {
1194 if (buf_starts_with_str(src_path_buf, "src/support/win32/")) {
1195 continue;
1196 }
1197 }
1198
1199 CFile *c_file = heap::c_allocator.create<CFile>();
1200 c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "%s",
1201 buf_ptr(parent->zig_lib_dir), rel_src_path));
1202
1203 c_file->args.append("-DNDEBUG");
1204 c_file->args.append("-D_LIBCPP_BUILDING_LIBRARY");
1205 c_file->args.append("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER");
1206 c_file->args.append("-DLIBCXX_BUILDING_LIBCXXABI");
1207 c_file->args.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
1208 c_file->args.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
1209
1210 if (target_abi_is_musl(parent->zig_target->abi)) {
1211 c_file->args.append("-D_LIBCPP_HAS_MUSL_LIBC");
1212 }
1213
1214 c_file->args.append("-I");
1215 c_file->args.append(cxx_include_path);
1216
1217 c_file->args.append("-I");
1218 c_file->args.append(cxxabi_include_path);
1219
1220 c_file->args.append("-O3");
1221 c_file->args.append("-DNDEBUG");
1222 if (target_supports_fpic(parent->zig_target)) {
1223 c_file->args.append("-fPIC");
1224 }
1225 c_file->args.append("-nostdinc++");
1226 c_file->args.append("-fvisibility-inlines-hidden");
1227 c_file->args.append("-std=c++14");
1228 c_file->args.append("-Wno-user-defined-literals");
1229
1230 c_source_files.append(c_file);
1231 }
1232
1233
1234 child_gen->c_source_files = c_source_files;
1235 codegen_build_and_link(child_gen);
1236 return buf_ptr(&child_gen->bin_file_output_path);
1237}
1238
1110static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) {1239static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) {
1111 CFile *c_file = heap::c_allocator.create<CFile>();1240 CFile *c_file = heap::c_allocator.create<CFile>();
1112 c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s",1241 c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s",
...@@ -1646,6 +1775,10 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1646,6 +1775,10 @@ static void construct_linker_job_elf(LinkJob *lj) {
1646 lj->args.append("--eh-frame-hdr");1775 lj->args.append("--eh-frame-hdr");
1647 }1776 }
16481777
1778 if (g->linker_rdynamic) {
1779 lj->args.append("--export-dynamic");
1780 }
1781
1649 lj->args.append("-m");1782 lj->args.append("-m");
1650 lj->args.append(getLDMOption(g->zig_target));1783 lj->args.append(getLDMOption(g->zig_target));
16511784
...@@ -1770,6 +1903,10 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1770,6 +1903,10 @@ static void construct_linker_job_elf(LinkJob *lj) {
1770 // libc is linked specially1903 // libc is linked specially
1771 continue;1904 continue;
1772 }1905 }
1906 if (buf_eql_str(link_lib->name, "c++") || buf_eql_str(link_lib->name, "c++abi")) {
1907 // libc++ is linked specially
1908 continue;
1909 }
1773 if (g->libc == nullptr && target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) {1910 if (g->libc == nullptr && target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) {
1774 // these libraries are always linked below when targeting glibc1911 // these libraries are always linked below when targeting glibc
1775 continue;1912 continue;
...@@ -1785,6 +1922,11 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1785,6 +1922,11 @@ static void construct_linker_job_elf(LinkJob *lj) {
1785 lj->args.append(buf_ptr(arg));1922 lj->args.append(buf_ptr(arg));
1786 }1923 }
17871924
1925 // libc++ dep
1926 if (g->libcpp_link_lib != nullptr && g->out_type != OutTypeObj) {
1927 lj->args.append(build_libcxxabi(g, lj->build_dep_prog_node));
1928 lj->args.append(build_libcxx(g, lj->build_dep_prog_node));
1929 }
17881930
1789 // libc dep1931 // libc dep
1790 if (g->libc_link_lib != nullptr && g->out_type != OutTypeObj) {1932 if (g->libc_link_lib != nullptr && g->out_type != OutTypeObj) {
...@@ -1815,6 +1957,8 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1815,6 +1957,8 @@ static void construct_linker_job_elf(LinkJob *lj) {
1815 lj->args.append(build_libunwind(g, lj->build_dep_prog_node));1957 lj->args.append(build_libunwind(g, lj->build_dep_prog_node));
1816 }1958 }
1817 lj->args.append(build_musl(g, lj->build_dep_prog_node));1959 lj->args.append(build_musl(g, lj->build_dep_prog_node));
1960 } else if (g->libcpp_link_lib != nullptr) {
1961 lj->args.append(build_libunwind(g, lj->build_dep_prog_node));
1818 } else {1962 } else {
1819 zig_unreachable();1963 zig_unreachable();
1820 }1964 }
...@@ -2303,6 +2447,13 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -2303,6 +2447,13 @@ static void construct_linker_job_coff(LinkJob *lj) {
2303 break;2447 break;
2304 }2448 }
23052449
2450 // libc++ dep
2451 if (g->libcpp_link_lib != nullptr && g->out_type != OutTypeObj) {
2452 lj->args.append(build_libcxxabi(g, lj->build_dep_prog_node));
2453 lj->args.append(build_libcxx(g, lj->build_dep_prog_node));
2454 lj->args.append(build_libunwind(g, lj->build_dep_prog_node));
2455 }
2456
2306 if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {2457 if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {
2307 if (g->libc_link_lib == nullptr && !g->is_dummy_so) {2458 if (g->libc_link_lib == nullptr && !g->is_dummy_so) {
2308 Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node);2459 Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node);
...@@ -2319,6 +2470,9 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -2319,6 +2470,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
2319 if (buf_eql_str(link_lib->name, "c")) {2470 if (buf_eql_str(link_lib->name, "c")) {
2320 continue;2471 continue;
2321 }2472 }
2473 if (buf_eql_str(link_lib->name, "c++") || buf_eql_str(link_lib->name, "c++abi")) {
2474 continue;
2475 }
2322 bool is_sys_lib = is_mingw_link_lib(link_lib->name);2476 bool is_sys_lib = is_mingw_link_lib(link_lib->name);
2323 if (have_windows_dll_import_libs && is_sys_lib) {2477 if (have_windows_dll_import_libs && is_sys_lib) {
2324 continue;2478 continue;
...@@ -2454,6 +2608,12 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -2454,6 +2608,12 @@ static void construct_linker_job_macho(LinkJob *lj) {
2454 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));2608 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
2455 }2609 }
24562610
2611 // libc++ dep
2612 if (g->libcpp_link_lib != nullptr && g->out_type != OutTypeObj) {
2613 lj->args.append(build_libcxxabi(g, lj->build_dep_prog_node));
2614 lj->args.append(build_libcxx(g, lj->build_dep_prog_node));
2615 }
2616
2457 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce2617 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
2458 if (g->out_type == OutTypeExe || is_dyn_lib) {2618 if (g->out_type == OutTypeExe || is_dyn_lib) {
2459 Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node);2619 Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node);
src/main.cpp+47-1
...@@ -412,6 +412,7 @@ static int main0(int argc, char **argv) {...@@ -412,6 +412,7 @@ static int main0(int argc, char **argv) {
412 ZigList<const char *> framework_dirs = {0};412 ZigList<const char *> framework_dirs = {0};
413 ZigList<const char *> frameworks = {0};413 ZigList<const char *> frameworks = {0};
414 bool have_libc = false;414 bool have_libc = false;
415 bool have_libcpp = false;
415 const char *target_string = nullptr;416 const char *target_string = nullptr;
416 bool rdynamic = false;417 bool rdynamic = false;
417 const char *linker_script = nullptr;418 const char *linker_script = nullptr;
...@@ -456,6 +457,9 @@ static int main0(int argc, char **argv) {...@@ -456,6 +457,9 @@ static int main0(int argc, char **argv) {
456 const char *override_soname = nullptr;457 const char *override_soname = nullptr;
457 bool only_preprocess = false;458 bool only_preprocess = false;
458 bool ensure_libc_on_non_freestanding = false;459 bool ensure_libc_on_non_freestanding = false;
460 bool ensure_libcpp_on_non_freestanding = false;
461 bool cpp_rtti = true;
462 bool cpp_exceptions = true;
459463
460 ZigList<const char *> llvm_argv = {0};464 ZigList<const char *> llvm_argv = {0};
461 llvm_argv.append("zig (LLVM option parsing)");465 llvm_argv.append("zig (LLVM option parsing)");
...@@ -580,10 +584,11 @@ static int main0(int argc, char **argv) {...@@ -580,10 +584,11 @@ static int main0(int argc, char **argv) {
580 return (term.how == TerminationIdClean) ? term.code : -1;584 return (term.how == TerminationIdClean) ? term.code : -1;
581 } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {585 } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
582 return stage2_fmt(argc, argv);586 return stage2_fmt(argc, argv);
583 } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) {587 } else if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || strcmp(argv[1], "c++") == 0)) {
584 emit_h = false;588 emit_h = false;
585 strip = true;589 strip = true;
586 ensure_libc_on_non_freestanding = true;590 ensure_libc_on_non_freestanding = true;
591 ensure_libcpp_on_non_freestanding = (strcmp(argv[1], "c++") == 0);
587592
588 bool c_arg = false;593 bool c_arg = false;
589 Stage2ClangArgIterator it;594 Stage2ClangArgIterator it;
...@@ -632,6 +637,8 @@ static int main0(int argc, char **argv) {...@@ -632,6 +637,8 @@ static int main0(int argc, char **argv) {
632 case Stage2ClangArgL: // -l637 case Stage2ClangArgL: // -l
633 if (strcmp(it.only_arg, "c") == 0)638 if (strcmp(it.only_arg, "c") == 0)
634 have_libc = true;639 have_libc = true;
640 if (strcmp(it.only_arg, "c++") == 0)
641 have_libcpp = true;
635 link_libs.append(it.only_arg);642 link_libs.append(it.only_arg);
636 break;643 break;
637 case Stage2ClangArgIgnore:644 case Stage2ClangArgIgnore:
...@@ -648,6 +655,9 @@ static int main0(int argc, char **argv) {...@@ -648,6 +655,9 @@ static int main0(int argc, char **argv) {
648 case Stage2ClangArgNoStdLib:655 case Stage2ClangArgNoStdLib:
649 ensure_libc_on_non_freestanding = false;656 ensure_libc_on_non_freestanding = false;
650 break;657 break;
658 case Stage2ClangArgNoStdLibCpp:
659 ensure_libcpp_on_non_freestanding = false;
660 break;
651 case Stage2ClangArgShared:661 case Stage2ClangArgShared:
652 is_dynamic = true;662 is_dynamic = true;
653 is_shared_lib = true;663 is_shared_lib = true;
...@@ -712,6 +722,25 @@ static int main0(int argc, char **argv) {...@@ -712,6 +722,25 @@ static int main0(int argc, char **argv) {
712 verbose_cc = true;722 verbose_cc = true;
713 verbose_link = true;723 verbose_link = true;
714 break;724 break;
725 case Stage2ClangArgExceptions:
726 cpp_exceptions = true;
727 break;
728 case Stage2ClangArgNoExceptions:
729 cpp_exceptions = false;
730 break;
731 case Stage2ClangArgRtti:
732 cpp_rtti = true;
733 break;
734 case Stage2ClangArgNoRtti:
735 cpp_rtti = false;
736 break;
737 case Stage2ClangArgForLinker:
738 linker_args.append(buf_create_from_str(it.only_arg));
739 break;
740 case Stage2ClangArgLinkerInputZ:
741 linker_args.append(buf_create_from_str("-z"));
742 linker_args.append(buf_create_from_str(it.only_arg));
743 break;
715 }744 }
716 }745 }
717 // Parse linker args746 // Parse linker args
...@@ -768,6 +797,11 @@ static int main0(int argc, char **argv) {...@@ -768,6 +797,11 @@ static int main0(int argc, char **argv) {
768 return EXIT_FAILURE;797 return EXIT_FAILURE;
769 }798 }
770 dynamic_linker = buf_ptr(linker_args.at(i));799 dynamic_linker = buf_ptr(linker_args.at(i));
800 } else if (buf_eql_str(arg, "-E") ||
801 buf_eql_str(arg, "--export-dynamic") ||
802 buf_eql_str(arg, "-export-dynamic"))
803 {
804 rdynamic = true;
771 } else {805 } else {
772 fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg));806 fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg));
773 }807 }
...@@ -916,6 +950,8 @@ static int main0(int argc, char **argv) {...@@ -916,6 +950,8 @@ static int main0(int argc, char **argv) {
916 const char *l = &arg[2];950 const char *l = &arg[2];
917 if (strcmp(l, "c") == 0)951 if (strcmp(l, "c") == 0)
918 have_libc = true;952 have_libc = true;
953 if (strcmp(l, "c++") == 0)
954 have_libcpp = true;
919 link_libs.append(l);955 link_libs.append(l);
920 } else if (arg[1] == 'I' && arg[2] != 0) {956 } else if (arg[1] == 'I' && arg[2] != 0) {
921 clang_argv.append("-I");957 clang_argv.append("-I");
...@@ -1057,6 +1093,8 @@ static int main0(int argc, char **argv) {...@@ -1057,6 +1093,8 @@ static int main0(int argc, char **argv) {
1057 } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {1093 } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {
1058 if (strcmp(argv[i], "c") == 0)1094 if (strcmp(argv[i], "c") == 0)
1059 have_libc = true;1095 have_libc = true;
1096 if (strcmp(argv[i], "c++") == 0)
1097 have_libcpp = true;
1060 link_libs.append(argv[i]);1098 link_libs.append(argv[i]);
1061 } else if (strcmp(arg, "--forbid-library") == 0) {1099 } else if (strcmp(arg, "--forbid-library") == 0) {
1062 forbidden_link_libs.append(argv[i]);1100 forbidden_link_libs.append(argv[i]);
...@@ -1221,6 +1259,10 @@ static int main0(int argc, char **argv) {...@@ -1221,6 +1259,10 @@ static int main0(int argc, char **argv) {
1221 have_libc = true;1259 have_libc = true;
1222 link_libs.append("c");1260 link_libs.append("c");
1223 }1261 }
1262 if (!have_libcpp && ensure_libcpp_on_non_freestanding && target.os != OsFreestanding) {
1263 have_libcpp = true;
1264 link_libs.append("c++");
1265 }
12241266
1225 Buf zig_triple_buf = BUF_INIT;1267 Buf zig_triple_buf = BUF_INIT;
1226 target_triple_zig(&zig_triple_buf, &target);1268 target_triple_zig(&zig_triple_buf, &target);
...@@ -1287,6 +1329,8 @@ static int main0(int argc, char **argv) {...@@ -1287,6 +1329,8 @@ static int main0(int argc, char **argv) {
1287 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));1329 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
1288 link_lib->provided_explicitly = true;1330 link_lib->provided_explicitly = true;
1289 }1331 }
1332 g->cpp_rtti = cpp_rtti;
1333 g->cpp_exceptions = cpp_exceptions;
1290 g->subsystem = subsystem;1334 g->subsystem = subsystem;
1291 g->valgrind_support = valgrind_support;1335 g->valgrind_support = valgrind_support;
1292 g->want_pic = want_pic;1336 g->want_pic = want_pic;
...@@ -1433,6 +1477,8 @@ static int main0(int argc, char **argv) {...@@ -1433,6 +1477,8 @@ static int main0(int argc, char **argv) {
1433 }1477 }
1434 CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,1478 CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
1435 override_lib_dir, libc, cache_dir_buf, cmd == CmdTest, root_progress_node);1479 override_lib_dir, libc, cache_dir_buf, cmd == CmdTest, root_progress_node);
1480 g->cpp_rtti = cpp_rtti;
1481 g->cpp_exceptions = cpp_exceptions;
1436 if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2);1482 if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2);
1437 g->valgrind_support = valgrind_support;1483 g->valgrind_support = valgrind_support;
1438 g->link_eh_frame_hdr = link_eh_frame_hdr;1484 g->link_eh_frame_hdr = link_eh_frame_hdr;
src/stage2.cpp+4
...@@ -197,6 +197,10 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons...@@ -197,6 +197,10 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
197{197{
198 Error err;198 Error err;
199199
200 if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
201 zig_triple = nullptr;
202 }
203
200 if (zig_triple == nullptr) {204 if (zig_triple == nullptr) {
201 get_native_target(target);205 get_native_target(target);
202206
src/stage2.h+9
...@@ -106,6 +106,7 @@ enum Error {...@@ -106,6 +106,7 @@ enum Error {
106 ErrorInvalidAbiVersion,106 ErrorInvalidAbiVersion,
107 ErrorInvalidOperatingSystemVersion,107 ErrorInvalidOperatingSystemVersion,
108 ErrorUnknownClangOption,108 ErrorUnknownClangOption,
109 ErrorNestedResponseFile,
109 ErrorPermissionDenied,110 ErrorPermissionDenied,
110 ErrorFileBusy,111 ErrorFileBusy,
111 ErrorLocked,112 ErrorLocked,
...@@ -337,6 +338,7 @@ enum Stage2ClangArg {...@@ -337,6 +338,7 @@ enum Stage2ClangArg {
337 Stage2ClangArgPIC,338 Stage2ClangArgPIC,
338 Stage2ClangArgNoPIC,339 Stage2ClangArgNoPIC,
339 Stage2ClangArgNoStdLib,340 Stage2ClangArgNoStdLib,
341 Stage2ClangArgNoStdLibCpp,
340 Stage2ClangArgShared,342 Stage2ClangArgShared,
341 Stage2ClangArgRDynamic,343 Stage2ClangArgRDynamic,
342 Stage2ClangArgWL,344 Stage2ClangArgWL,
...@@ -346,6 +348,12 @@ enum Stage2ClangArg {...@@ -346,6 +348,12 @@ enum Stage2ClangArg {
346 Stage2ClangArgSanitize,348 Stage2ClangArgSanitize,
347 Stage2ClangArgLinkerScript,349 Stage2ClangArgLinkerScript,
348 Stage2ClangArgVerboseCmds,350 Stage2ClangArgVerboseCmds,
351 Stage2ClangArgExceptions,
352 Stage2ClangArgNoExceptions,
353 Stage2ClangArgRtti,
354 Stage2ClangArgNoRtti,
355 Stage2ClangArgForLinker,
356 Stage2ClangArgLinkerInputZ,
349};357};
350358
351// ABI warning359// ABI warning
...@@ -359,6 +367,7 @@ struct Stage2ClangArgIterator {...@@ -359,6 +367,7 @@ struct Stage2ClangArgIterator {
359 const char **argv_ptr;367 const char **argv_ptr;
360 size_t argv_len;368 size_t argv_len;
361 size_t next_index;369 size_t next_index;
370 size_t root_args;
362};371};
363372
364// ABI warning373// ABI warning
src/target.cpp+7
...@@ -1229,6 +1229,13 @@ bool target_is_libc_lib_name(const ZigTarget *target, const char *name) {...@@ -1229,6 +1229,13 @@ bool target_is_libc_lib_name(const ZigTarget *target, const char *name) {
1229 return false;1229 return false;
1230}1230}
12311231
1232bool target_is_libcpp_lib_name(const ZigTarget *target, const char *name) {
1233 if (strcmp(name, "c++") == 0 || strcmp(name, "c++abi") == 0)
1234 return true;
1235
1236 return false;
1237}
1238
1232size_t target_libc_count(void) {1239size_t target_libc_count(void) {
1233 return array_length(libcs_available);1240 return array_length(libcs_available);
1234}1241}
src/target.hpp+1
...@@ -102,6 +102,7 @@ bool target_os_requires_libc(Os os);...@@ -102,6 +102,7 @@ bool target_os_requires_libc(Os os);
102bool target_can_build_libc(const ZigTarget *target);102bool target_can_build_libc(const ZigTarget *target);
103const char *target_libc_generic_name(const ZigTarget *target);103const char *target_libc_generic_name(const ZigTarget *target);
104bool target_is_libc_lib_name(const ZigTarget *target, const char *name);104bool target_is_libc_lib_name(const ZigTarget *target, const char *name);
105bool target_is_libcpp_lib_name(const ZigTarget *target, const char *name);
105bool target_supports_fpic(const ZigTarget *target);106bool target_supports_fpic(const ZigTarget *target);
106bool target_supports_clang_march_native(const ZigTarget *target);107bool target_supports_clang_march_native(const ZigTarget *target);
107bool target_requires_pic(const ZigTarget *target, bool linking_libc);108bool target_requires_pic(const ZigTarget *target, bool linking_libc);
test/stack_traces.zig+1-1
...@@ -282,7 +282,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -282,7 +282,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282 \\source.zig:10:8: [address] in main (test)282 \\source.zig:10:8: [address] in main (test)
283 \\ foo();283 \\ foo();
284 \\ ^284 \\ ^
285 \\start.zig:256:29: [address] in std.start.posixCallMainAndExit (test)285 \\start.zig:250:29: [address] in std.start.posixCallMainAndExit (test)
286 \\ return root.main();286 \\ return root.main();
287 \\ ^287 \\ ^
288 \\start.zig:123:5: [address] in std.start._start (test)288 \\start.zig:123:5: [address] in std.start._start (test)
tools/update_clang_options.zig+36
...@@ -62,6 +62,10 @@ const known_options = [_]KnownOpt{...@@ -62,6 +62,10 @@ const known_options = [_]KnownOpt{
62 .name = "no-standard-libraries",62 .name = "no-standard-libraries",
63 .ident = "nostdlib",63 .ident = "nostdlib",
64 },64 },
65 .{
66 .name = "nostdlib++",
67 .ident = "nostdlib_cpp",
68 },
65 .{69 .{
66 .name = "shared",70 .name = "shared",
67 .ident = "shared",71 .ident = "shared",
...@@ -74,6 +78,22 @@ const known_options = [_]KnownOpt{...@@ -74,6 +78,22 @@ const known_options = [_]KnownOpt{
74 .name = "Wl,",78 .name = "Wl,",
75 .ident = "wl",79 .ident = "wl",
76 },80 },
81 .{
82 .name = "Xlinker",
83 .ident = "for_linker",
84 },
85 .{
86 .name = "for-linker",
87 .ident = "for_linker",
88 },
89 .{
90 .name = "for-linker=",
91 .ident = "for_linker",
92 },
93 .{
94 .name = "z",
95 .ident = "linker_input_z",
96 },
77 .{97 .{
78 .name = "E",98 .name = "E",
79 .ident = "preprocess",99 .ident = "preprocess",
...@@ -154,6 +174,22 @@ const known_options = [_]KnownOpt{...@@ -154,6 +174,22 @@ const known_options = [_]KnownOpt{
154 .name = "###",174 .name = "###",
155 .ident = "verbose_cmds",175 .ident = "verbose_cmds",
156 },176 },
177 .{
178 .name = "fexceptions",
179 .ident = "exceptions",
180 },
181 .{
182 .name = "fno-exceptions",
183 .ident = "no_exceptions",
184 },
185 .{
186 .name = "frtti",
187 .ident = "rtti",
188 },
189 .{
190 .name = "fno-rtti",
191 .ident = "no_rtti",
192 },
157};193};
158194
159const blacklisted_options = [_][]const u8{};195const blacklisted_options = [_][]const u8{};