Roll chromium_revision c92ed25217..bcf2616e8e (559015:559838)
Change log: https://chromium.googlesource.com/chromium/src/+log/c92ed25217..bcf2616e8e
Full diff: https://chromium.googlesource.com/chromium/src/+/c92ed25217..bcf2616e8e
Roll chromium third_party 51c08cf9af..9d65a3cdda
Change log: https://chromium.googlesource.com/chromium/src/third_party/+log/51c08cf9af..9d65a3cdda
Changed dependencies:
* src/base: https://chromium.googlesource.com/chromium/src/base/+log/a7a2409f9b..b802985ef4
* src/build: https://chromium.googlesource.com/chromium/src/build/+log/03f39fd800..fc8308f6b6
* src/buildtools: https://chromium.googlesource.com/chromium/buildtools.git/+log/a9e946f166..94288c26d2
* src/ios: https://chromium.googlesource.com/chromium/src/ios/+log/e070a93062..289c450460
* src/testing: https://chromium.googlesource.com/chromium/src/testing/+log/f5b31b58c6..a5fce03148
* src/third_party/catapult: https://chromium.googlesource.com/catapult.git/+log/d8600ccc2d..ce9b3742a1
* src/third_party/depot_tools: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+log/8de3800ce5..8fe4d8cbef
* src/third_party/googletest/src: https://chromium.googlesource.com/external/github.com/google/googletest.git/+log/045e7f9ee4..08d5b1f33a
* src/tools: https://chromium.googlesource.com/chromium/src/tools/+log/e024720629..6e6e398687
* src/tools/swarming_client: https://chromium.googlesource.com/infra/luci/client-py.git/+log/88229872dd..833f5ebf89
DEPS diff: https://chromium.googlesource.com/chromium/src/+/c92ed25217..bcf2616e8e/DEPS
No update to Clang.
TBR=buildbot@webrtc.org,
BUG=None
CQ_INCLUDE_TRYBOTS=master.internal.tryserver.corp.webrtc:linux_internal
Change-Id: I22bf301fcec0103a1987a92f95ebf86e324dade7
Reviewed-on: https://webrtc-review.googlesource.com/77625
Reviewed-by: WebRTC Buildbot <buildbot@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23296}
diff --git a/DEPS b/DEPS
index 0fe61e5..f4c77ea 100644
--- a/DEPS
+++ b/DEPS
@@ -10,12 +10,12 @@
'checkout_configuration': 'default',
'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"',
'webrtc_git': 'https://webrtc.googlesource.com',
- 'chromium_revision': 'c92ed252174bc9b9ece9d11a83852f4ab8765575',
+ 'chromium_revision': 'bcf2616e8eb74191a038c9ad457344fa0354f420',
'boringssl_git': 'https://boringssl.googlesource.com',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling swarming_client
# and whatever else without interference from each other.
- 'swarming_revision': '88229872dd17e71658fe96763feaa77915d8cbd6',
+ 'swarming_revision': '833f5ebf894be1e3e6d13678d5de8479bf12ff28',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other.
@@ -27,7 +27,7 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling catapult
# and whatever else without interference from each other.
- 'catapult_revision': 'd8600ccc2ddeb2cc43ba6adccea9f687f5f1b2a9',
+ 'catapult_revision': 'ce9b3742a10dc2f4c796a1b26e73155d0bfa674a',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libFuzzer
# and whatever else without interference from each other.
@@ -43,17 +43,17 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Chromium third_party
# and whatever else without interference from each other.
- 'chromium_third_party_revision': '51c08cf9af330cc4173d8e37974e49074431d5f4',
+ 'chromium_third_party_revision': '9d65a3cddae9b8340d4c77b1ae9034d4501935b8',
}
deps = {
# TODO(kjellander): Move this to be Android-only once the libevent dependency
# in base/third_party/libevent is solved.
'src/base':
- Var('chromium_git') + '/chromium/src/base' + '@' + 'a7a2409f9b398da1abc5e7604a974a1fa2ade51d',
+ Var('chromium_git') + '/chromium/src/base' + '@' + 'b802985ef4661601e825640d1a566489cfcb6d8b',
'src/build':
- Var('chromium_git') + '/chromium/src/build' + '@' + '03f39fd800ed8fd5fa1a8b43b5963c6fc063475b',
+ Var('chromium_git') + '/chromium/src/build' + '@' + 'fc8308f6b6c6212c6be8d2769c721611d5253b49',
'src/buildtools':
- Var('chromium_git') + '/chromium/buildtools.git' + '@' + 'a9e946f166b73f9dc170129f6586a1e68efb0ab3',
+ Var('chromium_git') + '/chromium/buildtools.git' + '@' + '94288c26d2ffe3aec9848c147839afee597acefd',
# Gradle 4.3-rc4. Used for testing Android Studio project generation for WebRTC.
'src/examples/androidtests/third_party/gradle': {
'url': Var('chromium_git') + '/external/github.com/gradle/gradle.git' + '@' +
@@ -61,11 +61,11 @@
'condition': 'checkout_android',
},
'src/ios': {
- 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + 'e070a9306253c327361423e1fce2ae02c419f6ba',
+ 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '289c450460f6a2faf57d1ee011ef7595691dd25b',
'condition': 'checkout_ios',
},
'src/testing':
- Var('chromium_git') + '/chromium/src/testing' + '@' + 'f5b31b58c69ca3bbcfe81d8c2028063931f6681e',
+ Var('chromium_git') + '/chromium/src/testing' + '@' + 'a5fce03148805a479c78b685b31f5a2392218ffd',
# This entry is used for chromium third_party rolling into webrtc third_party only.
'src/third_party_chromium': {
'url': Var('chromium_git') + '/chromium/src/third_party' + '@' + Var('chromium_third_party_revision'),
@@ -94,7 +94,7 @@
'src/third_party/colorama/src':
Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
'src/third_party/depot_tools':
- Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8de3800ce55ba459ffcbedcfa52ef5e6e59caab6',
+ Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8fe4d8cbef3bff9d615de14d9a414679cf9ca8c3',
'src/third_party/errorprone/lib': {
'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '980d49e839aa4984015efed34b0134d4b2c9b6d7',
'condition': 'checkout_android',
@@ -113,7 +113,7 @@
'src/third_party/gtest-parallel':
Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + 'cb3514a0858be0f66281d892e2242d1073fd75fe',
'src/third_party/googletest/src':
- Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '045e7f9ee4f969ac1a3fe428f79c4b880f0aff43',
+ Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '08d5b1f33af8c18785fb8ca02792b5fac81e248f',
'src/third_party/icu': {
'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f61e46dbee9d539a32551493e3bcc1dea92f83ec',
},
@@ -175,7 +175,7 @@
'src/third_party/yasm/source/patched-yasm':
Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc',
'src/tools':
- Var('chromium_git') + '/chromium/src/tools' + '@' + 'e0247206293ec06cc0aee950384e13721cd55d86',
+ Var('chromium_git') + '/chromium/src/tools' + '@' + '6e6e39868794fc2bfeaf64502ad903be79616a0b',
'src/tools/gyp':
Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
'src/tools/swarming_client':
diff --git a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
index 0520fba..e4eafe4 100644
--- a/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilHelpers.cmake
@@ -16,6 +16,11 @@
include(CMakeParseArguments)
+# The IDE folder for Abseil that will be used if Abseil is included in a CMake
+# project that sets
+# set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+# For example, Visual Studio supports folders.
+set(ABSL_IDE_FOLDER Abseil)
#
# create a library in the absl namespace
@@ -49,6 +54,8 @@
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS}
)
+ # Add all Abseil targets to a a folder in the IDE for organization.
+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
if(ABSL_LIB_EXPORT_NAME)
add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
@@ -93,6 +100,9 @@
PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS}
)
+ # Add all Abseil targets to a a folder in the IDE for organization.
+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
+
if(ABSL_HO_LIB_EXPORT_NAME)
add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
endif()
@@ -139,7 +149,10 @@
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
)
- add_test(${_NAME}_test ${_NAME}_bin)
+ # Add all Abseil targets to a a folder in the IDE for organization.
+ set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER})
+
+ add_test(${_NAME} ${_NAME}_bin)
endif(BUILD_TESTING)
endfunction()
diff --git a/third_party/abseil-cpp/CMake/CMakeLists.txt.in b/third_party/abseil-cpp/CMake/CMakeLists.txt.in
new file mode 100644
index 0000000..d60a33e
--- /dev/null
+++ b/third_party/abseil-cpp/CMake/CMakeLists.txt.in
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.2)
+
+project(googletest-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(googletest
+ GIT_REPOSITORY https://github.com/google/googletest.git
+ GIT_TAG master
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+)
\ No newline at end of file
diff --git a/third_party/abseil-cpp/CMake/DownloadGTest.cmake b/third_party/abseil-cpp/CMake/DownloadGTest.cmake
new file mode 100644
index 0000000..9d41321
--- /dev/null
+++ b/third_party/abseil-cpp/CMake/DownloadGTest.cmake
@@ -0,0 +1,32 @@
+# Downloads and unpacks googletest at configure time. Based on the instructions
+# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
+
+# Download the latest googletest from Github master
+configure_file(
+ ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
+ googletest-download/CMakeLists.txt
+)
+
+# Configure and build the downloaded googletest source
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
+if(result)
+ message(FATAL_ERROR "CMake step for googletest failed: ${result}")
+endif()
+
+execute_process(COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+if(result)
+ message(FATAL_ERROR "Build step for googletest failed: ${result}")
+endif()
+
+# Prevent overriding the parent project's compiler/linker settings on Windows
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+
+# Add googletest directly to our build. This defines the gtest and gtest_main
+# targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
+ ${CMAKE_BINARY_DIR}/googletest-build
+ EXCLUDE_FROM_ALL)
diff --git a/third_party/abseil-cpp/CMake/README.md b/third_party/abseil-cpp/CMake/README.md
index e99340c..79bbe24 100644
--- a/third_party/abseil-cpp/CMake/README.md
+++ b/third_party/abseil-cpp/CMake/README.md
@@ -52,14 +52,42 @@
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
endif()
-add_subdirectory(googletest)
-add_subdirectory(cctz)
add_subdirectory(abseil-cpp)
add_executable(my_exe source.cpp)
target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
```
+### Running Abseil Tests with CMake
+
+Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
+
+You will need to provide Abseil with a Googletest dependency. There are two
+options for how to do this:
+
+* Use `-DABSL_USE_GOOGLETEST_HEAD`. This will automatically download the latest
+Googletest source into the build directory at configure time. Googletest will
+then be compiled directly alongside Abseil's tests.
+* Manually integrate Googletest with your build. See
+https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake
+for more information on using Googletest in a CMake project.
+
+For example, to run just the Abseil tests, you could use this script:
+
+```
+cd path/to/abseil-cpp
+mkdir build
+cd build
+cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
+make -j
+ctest
+```
+
+Currently, we only run our tests with CMake in a Linux environment, but we are
+working on the rest of our supported platforms. See
+https://github.com/abseil/abseil-cpp/projects/1 and
+https://github.com/abseil/abseil-cpp/issues/109 for more information.
+
### Available Abseil CMake Public Targets
Here's a non-exhaustive list of Abseil CMake public targets:
diff --git a/third_party/abseil-cpp/CMakeLists.txt b/third_party/abseil-cpp/CMakeLists.txt
index e46bdf4..744241e 100644
--- a/third_party/abseil-cpp/CMakeLists.txt
+++ b/third_party/abseil-cpp/CMakeLists.txt
@@ -16,9 +16,6 @@
cmake_minimum_required(VERSION 2.8.12)
project(absl)
-# enable ctest
-include(CTest)
-
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake)
include(GNUInstallDirs)
@@ -56,7 +53,6 @@
# -std=X
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_WARNING_VLA} ${CMAKE_CXX_FLAGS} ")
# -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
@@ -65,12 +61,25 @@
## pthread
find_package(Threads REQUIRED)
-# commented: used only for standalone test
-# Don't remove these or else CMake CI will break
-#add_subdirectory(googletest)
+option(ABSL_USE_GOOGLETEST_HEAD
+ "If ON, abseil will download HEAD from googletest at config time." OFF)
+
+option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
+
+if(${ABSL_RUN_TESTS})
+ # enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
+ # on the command line
+ include(CTest)
+ enable_testing()
+endif()
## check targets
if(BUILD_TESTING)
+
+ if(${ABSL_USE_GOOGLETEST_HEAD})
+ include(CMake/DownloadGTest.cmake)
+ endif()
+
check_target(gtest)
check_target(gtest_main)
check_target(gmock)
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index 1c3b40a..84f9b0b 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
License: Apache 2.0
License File: LICENSE
Version: 0
-Revision: af7882601aad93ada881486eeaabc562f1733961
+Revision: 30de20488bb88dc22d23521c5c222ec6d924e289
Security Critical: yes
Description:
diff --git a/third_party/abseil-cpp/WORKSPACE b/third_party/abseil-cpp/WORKSPACE
index 0546573..0644593 100644
--- a/third_party/abseil-cpp/WORKSPACE
+++ b/third_party/abseil-cpp/WORKSPACE
@@ -3,11 +3,11 @@
http_archive(
name = "bazel_toolchains",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
- "https://github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
+ "https://github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
],
- strip_prefix = "bazel-toolchains-r324073",
- sha256 = "71548c0d6cd53eddebbde4fa9962f5395e82645fb9992719e0890505b177f245",
+ strip_prefix = "bazel-toolchains-f8847f64e6950e8ab9fde1c0aba768550b0d9ab2",
+ sha256 = "794366f51fea224b3656a0b0f8f1518e739748646523a572fcd3d68614a0e670",
)
# GoogleTest/GoogleMock framework. Used by most unit-tests.
@@ -17,6 +17,13 @@
strip_prefix = "googletest-master",
)
+# Google benchmark.
+http_archive(
+ name = "com_github_google_benchmark",
+ urls = ["https://github.com/google/benchmark/archive/master.zip"],
+ strip_prefix = "benchmark-master",
+)
+
# RE2 regular-expression framework. Used by some unit-tests.
http_archive(
name = "com_googlesource_code_re2",
diff --git a/third_party/abseil-cpp/absl/algorithm/BUILD.bazel b/third_party/abseil-cpp/absl/algorithm/BUILD.bazel
index 255b986..3b24ce1 100644
--- a/third_party/abseil-cpp/absl/algorithm/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/algorithm/BUILD.bazel
@@ -41,6 +41,18 @@
],
)
+cc_test(
+ name = "algorithm_benchmark",
+ srcs = ["equal_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ tags = ["benchmark"],
+ deps = [
+ ":algorithm",
+ "//absl/base:core_headers",
+ "@com_github_google_benchmark//:benchmark",
+ ],
+)
+
cc_library(
name = "container",
hdrs = [
diff --git a/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc b/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc
new file mode 100644
index 0000000..9af36ce
--- /dev/null
+++ b/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc
@@ -0,0 +1,128 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstdint>
+#include <cstring>
+
+#include "benchmark/benchmark.h"
+#include "absl/algorithm/algorithm.h"
+
+namespace {
+
+// The range of sequence sizes to benchmark.
+constexpr int kMinBenchmarkSize = 1024;
+constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
+
+// A user-defined type for use in equality benchmarks. Note that we expect
+// std::memcmp to win for this type: libstdc++'s std::equal only defers to
+// memcmp for integral types. This is because it is not straightforward to
+// guarantee that std::memcmp would produce a result "as-if" compared by
+// operator== for other types (example gotchas: NaN floats, structs with
+// padding).
+struct EightBits {
+ explicit EightBits(int /* unused */) : data(0) {}
+ bool operator==(const EightBits& rhs) const { return data == rhs.data; }
+ uint8_t data;
+};
+
+template <typename T>
+void BM_absl_equal_benchmark(benchmark::State& state) {
+ std::vector<T> xs(state.range(0), T(0));
+ std::vector<T> ys = xs;
+ while (state.KeepRunning()) {
+ const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
+ benchmark::DoNotOptimize(same);
+ }
+}
+
+template <typename T>
+void BM_std_equal_benchmark(benchmark::State& state) {
+ std::vector<T> xs(state.range(0), T(0));
+ std::vector<T> ys = xs;
+ while (state.KeepRunning()) {
+ const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
+ benchmark::DoNotOptimize(same);
+ }
+}
+
+template <typename T>
+void BM_memcmp_benchmark(benchmark::State& state) {
+ std::vector<T> xs(state.range(0), T(0));
+ std::vector<T> ys = xs;
+ while (state.KeepRunning()) {
+ const bool same =
+ std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
+ benchmark::DoNotOptimize(same);
+ }
+}
+
+// The expectation is that the compiler should be able to elide the equality
+// comparison altogether for sufficiently simple types.
+template <typename T>
+void BM_absl_equal_self_benchmark(benchmark::State& state) {
+ std::vector<T> xs(state.range(0), T(0));
+ while (state.KeepRunning()) {
+ const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
+ benchmark::DoNotOptimize(same);
+ }
+}
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+} // namespace
+
+BENCHMARK_MAIN();
diff --git a/third_party/abseil-cpp/absl/base/BUILD.bazel b/third_party/abseil-cpp/absl/base/BUILD.bazel
index f9aac5a..5c05c67 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/base/BUILD.bazel
@@ -148,6 +148,18 @@
)
cc_test(
+ name = "atomic_hook_test",
+ size = "small",
+ srcs = ["internal/atomic_hook_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":base",
+ ":core_headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
name = "bit_cast_test",
size = "small",
srcs = [
@@ -393,3 +405,16 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_test(
+ name = "thread_identity_benchmark",
+ srcs = ["internal/thread_identity_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":base",
+ "//absl/synchronization",
+ "@com_github_google_benchmark//:benchmark",
+ ],
+)
diff --git a/third_party/abseil-cpp/absl/base/CMakeLists.txt b/third_party/abseil-cpp/absl/base/CMakeLists.txt
index 329a3d0..4564056 100644
--- a/third_party/abseil-cpp/absl/base/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/base/CMakeLists.txt
@@ -99,14 +99,18 @@
if(BUILD_TESTING)
# exception-safety testing library
- set(EXCEPTION_SAFETY_TESTING_SRC "internal/exception_safety_testing.cc")
+ set(EXCEPTION_SAFETY_TESTING_SRC
+ "internal/exception_safety_testing.h"
+ "internal/exception_safety_testing.cc"
+ )
set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
${ABSL_TEST_COMMON_LIBRARIES}
absl::base
absl::memory
absl::meta
absl::strings
- absl::types
+ absl::optional
+ gtest
)
absl_library(
@@ -116,6 +120,8 @@
${EXCEPTION_SAFETY_TESTING_SRC}
PUBLIC_LIBRARIES
${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
+ PRIVATE_COMPILE_FLAGS
+ ${ABSL_EXCEPTIONS_FLAG}
)
endif()
@@ -163,6 +169,20 @@
#
# call once test
+set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
+set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+ TARGET
+ atomic_hook_test
+ SOURCES
+ ${ATOMIC_HOOK_TEST_SRC}
+ PUBLIC_LIBRARIES
+ ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# call once test
set(CALL_ONCE_TEST_SRC "call_once_test.cc")
set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
@@ -344,7 +364,14 @@
#test exceptions_safety_testing_test
set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
-set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES absl::base absl::memory absl::meta absl::strings absl::optional)
+set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
+ absl::base
+ absl_base_internal_exception_safety_testing
+ absl::memory
+ absl::meta
+ absl::strings
+ absl::optional
+)
absl_test(
TARGET
diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h
index a4ec7e7..b1883b6 100644
--- a/third_party/abseil-cpp/absl/base/attributes.h
+++ b/third_party/abseil-cpp/absl/base/attributes.h
@@ -52,7 +52,8 @@
// Example:
//
// // Enable branches in the Abseil code that are tagged for ASan:
-// $ bazel -D ADDRESS_SANITIZER -fsanitize=address *target*
+// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
+// --linkopt=-fsanitize=address *target*
//
// Since these macro names are only supported by GCC and Clang, we only check
// for `__GNUC__` (GCC or Clang) and the above macros.
diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
index ae6ec0f..b97fa3a 100644
--- a/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
+++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.cc
@@ -32,7 +32,7 @@
/* Each function is empty and called (via a macro) only in debug mode.
The arguments are captured by dynamic tools at runtime. */
-#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
#if __has_feature(memory_sanitizer)
#include <sanitizer/msan_interface.h>
diff --git a/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/third_party/abseil-cpp/absl/base/dynamic_annotations.h
index 88048b0..b308e93 100644
--- a/third_party/abseil-cpp/absl/base/dynamic_annotations.h
+++ b/third_party/abseil-cpp/absl/base/dynamic_annotations.h
@@ -191,16 +191,16 @@
#elif defined(ABSL_ANNOTALYSIS_ENABLED)
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
- AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+ StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_READS_END() \
- AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+ StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
- AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+ StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
- AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+ StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
#else
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */
@@ -282,13 +282,13 @@
allows IGNORE_READS_AND_WRITES to work properly. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
-static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
+static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
+static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreWritesBegin(
+static inline void StaticAnnotateIgnoreWritesBegin(
const char *file, int line) { (void)file; (void)line; }
-static inline void AbslStaticAnnotateIgnoreWritesEnd(
+static inline void StaticAnnotateIgnoreWritesEnd(
const char *file, int line) { (void)file; (void)line; }
#pragma GCC diagnostic pop
#endif
diff --git a/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc b/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc
index 94a7e4f..a8b82b7 100644
--- a/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc
+++ b/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc
@@ -25,11 +25,13 @@
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
-namespace absl {
+namespace testing {
+
namespace {
-using ::absl::exceptions_internal::SetCountdown;
-using ::absl::exceptions_internal::TestException;
-using ::absl::exceptions_internal::UnsetCountdown;
+
+using ::testing::exceptions_internal::SetCountdown;
+using ::testing::exceptions_internal::TestException;
+using ::testing::exceptions_internal::UnsetCountdown;
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
template <typename F>
@@ -41,15 +43,7 @@
}
}
-class ThrowingValueTest : public ::testing::Test {
- protected:
- void SetUp() override { UnsetCountdown(); }
-
- private:
- ConstructorTracker clouseau_;
-};
-
-TEST_F(ThrowingValueTest, Throws) {
+TEST(ThrowingValueTest, Throws) {
SetCountdown();
EXPECT_THROW(ThrowingValue<> bomb, TestException);
@@ -60,6 +54,8 @@
ExpectNoThrow([]() { ThrowingValue<> bomb; });
ExpectNoThrow([]() { ThrowingValue<> bomb; });
EXPECT_THROW(ThrowingValue<> bomb, TestException);
+
+ UnsetCountdown();
}
// Tests that an operation throws when the countdown is at 0, doesn't throw when
@@ -67,7 +63,6 @@
// ThrowingValue if it throws
template <typename F>
void TestOp(const F& f) {
- UnsetCountdown();
ExpectNoThrow(f);
SetCountdown();
@@ -75,7 +70,7 @@
UnsetCountdown();
}
-TEST_F(ThrowingValueTest, ThrowingCtors) {
+TEST(ThrowingValueTest, ThrowingCtors) {
ThrowingValue<> bomb;
TestOp([]() { ThrowingValue<> bomb(1); });
@@ -83,14 +78,35 @@
TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
}
-TEST_F(ThrowingValueTest, ThrowingAssignment) {
+TEST(ThrowingValueTest, ThrowingAssignment) {
ThrowingValue<> bomb, bomb1;
TestOp([&]() { bomb = bomb1; });
TestOp([&]() { bomb = std::move(bomb1); });
+
+ // Test that when assignment throws, the assignment should fail (lhs != rhs)
+ // and strong guarantee fails (lhs != lhs_copy).
+ {
+ ThrowingValue<> lhs(39), rhs(42);
+ ThrowingValue<> lhs_copy(lhs);
+ SetCountdown();
+ EXPECT_THROW(lhs = rhs, TestException);
+ UnsetCountdown();
+ EXPECT_NE(lhs, rhs);
+ EXPECT_NE(lhs_copy, lhs);
+ }
+ {
+ ThrowingValue<> lhs(39), rhs(42);
+ ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
+ SetCountdown();
+ EXPECT_THROW(lhs = std::move(rhs), TestException);
+ UnsetCountdown();
+ EXPECT_NE(lhs, rhs_copy);
+ EXPECT_NE(lhs_copy, lhs);
+ }
}
-TEST_F(ThrowingValueTest, ThrowingComparisons) {
+TEST(ThrowingValueTest, ThrowingComparisons) {
ThrowingValue<> bomb1, bomb2;
TestOp([&]() { return bomb1 == bomb2; });
TestOp([&]() { return bomb1 != bomb2; });
@@ -100,7 +116,7 @@
TestOp([&]() { return bomb1 >= bomb2; });
}
-TEST_F(ThrowingValueTest, ThrowingArithmeticOps) {
+TEST(ThrowingValueTest, ThrowingArithmeticOps) {
ThrowingValue<> bomb1(1), bomb2(2);
TestOp([&bomb1]() { +bomb1; });
@@ -118,7 +134,7 @@
TestOp([&]() { bomb1 >> 1; });
}
-TEST_F(ThrowingValueTest, ThrowingLogicalOps) {
+TEST(ThrowingValueTest, ThrowingLogicalOps) {
ThrowingValue<> bomb1, bomb2;
TestOp([&bomb1]() { !bomb1; });
@@ -126,7 +142,7 @@
TestOp([&]() { bomb1 || bomb2; });
}
-TEST_F(ThrowingValueTest, ThrowingBitwiseOps) {
+TEST(ThrowingValueTest, ThrowingBitwiseOps) {
ThrowingValue<> bomb1, bomb2;
TestOp([&bomb1]() { ~bomb1; });
@@ -135,7 +151,7 @@
TestOp([&]() { bomb1 ^ bomb2; });
}
-TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
+TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
ThrowingValue<> bomb1(1), bomb2(2);
TestOp([&]() { bomb1 += bomb2; });
@@ -149,7 +165,7 @@
TestOp([&]() { bomb1 *= bomb2; });
}
-TEST_F(ThrowingValueTest, ThrowingStreamOps) {
+TEST(ThrowingValueTest, ThrowingStreamOps) {
ThrowingValue<> bomb;
TestOp([&]() { std::cin >> bomb; });
@@ -158,7 +174,6 @@
template <typename F>
void TestAllocatingOp(const F& f) {
- UnsetCountdown();
ExpectNoThrow(f);
SetCountdown();
@@ -166,62 +181,90 @@
UnsetCountdown();
}
-TEST_F(ThrowingValueTest, ThrowingAllocatingOps) {
+TEST(ThrowingValueTest, ThrowingAllocatingOps) {
// make_unique calls unqualified operator new, so these exercise the
// ThrowingValue overloads.
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
}
-TEST_F(ThrowingValueTest, NonThrowingMoveCtor) {
- ThrowingValue<NoThrow::kMoveCtor> nothrow_ctor;
+TEST(ThrowingValueTest, NonThrowingMoveCtor) {
+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;
SetCountdown();
ExpectNoThrow([¬hrow_ctor]() {
- ThrowingValue<NoThrow::kMoveCtor> nothrow1 = std::move(nothrow_ctor);
+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);
});
+ UnsetCountdown();
}
-TEST_F(ThrowingValueTest, NonThrowingMoveAssign) {
- ThrowingValue<NoThrow::kMoveAssign> nothrow_assign1, nothrow_assign2;
+TEST(ThrowingValueTest, NonThrowingMoveAssign) {
+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;
SetCountdown();
ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {
nothrow_assign1 = std::move(nothrow_assign2);
});
+ UnsetCountdown();
}
-TEST_F(ThrowingValueTest, ThrowingSwap) {
+TEST(ThrowingValueTest, ThrowingCopyCtor) {
+ ThrowingValue<> tv;
+
+ TestOp([&]() { ThrowingValue<> tv_copy(tv); });
+}
+
+TEST(ThrowingValueTest, ThrowingCopyAssign) {
+ ThrowingValue<> tv1, tv2;
+
+ TestOp([&]() { tv1 = tv2; });
+}
+
+TEST(ThrowingValueTest, NonThrowingCopyCtor) {
+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;
+
+ SetCountdown();
+ ExpectNoThrow([¬hrow_ctor]() {
+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);
+ });
+ UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, NonThrowingCopyAssign) {
+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;
+
+ SetCountdown();
+ ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {
+ nothrow_assign1 = nothrow_assign2;
+ });
+ UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, ThrowingSwap) {
ThrowingValue<> bomb1, bomb2;
TestOp([&]() { std::swap(bomb1, bomb2); });
-
- ThrowingValue<NoThrow::kMoveCtor> bomb3, bomb4;
- TestOp([&]() { std::swap(bomb3, bomb4); });
-
- ThrowingValue<NoThrow::kMoveAssign> bomb5, bomb6;
- TestOp([&]() { std::swap(bomb5, bomb6); });
}
-TEST_F(ThrowingValueTest, NonThrowingSwap) {
- ThrowingValue<NoThrow::kMoveAssign | NoThrow::kMoveCtor> bomb1, bomb2;
+TEST(ThrowingValueTest, NonThrowingSwap) {
+ ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;
ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
}
-TEST_F(ThrowingValueTest, NonThrowingAllocation) {
- ThrowingValue<NoThrow::kAllocation>* allocated;
- ThrowingValue<NoThrow::kAllocation>* array;
+TEST(ThrowingValueTest, NonThrowingAllocation) {
+ ThrowingValue<TypeSpec::kNoThrowNew>* allocated;
+ ThrowingValue<TypeSpec::kNoThrowNew>* array;
ExpectNoThrow([&allocated]() {
- allocated = new ThrowingValue<NoThrow::kAllocation>(1);
+ allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);
delete allocated;
});
ExpectNoThrow([&array]() {
- array = new ThrowingValue<NoThrow::kAllocation>[2];
+ array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];
delete[] array;
});
}
-TEST_F(ThrowingValueTest, NonThrowingDelete) {
+TEST(ThrowingValueTest, NonThrowingDelete) {
auto* allocated = new ThrowingValue<>(1);
auto* array = new ThrowingValue<>[2];
@@ -229,12 +272,14 @@
ExpectNoThrow([allocated]() { delete allocated; });
SetCountdown();
ExpectNoThrow([array]() { delete[] array; });
+
+ UnsetCountdown();
}
using Storage =
absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
-TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) {
+TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
constexpr int kArrayLen = 2;
// We intentionally create extra space to store the tag allocated by placement
// new[].
@@ -256,16 +301,19 @@
for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
ThrowingValue<>::operator delete[](placed_array, &array_buf);
});
+
+ UnsetCountdown();
}
-TEST_F(ThrowingValueTest, NonThrowingDestructor) {
+TEST(ThrowingValueTest, NonThrowingDestructor) {
auto* allocated = new ThrowingValue<>();
+
SetCountdown();
ExpectNoThrow([allocated]() { delete allocated; });
+ UnsetCountdown();
}
TEST(ThrowingBoolTest, ThrowingBool) {
- UnsetCountdown();
ThrowingBool t = true;
// Test that it's contextually convertible to bool
@@ -276,15 +324,7 @@
TestOp([&]() { (void)!t; });
}
-class ThrowingAllocatorTest : public ::testing::Test {
- protected:
- void SetUp() override { UnsetCountdown(); }
-
- private:
- ConstructorTracker borlu_;
-};
-
-TEST_F(ThrowingAllocatorTest, MemoryManagement) {
+TEST(ThrowingAllocatorTest, MemoryManagement) {
// Just exercise the memory management capabilities under LSan to make sure we
// don't leak.
ThrowingAllocator<int> int_alloc;
@@ -293,24 +333,26 @@
int* i_array = int_alloc.allocate(2);
int_alloc.deallocate(i_array, 2);
- ThrowingAllocator<ThrowingValue<>> ef_alloc;
- ThrowingValue<>* efp = ef_alloc.allocate(1);
- ef_alloc.deallocate(efp, 1);
- ThrowingValue<>* ef_array = ef_alloc.allocate(2);
- ef_alloc.deallocate(ef_array, 2);
+ ThrowingAllocator<ThrowingValue<>> tv_alloc;
+ ThrowingValue<>* ptr = tv_alloc.allocate(1);
+ tv_alloc.deallocate(ptr, 1);
+ ThrowingValue<>* tv_array = tv_alloc.allocate(2);
+ tv_alloc.deallocate(tv_array, 2);
}
-TEST_F(ThrowingAllocatorTest, CallsGlobalNew) {
- ThrowingAllocator<ThrowingValue<>, NoThrow::kNoThrow> nothrow_alloc;
+TEST(ThrowingAllocatorTest, CallsGlobalNew) {
+ ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;
ThrowingValue<>* ptr;
SetCountdown();
// This will only throw if ThrowingValue::new is called.
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
nothrow_alloc.deallocate(ptr, 1);
+
+ UnsetCountdown();
}
-TEST_F(ThrowingAllocatorTest, ThrowingConstructors) {
+TEST(ThrowingAllocatorTest, ThrowingConstructors) {
ThrowingAllocator<int> int_alloc;
int* ip = nullptr;
@@ -323,22 +365,27 @@
EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
EXPECT_EQ(*ip, 1);
int_alloc.deallocate(ip, 1);
+
+ UnsetCountdown();
}
-TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) {
+TEST(ThrowingAllocatorTest, NonThrowingConstruction) {
{
- ThrowingAllocator<int, NoThrow::kNoThrow> int_alloc;
+ ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;
int* ip = nullptr;
SetCountdown();
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
+
SetCountdown();
ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
+
EXPECT_EQ(*ip, 2);
int_alloc.deallocate(ip, 1);
+
+ UnsetCountdown();
}
- UnsetCountdown();
{
ThrowingAllocator<int> int_alloc;
int* ip = nullptr;
@@ -348,37 +395,45 @@
int_alloc.deallocate(ip, 1);
}
- UnsetCountdown();
{
- ThrowingAllocator<ThrowingValue<NoThrow::kIntCtor>, NoThrow::kNoThrow>
- ef_alloc;
- ThrowingValue<NoThrow::kIntCtor>* efp;
+ ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>
+ nothrow_alloc;
+ ThrowingValue<>* ptr;
+
SetCountdown();
- ExpectNoThrow([&]() { efp = ef_alloc.allocate(1); });
+ ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
+
SetCountdown();
- ExpectNoThrow([&]() { ef_alloc.construct(efp, 2); });
- EXPECT_EQ(efp->Get(), 2);
- ef_alloc.destroy(efp);
- ef_alloc.deallocate(efp, 1);
+ ExpectNoThrow(
+ [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });
+
+ EXPECT_EQ(ptr->Get(), 2);
+ nothrow_alloc.destroy(ptr);
+ nothrow_alloc.deallocate(ptr, 1);
+
+ UnsetCountdown();
}
- UnsetCountdown();
{
ThrowingAllocator<int> a;
+
SetCountdown();
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
+
SetCountdown();
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
+
+ UnsetCountdown();
}
}
-TEST_F(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
+TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
ThrowingAllocator<int> a;
TestOp([]() { ThrowingAllocator<int> a; });
TestOp([&]() { a.select_on_container_copy_construction(); });
}
-TEST_F(ThrowingAllocatorTest, State) {
+TEST(ThrowingAllocatorTest, State) {
ThrowingAllocator<int> a1, a2;
EXPECT_NE(a1, a2);
@@ -390,13 +445,13 @@
EXPECT_EQ(a3, a1);
}
-TEST_F(ThrowingAllocatorTest, InVector) {
+TEST(ThrowingAllocatorTest, InVector) {
std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
for (int i = 0; i < 20; ++i) v.push_back({});
for (int i = 0; i < 20; ++i) v.pop_back();
}
-TEST_F(ThrowingAllocatorTest, InList) {
+TEST(ThrowingAllocatorTest, InList) {
std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
for (int i = 0; i < 20; ++i) l.push_back({});
for (int i = 0; i < 20; ++i) l.pop_back();
@@ -443,15 +498,15 @@
// Test that providing operation and inveriants still does not allow for the
// the invocation of .Test() and .Test(op) because it lacks a factory
auto without_fac =
- absl::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
- inv, absl::strong_guarantee);
+ testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
+ inv, testing::strong_guarantee);
EXPECT_FALSE(HasNullaryTest(without_fac));
EXPECT_FALSE(HasUnaryTest(without_fac));
// Test that providing invariants and factory allows the invocation of
// .Test(op) but does not allow for .Test() because it lacks an operation
- auto without_op = absl::MakeExceptionSafetyTester()
- .WithInvariants(inv, absl::strong_guarantee)
+ auto without_op = testing::MakeExceptionSafetyTester()
+ .WithInvariants(inv, testing::strong_guarantee)
.WithFactory(fac);
EXPECT_FALSE(HasNullaryTest(without_op));
EXPECT_TRUE(HasUnaryTest(without_op));
@@ -459,7 +514,7 @@
// Test that providing operation and factory still does not allow for the
// the invocation of .Test() and .Test(op) because it lacks invariants
auto without_inv =
- absl::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
+ testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
EXPECT_FALSE(HasNullaryTest(without_inv));
EXPECT_FALSE(HasUnaryTest(without_inv));
}
@@ -504,28 +559,28 @@
// lambdas can all be used with ExceptionSafetyTester
TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
// function reference
- EXPECT_TRUE(absl::MakeExceptionSafetyTester()
+ EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(ExampleFunctionFactory)
.WithOperation(ExampleFunctionOperation)
.WithInvariants(ExampleFunctionInvariant)
.Test());
// function pointer
- EXPECT_TRUE(absl::MakeExceptionSafetyTester()
+ EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(&ExampleFunctionFactory)
.WithOperation(&ExampleFunctionOperation)
.WithInvariants(&ExampleFunctionInvariant)
.Test());
// struct
- EXPECT_TRUE(absl::MakeExceptionSafetyTester()
+ EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(example_struct_factory)
.WithOperation(example_struct_operation)
.WithInvariants(example_struct_invariant)
.Test());
// lambda
- EXPECT_TRUE(absl::MakeExceptionSafetyTester()
+ EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(example_lambda_factory)
.WithOperation(example_lambda_operation)
.WithInvariants(example_lambda_invariant)
@@ -553,9 +608,9 @@
} invoker;
auto tester =
- absl::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
+ testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
CheckNonNegativeInvariants);
-auto strong_tester = tester.WithInvariants(absl::strong_guarantee);
+auto strong_tester = tester.WithInvariants(testing::strong_guarantee);
struct FailsBasicGuarantee : public NonNegative {
void operator()() {
@@ -659,7 +714,7 @@
EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
.WithInvariants(increment)
.Test());
- EXPECT_TRUE(absl::MakeExceptionSafetyTester()
+ EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithInitialValue(HasReset{})
.WithInvariants(CheckHasResetInvariants)
.Test(invoker));
@@ -734,7 +789,7 @@
unsigned char ExhaustivenessTester<T>::successes = 0;
TEST(ExceptionCheckTest, Exhaustiveness) {
- auto exhaust_tester = absl::MakeExceptionSafetyTester()
+ auto exhaust_tester = testing::MakeExceptionSafetyTester()
.WithInvariants(CheckExhaustivenessTesterInvariants)
.WithOperation(invoker);
@@ -744,7 +799,7 @@
EXPECT_TRUE(
exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
- .WithInvariants(absl::strong_guarantee)
+ .WithInvariants(testing::strong_guarantee)
.Test());
EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
}
@@ -763,7 +818,7 @@
int LeaksIfCtorThrows::counter = 0;
TEST(ExceptionCheckTest, TestLeakyCtor) {
- absl::TestThrowingCtor<LeaksIfCtorThrows>();
+ testing::TestThrowingCtor<LeaksIfCtorThrows>();
EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
LeaksIfCtorThrows::counter = 0;
}
@@ -772,19 +827,28 @@
Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
};
-TEST(ConstructorTrackerTest, Pass) {
- ConstructorTracker javert;
- Tracked t;
+TEST(ConstructorTrackerTest, CreatedBefore) {
+ Tracked a, b, c;
+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
}
-TEST(ConstructorTrackerTest, NotDestroyed) {
+TEST(ConstructorTrackerTest, CreatedAfter) {
+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+ Tracked a, b, c;
+}
+
+TEST(ConstructorTrackerTest, NotDestroyedAfter) {
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
EXPECT_NONFATAL_FAILURE(
{
- ConstructorTracker gadget;
+ exceptions_internal::ConstructorTracker ct(
+ exceptions_internal::countdown);
new (&storage) Tracked;
},
"not destroyed");
+
+ // Manual destruction of the Tracked instance is not required because
+ // ~ConstructorTracker() handles that automatically when a leak is found
}
TEST(ConstructorTrackerTest, DestroyedTwice) {
@@ -825,4 +889,5 @@
}
} // namespace
-} // namespace absl
+
+} // namespace testing
diff --git a/third_party/abseil-cpp/absl/base/internal/atomic_hook.h b/third_party/abseil-cpp/absl/base/internal/atomic_hook.h
index 47d4013..b458511 100644
--- a/third_party/abseil-cpp/absl/base/internal/atomic_hook.h
+++ b/third_party/abseil-cpp/absl/base/internal/atomic_hook.h
@@ -21,6 +21,12 @@
#include <cstdint>
#include <utility>
+#ifdef _MSC_FULL_VER
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
+#else
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
+#endif
+
namespace absl {
namespace base_internal {
@@ -29,9 +35,15 @@
// AtomicHook is a helper class, templatized on a raw function pointer type, for
// implementing Abseil customization hooks. It is a callable object that
-// dispatches to the registered hook, or performs a no-op (and returns a default
+// dispatches to the registered hook.
+//
+// A default constructed object performs a no-op (and returns a default
// constructed object) if no hook has been registered.
//
+// Hooks can be pre-registered via constant initialization, for example,
+// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
+// and then changed at runtime via a call to Store().
+//
// Reads and writes guarantee memory_order_acquire/memory_order_release
// semantics.
template <typename ReturnType, typename... Args>
@@ -39,7 +51,19 @@
public:
using FnPtr = ReturnType (*)(Args...);
- constexpr AtomicHook() : hook_(kInitialValue) {}
+ // Constructs an object that by default performs a no-op (and
+ // returns a default constructed object) when no hook as been registered.
+ constexpr AtomicHook() : AtomicHook(DummyFunction) {}
+
+ // Constructs an object that by default dispatches to/returns the
+ // pre-registered default_fn when no hook has been registered at runtime.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+ explicit constexpr AtomicHook(FnPtr default_fn)
+ : hook_(default_fn), default_fn_(default_fn) {}
+#else
+ explicit constexpr AtomicHook(FnPtr default_fn)
+ : hook_(kUninitialized), default_fn_(default_fn) {}
+#endif
// Stores the provided function pointer as the value for this hook.
//
@@ -86,16 +110,7 @@
//
// This causes an issue when building with LLVM under Windows. To avoid this,
// we use a less-efficient, intptr_t-based implementation on Windows.
-
-#ifdef _MSC_FULL_VER
-#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
-#else
-#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
-#endif
-
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
- static constexpr FnPtr kInitialValue = &DummyFunction;
-
// Return the stored value, or DummyFunction if no value has been stored.
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
@@ -103,10 +118,9 @@
// stored to this object.
bool DoStore(FnPtr fn) {
assert(fn);
- FnPtr expected = DummyFunction;
- hook_.compare_exchange_strong(expected, fn, std::memory_order_acq_rel,
- std::memory_order_acquire);
- const bool store_succeeded = (expected == DummyFunction);
+ FnPtr expected = default_fn_;
+ const bool store_succeeded = hook_.compare_exchange_strong(
+ expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == fn);
return store_succeeded || same_value_already_stored;
}
@@ -114,15 +128,15 @@
std::atomic<FnPtr> hook_;
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
// Use a sentinel value unlikely to be the address of an actual function.
- static constexpr intptr_t kInitialValue = 0;
+ static constexpr intptr_t kUninitialized = 0;
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
"intptr_t can't contain a function pointer");
FnPtr DoLoad() const {
const intptr_t value = hook_.load(std::memory_order_acquire);
- if (value == 0) {
- return DummyFunction;
+ if (value == kUninitialized) {
+ return default_fn_;
}
return reinterpret_cast<FnPtr>(value);
}
@@ -130,16 +144,17 @@
bool DoStore(FnPtr fn) {
assert(fn);
const auto value = reinterpret_cast<intptr_t>(fn);
- intptr_t expected = 0;
- hook_.compare_exchange_strong(expected, value, std::memory_order_acq_rel,
- std::memory_order_acquire);
- const bool store_succeeded = (expected == 0);
+ intptr_t expected = kUninitialized;
+ const bool store_succeeded = hook_.compare_exchange_strong(
+ expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == value);
return store_succeeded || same_value_already_stored;
}
std::atomic<intptr_t> hook_;
#endif
+
+ const FnPtr default_fn_;
};
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
diff --git a/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc b/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc
new file mode 100644
index 0000000..cf74075
--- /dev/null
+++ b/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/atomic_hook.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+
+namespace {
+
+int value = 0;
+void TestHook(int x) { value = x; }
+
+TEST(AtomicHookTest, NoDefaultFunction) {
+ ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
+ value = 0;
+
+ // Test the default DummyFunction.
+ EXPECT_TRUE(hook.Load() == nullptr);
+ EXPECT_EQ(value, 0);
+ hook(1);
+ EXPECT_EQ(value, 0);
+
+ // Test a stored hook.
+ hook.Store(TestHook);
+ EXPECT_TRUE(hook.Load() == TestHook);
+ EXPECT_EQ(value, 0);
+ hook(1);
+ EXPECT_EQ(value, 1);
+
+ // Calling Store() with the same hook should not crash.
+ hook.Store(TestHook);
+ EXPECT_TRUE(hook.Load() == TestHook);
+ EXPECT_EQ(value, 1);
+ hook(2);
+ EXPECT_EQ(value, 2);
+}
+
+TEST(AtomicHookTest, WithDefaultFunction) {
+ // Set the default value to TestHook at compile-time.
+ ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
+ TestHook);
+ value = 0;
+
+ // Test the default value is TestHook.
+ EXPECT_TRUE(hook.Load() == TestHook);
+ EXPECT_EQ(value, 0);
+ hook(1);
+ EXPECT_EQ(value, 1);
+
+ // Calling Store() with the same hook should not crash.
+ hook.Store(TestHook);
+ EXPECT_TRUE(hook.Load() == TestHook);
+ EXPECT_EQ(value, 1);
+ hook(2);
+ EXPECT_EQ(value, 2);
+}
+
+} // namespace
diff --git a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
index 4bd273e..2fe345f 100644
--- a/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
+++ b/third_party/abseil-cpp/absl/base/internal/direct_mmap.h
@@ -52,7 +52,7 @@
// SYS_mmap and SYS_munmap are not defined in Android.
#ifdef __BIONIC__
-extern "C" void* __mmap2(void*, size_t, int, int, int, long);
+extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#if defined(__NR_mmap) && !defined(SYS_mmap)
#define SYS_mmap __NR_mmap
#endif
diff --git a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc
index c6f7c7c..d3e9407 100644
--- a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc
+++ b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc
@@ -17,9 +17,14 @@
#include "gtest/gtest.h"
#include "absl/meta/type_traits.h"
-namespace absl {
+namespace testing {
-exceptions_internal::NoThrowTag no_throw_ctor;
+exceptions_internal::NoThrowTag nothrow_ctor;
+
+bool nothrow_guarantee(const void*) {
+ return ::testing::AssertionFailure()
+ << "Exception thrown violating NoThrow Guarantee";
+}
exceptions_internal::StrongGuaranteeTagType strong_guarantee;
namespace exceptions_internal {
@@ -37,5 +42,7 @@
int countdown) noexcept {
return testing::AssertionFailure() << "Exception thrown from " << e.what();
}
+
} // namespace exceptions_internal
-} // namespace absl
+
+} // namespace testing
diff --git a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h
index 48a292b..c3ff34c 100644
--- a/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h
+++ b/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h
@@ -35,40 +35,36 @@
#include "absl/strings/substitute.h"
#include "absl/types/optional.h"
-namespace absl {
+namespace testing {
-struct ConstructorTracker;
+enum class TypeSpec;
+enum class AllocSpec;
-// A configuration enum for Throwing*. Operations whose flags are set will
-// throw, everything else won't. This isn't meant to be exhaustive, more flags
-// can always be made in the future.
-enum class NoThrow : uint8_t {
- kNone = 0,
- kMoveCtor = 1,
- kMoveAssign = 1 << 1,
- kAllocation = 1 << 2,
- kIntCtor = 1 << 3,
- kNoThrow = static_cast<uint8_t>(-1)
-};
-
-constexpr NoThrow operator|(NoThrow a, NoThrow b) {
- using T = absl::underlying_type_t<NoThrow>;
- return static_cast<NoThrow>(static_cast<T>(a) | static_cast<T>(b));
+constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
+ using T = absl::underlying_type_t<TypeSpec>;
+ return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
}
-constexpr NoThrow operator&(NoThrow a, NoThrow b) {
- using T = absl::underlying_type_t<NoThrow>;
- return static_cast<NoThrow>(static_cast<T>(a) & static_cast<T>(b));
+constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
+ using T = absl::underlying_type_t<TypeSpec>;
+ return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
+}
+
+constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
+ using T = absl::underlying_type_t<AllocSpec>;
+ return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
+}
+
+constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
+ using T = absl::underlying_type_t<AllocSpec>;
+ return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
}
namespace exceptions_internal {
+
struct NoThrowTag {};
struct StrongGuaranteeTagType {};
-constexpr bool ThrowingAllowed(NoThrow flags, NoThrow flag) {
- return !static_cast<bool>(flags & flag);
-}
-
// A simple exception class. We throw this so that test code can catch
// exceptions specifically thrown by ThrowingValue.
class TestException {
@@ -105,6 +101,8 @@
testing::AssertionResult FailureMessage(const TestException& e,
int countdown) noexcept;
+class ConstructorTracker;
+
class TrackedObject {
public:
TrackedObject(const TrackedObject&) = delete;
@@ -112,31 +110,61 @@
protected:
explicit TrackedObject(const char* child_ctor) {
- if (!GetAllocs().emplace(this, child_ctor).second) {
+ if (!GetInstanceMap().emplace(this, child_ctor).second) {
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
<< " re-constructed in ctor " << child_ctor;
}
}
- static std::unordered_map<TrackedObject*, absl::string_view>& GetAllocs() {
- static auto* m =
- new std::unordered_map<TrackedObject*, absl::string_view>();
- return *m;
- }
-
~TrackedObject() noexcept {
- if (GetAllocs().erase(this) == 0) {
+ if (GetInstanceMap().erase(this) == 0) {
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
<< " destroyed improperly";
}
}
- friend struct ::absl::ConstructorTracker;
+ private:
+ using InstanceMap = std::unordered_map<TrackedObject*, absl::string_view>;
+ static InstanceMap& GetInstanceMap() {
+ static auto* instance_map = new InstanceMap();
+ return *instance_map;
+ }
+
+ friend class ConstructorTracker;
+};
+
+// Inspects the constructions and destructions of anything inheriting from
+// TrackedObject. This allows us to safely "leak" TrackedObjects, as
+// ConstructorTracker will destroy everything left over in its destructor.
+class ConstructorTracker {
+ public:
+ explicit ConstructorTracker(int c)
+ : init_count_(c), init_instances_(TrackedObject::GetInstanceMap()) {}
+ ~ConstructorTracker() {
+ auto& cur_instances = TrackedObject::GetInstanceMap();
+ for (auto it = cur_instances.begin(); it != cur_instances.end();) {
+ if (init_instances_.count(it->first) == 0) {
+ ADD_FAILURE() << "Object at address " << static_cast<void*>(it->first)
+ << " constructed from " << it->second
+ << " where the exception countdown was set to "
+ << init_count_ << " was not destroyed";
+ // Erasing an item inside an unordered_map invalidates the existing
+ // iterator. A new one is returned for iteration to continue.
+ it = cur_instances.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ private:
+ int init_count_;
+ TrackedObject::InstanceMap init_instances_;
};
template <typename Factory, typename Operation, typename Invariant>
absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
- const Factory& factory, const Operation& operation, int count,
+ const Factory& factory, Operation operation, int count,
const Invariant& invariant) {
auto t_ptr = factory();
absl::optional<testing::AssertionResult> current_res;
@@ -199,7 +227,9 @@
} // namespace exceptions_internal
-extern exceptions_internal::NoThrowTag no_throw_ctor;
+extern exceptions_internal::NoThrowTag nothrow_ctor;
+
+bool nothrow_guarantee(const void*);
extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
// A test class which is convertible to bool. The conversion can be
@@ -216,47 +246,71 @@
bool b_;
};
-// A testing class instrumented to throw an exception at a controlled time.
-//
-// ThrowingValue implements a slightly relaxed version of the Regular concept --
-// that is it's a value type with the expected semantics. It also implements
-// arithmetic operations. It doesn't implement member and pointer operators
-// like operator-> or operator[].
-//
-// ThrowingValue can be instrumented to have certain operations be noexcept by
-// using compile-time bitfield flag template arguments. That is, to make an
-// ThrowingValue which has a noexcept move constructor and noexcept move
-// assignment, use
-// ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign>.
-template <NoThrow Flags = NoThrow::kNone>
+/*
+ * Configuration enum for the ThrowingValue type that defines behavior for the
+ * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer
+ * constructor from throwing.
+ *
+ * kEverythingThrows: Every operation can throw an exception
+ * kNoThrowCopy: Copy construction and copy assignment will not throw
+ * kNoThrowMove: Move construction and move assignment will not throw
+ * kNoThrowNew: Overloaded operators new and new[] will not throw
+ */
+enum class TypeSpec {
+ kEverythingThrows = 0,
+ kNoThrowCopy = 1,
+ kNoThrowMove = 1 << 1,
+ kNoThrowNew = 1 << 2,
+};
+
+/*
+ * A testing class instrumented to throw an exception at a controlled time.
+ *
+ * ThrowingValue implements a slightly relaxed version of the Regular concept --
+ * that is it's a value type with the expected semantics. It also implements
+ * arithmetic operations. It doesn't implement member and pointer operators
+ * like operator-> or operator[].
+ *
+ * ThrowingValue can be instrumented to have certain operations be noexcept by
+ * using compile-time bitfield template arguments. That is, to make an
+ * ThrowingValue which has noexcept move construction/assignment and noexcept
+ * copy construction/assignment, use the following:
+ * ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val};
+ */
+template <TypeSpec Spec = TypeSpec::kEverythingThrows>
class ThrowingValue : private exceptions_internal::TrackedObject {
+ static constexpr bool IsSpecified(TypeSpec spec) {
+ return static_cast<bool>(Spec & spec);
+ }
+
+ static constexpr int kBadValue = 938550620;
+
public:
ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
dummy_ = 0;
}
- ThrowingValue(const ThrowingValue& other)
+ ThrowingValue(const ThrowingValue& other) noexcept(
+ IsSpecified(TypeSpec::kNoThrowCopy))
: TrackedObject(ABSL_PRETTY_FUNCTION) {
- exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+ if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+ }
dummy_ = other.dummy_;
}
ThrowingValue(ThrowingValue&& other) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor))
+ IsSpecified(TypeSpec::kNoThrowMove))
: TrackedObject(ABSL_PRETTY_FUNCTION) {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) {
+ if (!IsSpecified(TypeSpec::kNoThrowMove)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
}
dummy_ = other.dummy_;
}
- explicit ThrowingValue(int i) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor))
- : TrackedObject(ABSL_PRETTY_FUNCTION) {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) {
- exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- }
+ explicit ThrowingValue(int i) : TrackedObject(ABSL_PRETTY_FUNCTION) {
+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
dummy_ = i;
}
@@ -266,15 +320,20 @@
// absl expects nothrow destructors
~ThrowingValue() noexcept = default;
- ThrowingValue& operator=(const ThrowingValue& other) {
- exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+ ThrowingValue& operator=(const ThrowingValue& other) noexcept(
+ IsSpecified(TypeSpec::kNoThrowCopy)) {
+ dummy_ = kBadValue;
+ if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+ }
dummy_ = other.dummy_;
return *this;
}
ThrowingValue& operator=(ThrowingValue&& other) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) {
+ IsSpecified(TypeSpec::kNoThrowMove)) {
+ dummy_ = kBadValue;
+ if (!IsSpecified(TypeSpec::kNoThrowMove)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
}
dummy_ = other.dummy_;
@@ -284,22 +343,22 @@
// Arithmetic Operators
ThrowingValue operator+(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ + other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
}
ThrowingValue operator+() const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_, nothrow_ctor);
}
ThrowingValue operator-(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ - other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
}
ThrowingValue operator-() const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(-dummy_, no_throw_ctor);
+ return ThrowingValue(-dummy_, nothrow_ctor);
}
ThrowingValue& operator++() {
@@ -310,7 +369,7 @@
ThrowingValue operator++(int) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- auto out = ThrowingValue(dummy_, no_throw_ctor);
+ auto out = ThrowingValue(dummy_, nothrow_ctor);
++dummy_;
return out;
}
@@ -323,34 +382,34 @@
ThrowingValue operator--(int) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- auto out = ThrowingValue(dummy_, no_throw_ctor);
+ auto out = ThrowingValue(dummy_, nothrow_ctor);
--dummy_;
return out;
}
ThrowingValue operator*(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ * other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
}
ThrowingValue operator/(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ / other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
}
ThrowingValue operator%(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ % other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
}
ThrowingValue operator<<(int shift) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ << shift, no_throw_ctor);
+ return ThrowingValue(dummy_ << shift, nothrow_ctor);
}
ThrowingValue operator>>(int shift) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ >> shift, no_throw_ctor);
+ return ThrowingValue(dummy_ >> shift, nothrow_ctor);
}
// Comparison Operators
@@ -406,22 +465,22 @@
// Bitwise Logical Operators
ThrowingValue operator~() const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(~dummy_, no_throw_ctor);
+ return ThrowingValue(~dummy_, nothrow_ctor);
}
ThrowingValue operator&(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ & other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
}
ThrowingValue operator|(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ | other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
}
ThrowingValue operator^(const ThrowingValue& other) const {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
- return ThrowingValue(dummy_ ^ other.dummy_, no_throw_ctor);
+ return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
}
// Compound Assignment operators
@@ -503,8 +562,8 @@
// Args.. allows us to overload regular and placement new in one shot
template <typename... Args>
static void* operator new(size_t s, Args&&... args) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
+ IsSpecified(TypeSpec::kNoThrowNew)) {
+ if (!IsSpecified(TypeSpec::kNoThrowNew)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
}
return ::operator new(s, std::forward<Args>(args)...);
@@ -512,8 +571,8 @@
template <typename... Args>
static void* operator new[](size_t s, Args&&... args) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
+ IsSpecified(TypeSpec::kNoThrowNew)) {
+ if (!IsSpecified(TypeSpec::kNoThrowNew)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
}
return ::operator new[](s, std::forward<Args>(args)...);
@@ -551,20 +610,35 @@
};
// While not having to do with exceptions, explicitly delete comma operator, to
// make sure we don't use it on user-supplied types.
-template <NoThrow N, typename T>
-void operator,(const ThrowingValue<N>& ef, T&& t) = delete;
-template <NoThrow N, typename T>
-void operator,(T&& t, const ThrowingValue<N>& ef) = delete;
+template <TypeSpec Spec, typename T>
+void operator,(const ThrowingValue<Spec>&, T&&) = delete;
+template <TypeSpec Spec, typename T>
+void operator,(T&&, const ThrowingValue<Spec>&) = delete;
-// An allocator type which is instrumented to throw at a controlled time, or not
-// to throw, using NoThrow. The supported settings are the default of every
-// function which is allowed to throw in a conforming allocator possibly
-// throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
-// configuration macro.
-template <typename T, NoThrow Flags = NoThrow::kNone>
+/*
+ * Configuration enum for the ThrowingAllocator type that defines behavior for
+ * the lifetime of the instance.
+ *
+ * kEverythingThrows: Calls to the member functions may throw
+ * kNoThrowAllocate: Calls to the member functions will not throw
+ */
+enum class AllocSpec {
+ kEverythingThrows = 0,
+ kNoThrowAllocate = 1,
+};
+
+/*
+ * An allocator type which is instrumented to throw at a controlled time, or not
+ * to throw, using AllocSpec. The supported settings are the default of every
+ * function which is allowed to throw in a conforming allocator possibly
+ * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
+ * configuration macro.
+ */
+template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
class ThrowingAllocator : private exceptions_internal::TrackedObject {
- static_assert(Flags == NoThrow::kNone || Flags == NoThrow::kNoThrow,
- "Invalid flag");
+ static constexpr bool IsSpecified(AllocSpec spec) {
+ return static_cast<bool>(Spec & spec);
+ }
public:
using pointer = T*;
@@ -577,7 +651,8 @@
using size_type = size_t;
using difference_type = ptrdiff_t;
- using is_nothrow = std::integral_constant<bool, Flags == NoThrow::kNoThrow>;
+ using is_nothrow =
+ std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
@@ -589,8 +664,7 @@
}
template <typename U>
- ThrowingAllocator( // NOLINT
- const ThrowingAllocator<U, Flags>& other) noexcept
+ ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept // NOLINT
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
// According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
@@ -599,8 +673,7 @@
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
template <typename U>
- ThrowingAllocator( // NOLINT
- ThrowingAllocator<U, Flags>&& other) noexcept
+ ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept // NOLINT
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {}
ThrowingAllocator(ThrowingAllocator&& other) noexcept
@@ -615,29 +688,30 @@
template <typename U>
ThrowingAllocator& operator=(
- const ThrowingAllocator<U, Flags>& other) noexcept {
+ const ThrowingAllocator<U, Spec>& other) noexcept {
dummy_ = other.State();
return *this;
}
template <typename U>
- ThrowingAllocator& operator=(ThrowingAllocator<U, Flags>&& other) noexcept {
+ ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
dummy_ = std::move(other.State());
return *this;
}
template <typename U>
struct rebind {
- using other = ThrowingAllocator<U, Flags>;
+ using other = ThrowingAllocator<U, Spec>;
};
pointer allocate(size_type n) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
+ IsSpecified(AllocSpec::kNoThrowAllocate)) {
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
return static_cast<pointer>(::operator new(n * sizeof(T)));
}
+
pointer allocate(size_type n, const_void_pointer) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
+ IsSpecified(AllocSpec::kNoThrowAllocate)) {
return allocate(n);
}
@@ -648,7 +722,7 @@
template <typename U, typename... Args>
void construct(U* ptr, Args&&... args) noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
+ IsSpecified(AllocSpec::kNoThrowAllocate)) {
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
}
@@ -664,23 +738,23 @@
}
ThrowingAllocator select_on_container_copy_construction() noexcept(
- !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
+ IsSpecified(AllocSpec::kNoThrowAllocate)) {
auto& out = *this;
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
return out;
}
template <typename U>
- bool operator==(const ThrowingAllocator<U, Flags>& other) const noexcept {
+ bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
return dummy_ == other.dummy_;
}
template <typename U>
- bool operator!=(const ThrowingAllocator<U, Flags>& other) const noexcept {
+ bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
return dummy_ != other.dummy_;
}
- template <typename U, NoThrow B>
+ template <typename, AllocSpec>
friend class ThrowingAllocator;
private:
@@ -694,7 +768,7 @@
}
void ReadStateAndMaybeThrow(absl::string_view msg) const {
- if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
+ if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
exceptions_internal::MaybeThrow(
absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
}
@@ -704,40 +778,24 @@
std::shared_ptr<const int> dummy_;
};
-template <typename T, NoThrow Throws>
-int ThrowingAllocator<T, Throws>::next_id_ = 0;
-
-// Inspects the constructions and destructions of anything inheriting from
-// TrackedObject. Place this as a member variable in a test fixture to ensure
-// that every ThrowingValue was constructed and destroyed correctly. This also
-// allows us to safely "leak" TrackedObjects, as ConstructorTracker will destroy
-// everything left over in its destructor.
-struct ConstructorTracker {
- ConstructorTracker() = default;
- ~ConstructorTracker() {
- auto& allocs = exceptions_internal::TrackedObject::GetAllocs();
- for (const auto& kv : allocs) {
- ADD_FAILURE() << "Object at address " << static_cast<void*>(kv.first)
- << " constructed from " << kv.second << " not destroyed";
- }
- allocs.clear();
- }
-};
+template <typename T, AllocSpec Spec>
+int ThrowingAllocator<T, Spec>::next_id_ = 0;
// Tests for resource leaks by attempting to construct a T using args repeatedly
// until successful, using the countdown method. Side effects can then be
-// tested for resource leaks. If a ConstructorTracker is present in the test
-// fixture, then this will also test that memory resources are not leaked as
-// long as T allocates TrackedObjects.
+// tested for resource leaks.
template <typename T, typename... Args>
-T TestThrowingCtor(Args&&... args) {
+void TestThrowingCtor(Args&&... args) {
struct Cleanup {
~Cleanup() { exceptions_internal::UnsetCountdown(); }
} c;
for (int count = 0;; ++count) {
+ exceptions_internal::ConstructorTracker ct(count);
exceptions_internal::SetCountdown(count);
try {
- return T(std::forward<Args>(args)...);
+ T temp(std::forward<Args>(args)...);
+ static_cast<void>(temp);
+ break;
} catch (const exceptions_internal::TestException&) {
}
}
@@ -859,7 +917,7 @@
* created in order to get an empty Invariants... list.
*
* In addition to passing in custom invariant assertion callbacks, this method
- * accepts `absl::strong_guarantee` as an argument which checks T instances
+ * accepts `testing::strong_guarantee` as an argument which checks T instances
* post-throw against freshly created T instances via operator== to verify
* that any state changes made during the execution of the operation were
* properly rolled back.
@@ -920,7 +978,7 @@
template <typename, typename, typename...>
friend class ExceptionSafetyTester;
- friend ExceptionSafetyTester<> absl::MakeExceptionSafetyTester();
+ friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester();
ExceptionSafetyTester() {}
@@ -934,6 +992,8 @@
// Starting from 0 and counting upwards until one of the exit conditions is
// hit...
for (int count = 0;; ++count) {
+ exceptions_internal::ConstructorTracker ct(count);
+
// Run the full exception safety test algorithm for the current countdown
auto reduced_res =
TestAllInvariantsAtCountdown(factory_, selected_operation, count,
@@ -976,6 +1036,6 @@
return {};
}
-} // namespace absl
+} // namespace testing
#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
diff --git a/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc b/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc
new file mode 100644
index 0000000..fe22e4cf
--- /dev/null
+++ b/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+namespace {
+
+void BM_SafeCurrentThreadIdentity(benchmark::State& state) {
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(
+ absl::synchronization_internal::GetOrCreateCurrentThreadIdentity());
+ }
+}
+BENCHMARK(BM_SafeCurrentThreadIdentity);
+
+void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) {
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(
+ absl::base_internal::CurrentThreadIdentityIfPresent());
+ }
+}
+BENCHMARK(BM_UnsafeCurrentThreadIdentity);
+
+} // namespace
+
+BENCHMARK_MAIN();
diff --git a/third_party/abseil-cpp/absl/base/macros.h b/third_party/abseil-cpp/absl/base/macros.h
index 114a7be..afa3030 100644
--- a/third_party/abseil-cpp/absl/base/macros.h
+++ b/third_party/abseil-cpp/absl/base/macros.h
@@ -36,21 +36,20 @@
// ABSL_ARRAYSIZE()
//
-// Returns the # of elements in an array as a compile-time constant, which can
-// be used in defining new arrays. If you use this macro on a pointer by
+// Returns the number of elements in an array as a compile-time constant, which
+// can be used in defining new arrays. If you use this macro on a pointer by
// mistake, you will get a compile-time error.
-//
-// Note: this template function declaration is used in defining arraysize.
-// Note that the function doesn't need an implementation, as we only
-// use its type.
+#define ABSL_ARRAYSIZE(array) \
+ (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
+
namespace absl {
namespace macros_internal {
+// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
+// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
} // namespace absl
-#define ABSL_ARRAYSIZE(array) \
- (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
// kLinkerInitialized
//
diff --git a/third_party/abseil-cpp/absl/base/policy_checks.h b/third_party/abseil-cpp/absl/base/policy_checks.h
index d634dac..0a07fc0 100644
--- a/third_party/abseil-cpp/absl/base/policy_checks.h
+++ b/third_party/abseil-cpp/absl/base/policy_checks.h
@@ -86,7 +86,7 @@
// in May, 2010 and includes some functionality used in Google software
// (for instance pthread_setname_np):
// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
-#ifdef __GLIBC_PREREQ
+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2, 12)
#error "Minimum required version of glibc is 2.12."
#endif
diff --git a/third_party/abseil-cpp/absl/container/BUILD.bazel b/third_party/abseil-cpp/absl/container/BUILD.bazel
index 8bdf631..3034108 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -62,6 +62,17 @@
],
)
+cc_test(
+ name = "fixed_array_benchmark",
+ srcs = ["fixed_array_benchmark.cc"],
+ copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"],
+ tags = ["benchmark"],
+ deps = [
+ ":fixed_array",
+ "@com_github_google_benchmark//:benchmark",
+ ],
+)
+
cc_library(
name = "inlined_vector",
hdrs = ["inlined_vector.h"],
@@ -106,6 +117,19 @@
],
)
+cc_test(
+ name = "inlined_vector_benchmark",
+ srcs = ["inlined_vector_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ tags = ["benchmark"],
+ deps = [
+ ":inlined_vector",
+ "//absl/base",
+ "//absl/strings",
+ "@com_github_google_benchmark//:benchmark",
+ ],
+)
+
cc_library(
name = "test_instance_tracker",
testonly = 1,
diff --git a/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc b/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc
new file mode 100644
index 0000000..2d39898
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/fixed_array.h"
+
+#include <stddef.h>
+#include <string>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// For benchmarking -- simple class with constructor and destructor that
+// set an int to a constant..
+class SimpleClass {
+ public:
+ SimpleClass() : i(3) { }
+ ~SimpleClass() { i = 0; }
+ private:
+ int i;
+};
+
+template <typename C, size_t stack_size>
+void BM_FixedArray(benchmark::State& state) {
+ const int size = state.range(0);
+ for (auto _ : state) {
+ absl::FixedArray<C, stack_size> fa(size);
+ benchmark::DoNotOptimize(fa.data());
+ }
+}
+BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault)
+ ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault)
+ ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault)
+ ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16);
+
+} // namespace
+
+BENCHMARK_MAIN();
diff --git a/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
new file mode 100644
index 0000000..c6bc5cd
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
@@ -0,0 +1,376 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/inlined_vector.h"
+
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using IntVec = absl::InlinedVector<int, 8>;
+
+void BM_InlinedVectorFill(benchmark::State& state) {
+ const int len = state.range(0);
+ for (auto _ : state) {
+ IntVec v;
+ for (int i = 0; i < len; i++) {
+ v.push_back(i);
+ }
+ }
+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
+
+void BM_InlinedVectorFillRange(benchmark::State& state) {
+ const int len = state.range(0);
+ std::unique_ptr<int[]> ia(new int[len]);
+ for (int i = 0; i < len; i++) {
+ ia[i] = i;
+ }
+ for (auto _ : state) {
+ IntVec v(ia.get(), ia.get() + len);
+ benchmark::DoNotOptimize(v);
+ }
+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
+
+void BM_StdVectorFill(benchmark::State& state) {
+ const int len = state.range(0);
+ for (auto _ : state) {
+ std::vector<int> v;
+ for (int i = 0; i < len; i++) {
+ v.push_back(i);
+ }
+ }
+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
+
+bool StringRepresentedInline(std::string s) {
+ const char* chars = s.data();
+ std::string s1 = std::move(s);
+ return s1.data() != chars;
+}
+
+void BM_InlinedVectorFillString(benchmark::State& state) {
+ const int len = state.range(0);
+ std::string strings[4] = {"a quite long string",
+ "another long string",
+ "012345678901234567",
+ "to cause allocation"};
+ for (auto _ : state) {
+ absl::InlinedVector<std::string, 8> v;
+ for (int i = 0; i < len; i++) {
+ v.push_back(strings[i & 3]);
+ }
+ }
+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024);
+
+void BM_StdVectorFillString(benchmark::State& state) {
+ const int len = state.range(0);
+ std::string strings[4] = {"a quite long string",
+ "another long string",
+ "012345678901234567",
+ "to cause allocation"};
+ for (auto _ : state) {
+ std::vector<std::string> v;
+ for (int i = 0; i < len; i++) {
+ v.push_back(strings[i & 3]);
+ }
+ }
+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+ // The purpose of the benchmark is to verify that inlined vector is
+ // efficient when moving is more efficent than copying. To do so, we
+ // use strings that are larger than the small std::string optimization.
+ ABSL_RAW_CHECK(!StringRepresentedInline(strings[0]),
+ "benchmarked with strings that are too small");
+}
+BENCHMARK(BM_StdVectorFillString)->Range(0, 1024);
+
+struct Buffer { // some arbitrary structure for benchmarking.
+ char* base;
+ int length;
+ int capacity;
+ void* user_data;
+};
+
+void BM_InlinedVectorTenAssignments(benchmark::State& state) {
+ const int len = state.range(0);
+ using BufferVec = absl::InlinedVector<Buffer, 2>;
+
+ BufferVec src;
+ src.resize(len);
+
+ BufferVec dst;
+ for (auto _ : state) {
+ for (int i = 0; i < 10; ++i) {
+ dst = src;
+ }
+ }
+}
+BENCHMARK(BM_InlinedVectorTenAssignments)
+ ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
+
+void BM_CreateFromContainer(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
+ benchmark::DoNotOptimize(x);
+ }
+}
+BENCHMARK(BM_CreateFromContainer);
+
+struct LargeCopyableOnly {
+ LargeCopyableOnly() : d(1024, 17) {}
+ LargeCopyableOnly(const LargeCopyableOnly& o) = default;
+ LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default;
+
+ std::vector<int> d;
+};
+
+struct LargeCopyableSwappable {
+ LargeCopyableSwappable() : d(1024, 17) {}
+ LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
+ LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
+
+ LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
+ using std::swap;
+ swap(*this, o);
+ return *this;
+ }
+ LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
+
+ friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
+ using std::swap;
+ swap(a.d, b.d);
+ }
+
+ std::vector<int> d;
+};
+
+struct LargeCopyableMovable {
+ LargeCopyableMovable() : d(1024, 17) {}
+ // Use implicitly defined copy and move.
+
+ std::vector<int> d;
+};
+
+struct LargeCopyableMovableSwappable {
+ LargeCopyableMovableSwappable() : d(1024, 17) {}
+ LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) =
+ default;
+ LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default;
+
+ LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) {
+ using std::swap;
+ swap(*this, o);
+ return *this;
+ }
+ LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) =
+ default;
+
+ friend void swap(LargeCopyableMovableSwappable& a,
+ LargeCopyableMovableSwappable& b) {
+ using std::swap;
+ swap(a.d, b.d);
+ }
+
+ std::vector<int> d;
+};
+
+template <typename ElementType>
+void BM_SwapElements(benchmark::State& state) {
+ const int len = state.range(0);
+ using Vec = absl::InlinedVector<ElementType, 32>;
+ Vec a(len);
+ Vec b;
+ for (auto _ : state) {
+ using std::swap;
+ swap(a, b);
+ }
+}
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable)
+ ->Range(0, 1024);
+
+// The following benchmark is meant to track the efficiency of the vector size
+// as a function of stored type via the benchmark label. It is not meant to
+// output useful sizeof operator performance. The loop is a dummy operation
+// to fulfill the requirement of running the benchmark.
+template <typename VecType>
+void BM_Sizeof(benchmark::State& state) {
+ int size = 0;
+ for (auto _ : state) {
+ VecType vec;
+ size = sizeof(vec);
+ }
+ state.SetLabel(absl::StrCat("sz=", size));
+}
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
+
+void BM_InlinedVectorIndexInlined(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+ for (auto _ : state) {
+ for (int i = 0; i < 1000; ++i) {
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
+ }
+ }
+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexInlined);
+
+void BM_InlinedVectorIndexExternal(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ for (int i = 0; i < 1000; ++i) {
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
+ }
+ }
+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexExternal);
+
+void BM_StdVectorIndex(benchmark::State& state) {
+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ for (int i = 0; i < 1000; ++i) {
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
+ }
+ }
+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorIndex);
+
+#define UNROLL_2(x) \
+ benchmark::DoNotOptimize(x); \
+ benchmark::DoNotOptimize(x);
+
+#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
+#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
+#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
+
+void BM_InlinedVectorDataInlined(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+ for (auto _ : state) {
+ UNROLL_16(v.data());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataInlined);
+
+void BM_InlinedVectorDataExternal(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.data());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataExternal);
+
+void BM_StdVectorData(benchmark::State& state) {
+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.data());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorData);
+
+void BM_InlinedVectorSizeInlined(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+ for (auto _ : state) {
+ UNROLL_16(v.size());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeInlined);
+
+void BM_InlinedVectorSizeExternal(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.size());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeExternal);
+
+void BM_StdVectorSize(benchmark::State& state) {
+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.size());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorSize);
+
+void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+ for (auto _ : state) {
+ UNROLL_16(v.empty());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyInlined);
+
+void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.empty());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyExternal);
+
+void BM_StdVectorEmpty(benchmark::State& state) {
+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ for (auto _ : state) {
+ UNROLL_16(v.empty());
+ }
+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorEmpty);
+
+} // namespace
+
+BENCHMARK_MAIN();
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
index 8543200..e1e7fce 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.bazel
@@ -46,6 +46,7 @@
"symbolize.cc",
"symbolize_elf.inc",
"symbolize_unimplemented.inc",
+ "symbolize_win32.inc",
],
hdrs = [
"internal/symbolize.h",
@@ -94,6 +95,38 @@
)
cc_library(
+ name = "failure_signal_handler",
+ srcs = ["failure_signal_handler.cc"],
+ hdrs = ["failure_signal_handler.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":examine_stack",
+ ":stacktrace",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_test(
+ name = "failure_signal_handler_test",
+ srcs = ["failure_signal_handler_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }),
+ deps = [
+ ":failure_signal_handler",
+ ":stacktrace",
+ ":symbolize",
+ "//absl/base",
+ "//absl/strings",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
name = "debugging_internal",
srcs = [
"internal/address_is_readable.cc",
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn
index 2838b77..18e2f4f 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.gn
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn
@@ -46,6 +46,7 @@
"symbolize.cc",
"symbolize_elf.inc",
"symbolize_unimplemented.inc",
+ "symbolize_win32.inc",
]
public = [
"internal/symbolize.h",
@@ -83,6 +84,28 @@
]
}
+source_set("failure_signal_handler") {
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//third_party/abseil-cpp:absl_default_cflags_cc",
+ ]
+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+ sources = [
+ "failure_signal_handler.cc"
+ ]
+ public = [
+ "failure_signal_handler.h"
+ ]
+ deps = [
+ ":examine_stack",
+ ":stacktrace",
+ "../base",
+ "../base:config",
+ "../base:core_headers",
+ ]
+}
+
source_set("debugging_internal") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
diff --git a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
index 8d2ec84..4af2ec8 100644
--- a/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/debugging/CMakeLists.txt
@@ -15,12 +15,14 @@
#
list(APPEND DEBUGGING_PUBLIC_HEADERS
+ "failure_signal_handler.h"
"leak_check.h"
"stacktrace.h"
"symbolize.h"
)
-
+# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in
+# Bazel
list(APPEND DEBUGGING_INTERNAL_HEADERS
"internal/address_is_readable.h"
"internal/demangle.h"
@@ -31,12 +33,16 @@
"internal/vdso_support.h"
)
-
-list(APPEND STACKTRACE_SRC
- "stacktrace.cc"
+list(APPEND DEBUGGING_INTERNAL_SRC
"internal/address_is_readable.cc"
"internal/elf_mem_image.cc"
"internal/vdso_support.cc"
+)
+
+
+list(APPEND STACKTRACE_SRC
+ "stacktrace.cc"
+ ${DEBUGGING_INTERNAL_SRC}
${DEBUGGING_PUBLIC_HEADERS}
${DEBUGGING_INTERNAL_HEADERS}
)
@@ -45,9 +51,16 @@
"symbolize.cc"
"symbolize_elf.inc"
"symbolize_unimplemented.inc"
+ "symbolize_win32.inc"
"internal/demangle.cc"
${DEBUGGING_PUBLIC_HEADERS}
${DEBUGGING_INTERNAL_HEADERS}
+ ${DEBUGGING_INTERNAL_SRC}
+)
+
+list(APPEND FAILURE_SIGNAL_HANDLER_SRC
+ "failure_signal_handler.cc"
+ ${DEBUGGING_PUBLIC_HEADERS}
)
list(APPEND EXAMINE_STACK_SRC
@@ -70,10 +83,24 @@
absl_symbolize
SOURCES
${SYMBOLIZE_SRC}
+ PUBLIC_LIBRARIES
+ absl::base
+ absl_malloc_internal
EXPORT_NAME
symbolize
)
+absl_library(
+ TARGET
+ absl_failure_signal_handler
+ SOURCES
+ ${FAILURE_SIGNAL_HANDLER_SRC}
+ PUBLIC_LIBRARIES
+ absl_base absl::examine_stack absl::stacktrace absl_synchronization
+ EXPORT_NAME
+ failure_signal_handler
+)
+
# Internal-only. Projects external to Abseil should not depend
# directly on this library.
absl_library(
@@ -117,13 +144,9 @@
## TESTS
#
-list(APPEND DEBUGGING_INTERNAL_TEST_HEADERS
- "internal/stack_consumption.h"
-)
-
list(APPEND STACK_CONSUMPTION_SRC
"internal/stack_consumption.cc"
- ${DEBUGGING_INTERNAL_TEST_HEADERS}
+ "internal/stack_consumption.h"
)
absl_library(
@@ -137,10 +160,13 @@
TARGET
absl_stack_consumption_test
SOURCES
- ${STACK_CONSUMPTION_SRC}
+ "internal/stack_consumption_test.cc"
+ PUBLIC_LIBRARIES
+ absl_stack_consumption
+ absl::base
)
-list(APPEND DEMANGLE_TEST_SRC "demangle_test.cc")
+list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
absl_test(
TARGET
@@ -159,7 +185,23 @@
SOURCES
${SYMBOLIZE_TEST_SRC}
PUBLIC_LIBRARIES
- absl_symbolize absl_stack_consumption
+ absl::base absl::memory absl_symbolize absl_stack_consumption
+)
+
+list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
+
+absl_test(
+ TARGET
+ failure_signal_handler_test
+ SOURCES
+ ${FAILURE_SIGNAL_HANDLER_TEST_SRC}
+ PUBLIC_LIBRARIES
+ absl_examine_stack
+ absl_failure_signal_handler
+ absl_stacktrace
+ absl_symbolize
+ absl::base
+ absl::strings
)
# test leak_check_test
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
new file mode 100644
index 0000000..46ef7b8
--- /dev/null
+++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
@@ -0,0 +1,356 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "absl/debugging/failure_signal_handler.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifdef ABSL_HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <csignal>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/debugging/internal/examine_stack.h"
+#include "absl/debugging/stacktrace.h"
+
+#ifndef _WIN32
+#define ABSL_HAVE_SIGACTION
+#endif
+
+namespace absl {
+
+ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
+
+// Resets the signal handler for signo to the default action for that
+// signal, then raises the signal.
+static void RaiseToDefaultHandler(int signo) {
+ signal(signo, SIG_DFL);
+ raise(signo);
+}
+
+struct FailureSignalData {
+ const int signo;
+ const char* const as_string;
+#ifdef ABSL_HAVE_SIGACTION
+ struct sigaction previous_action;
+ // StructSigaction is used to silence -Wmissing-field-initializers.
+ using StructSigaction = struct sigaction;
+ #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
+#else
+ void (*previous_handler)(int);
+ #define FSD_PREVIOUS_INIT SIG_DFL
+#endif
+};
+
+ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = {
+ {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
+ {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
+ {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
+ {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
+ {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
+#ifndef _WIN32
+ {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
+ {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
+#endif
+};
+
+#undef FSD_PREVIOUS_INIT
+
+static void RaiseToPreviousHandler(int signo) {
+ // Search for the previous handler.
+ for (const auto& it : failure_signal_data) {
+ if (it.signo == signo) {
+#ifdef ABSL_HAVE_SIGACTION
+ sigaction(signo, &it.previous_action, nullptr);
+#else
+ signal(signo, it.previous_handler);
+#endif
+ raise(signo);
+ return;
+ }
+ }
+
+ // Not found, use the default handler.
+ RaiseToDefaultHandler(signo);
+}
+
+namespace debugging_internal {
+
+const char* FailureSignalToString(int signo) {
+ for (const auto& it : failure_signal_data) {
+ if (it.signo == signo) {
+ return it.as_string;
+ }
+ }
+ return "";
+}
+
+} // namespace debugging_internal
+
+#ifndef _WIN32
+
+static bool SetupAlternateStackOnce() {
+ const size_t page_mask = getpagesize() - 1;
+ size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+ defined(THREAD_SANITIZER)
+ // Account for sanitizer instrumentation requiring additional stack space.
+ stack_size *= 5;
+#endif
+
+ stack_t sigstk;
+ memset(&sigstk, 0, sizeof(sigstk));
+ sigstk.ss_size = stack_size;
+
+#ifdef ABSL_HAVE_MMAP
+#ifndef MAP_STACK
+#define MAP_STACK 0
+#endif
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+ sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+ if (sigstk.ss_sp == MAP_FAILED) {
+ ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
+ }
+#else
+ sigstk.ss_sp = malloc(sigstk.ss_size);
+ if (sigstk.ss_sp == nullptr) {
+ ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
+ }
+#endif
+
+ if (sigaltstack(&sigstk, nullptr) != 0) {
+ ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
+ }
+ return true;
+}
+
+#endif
+
+// Sets up an alternate stack for signal handlers once.
+// Returns the appropriate flag for sig_action.sa_flags
+// if the system supports using an alternate stack.
+static int MaybeSetupAlternateStack() {
+#ifndef _WIN32
+ ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
+ return SA_ONSTACK;
+#else
+ return 0;
+#endif
+}
+
+#ifdef ABSL_HAVE_SIGACTION
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+ void (*handler)(int, siginfo_t*, void*)) {
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ sigemptyset(&act.sa_mask);
+ act.sa_flags |= SA_SIGINFO;
+ // SA_NODEFER is required to handle SIGABRT from
+ // ImmediateAbortSignalHandler().
+ act.sa_flags |= SA_NODEFER;
+ if (fsh_options.use_alternate_stack) {
+ act.sa_flags |= MaybeSetupAlternateStack();
+ }
+ act.sa_sigaction = handler;
+ ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
+ "sigaction() failed");
+}
+
+#else
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+ void (*handler)(int)) {
+ data->previous_handler = signal(data->signo, handler);
+ ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
+}
+
+#endif
+
+static void WriteToStderr(const char* data) {
+ int old_errno = errno;
+ absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
+ errno = old_errno;
+}
+
+static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
+ char buf[64];
+ const char* const signal_string =
+ debugging_internal::FailureSignalToString(signo);
+ if (signal_string != nullptr && signal_string[0] != '\0') {
+ snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
+ signal_string,
+ static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
+ } else {
+ snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
+ signo, static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
+ }
+ writerfn(buf);
+}
+
+// `void*` might not be big enough to store `void(*)(const char*)`.
+struct WriterFnStruct {
+ void (*writerfn)(const char*);
+};
+
+// Many of the absl::debugging_internal::Dump* functions in
+// examine_stack.h take a writer function pointer that has a void* arg
+// for historical reasons. failure_signal_handler_writer only takes a
+// data pointer. This function converts between these types.
+static void WriterFnWrapper(const char* data, void* arg) {
+ static_cast<WriterFnStruct*>(arg)->writerfn(data);
+}
+
+// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
+// handlers. "noinline" so that GetStackFrames() skips the top-most stack
+// frame for this function.
+ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace(
+ void* ucontext, bool symbolize_stacktrace,
+ void (*writerfn)(const char*, void*), void* writerfn_arg) {
+ constexpr int kNumStackFrames = 32;
+ void* stack[kNumStackFrames];
+ int frame_sizes[kNumStackFrames];
+ int min_dropped_frames;
+ int depth = absl::GetStackFramesWithContext(
+ stack, frame_sizes, kNumStackFrames,
+ 1, // Do not include this function in stack trace.
+ ucontext, &min_dropped_frames);
+ absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace(
+ absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
+ depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
+}
+
+// Called by FailureSignalHandler() to write the failure info. It is
+// called once with writerfn set to WriteToStderr() and then possibly
+// with writerfn set to the user provided function.
+static void WriteFailureInfo(int signo, void* ucontext,
+ void (*writerfn)(const char*)) {
+ WriterFnStruct writerfn_struct{writerfn};
+ WriteSignalMessage(signo, writerfn);
+ WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
+ &writerfn_struct);
+}
+
+// absl::SleepFor() can't be used here since AbslInternalSleepFor()
+// may be overridden to do something that isn't async-signal-safe on
+// some platforms.
+static void PortableSleepForSeconds(int seconds) {
+#ifdef _WIN32
+ Sleep(seconds * 1000);
+#else
+ struct timespec sleep_time;
+ sleep_time.tv_sec = seconds;
+ sleep_time.tv_nsec = 0;
+ while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
+#endif
+}
+
+#ifdef ABSL_HAVE_ALARM
+// FailureSignalHandler() installs this as a signal handler for
+// SIGALRM, then sets an alarm to be delivered to the program after a
+// set amount of time. If FailureSignalHandler() hangs for more than
+// the alarm timeout, ImmediateAbortSignalHandler() will abort the
+// program.
+static void ImmediateAbortSignalHandler(int) {
+ RaiseToDefaultHandler(SIGABRT);
+}
+#endif
+
+// absl::base_internal::GetTID() returns pid_t on most platforms, but
+// returns absl::base_internal::pid_t on Windows.
+using GetTidType = decltype(absl::base_internal::GetTID());
+ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
+
+#ifndef ABSL_HAVE_SIGACTION
+static void FailureSignalHandler(int signo) {
+ void* ucontext = nullptr;
+#else
+static void FailureSignalHandler(int signo, siginfo_t*,
+ void* ucontext) {
+#endif
+
+ const GetTidType this_tid = absl::base_internal::GetTID();
+ GetTidType previous_failed_tid = 0;
+ if (!failed_tid.compare_exchange_strong(
+ previous_failed_tid, static_cast<intptr_t>(this_tid),
+ std::memory_order_acq_rel, std::memory_order_relaxed)) {
+ ABSL_RAW_LOG(
+ ERROR,
+ "Signal %d raised at PC=%p while already in FailureSignalHandler()",
+ signo, absl::debugging_internal::GetProgramCounter(ucontext));
+ if (this_tid != previous_failed_tid) {
+ // Another thread is already in FailureSignalHandler(), so wait
+ // a bit for it to finish. If the other thread doesn't kill us,
+ // we do so after sleeping.
+ PortableSleepForSeconds(3);
+ RaiseToDefaultHandler(signo);
+ // The recursively raised signal may be blocked until we return.
+ return;
+ }
+ }
+
+#ifdef ABSL_HAVE_ALARM
+ // Set an alarm to abort the program in case this code hangs or deadlocks.
+ if (fsh_options.alarm_on_failure_secs > 0) {
+ alarm(0); // Cancel any existing alarms.
+ signal(SIGALRM, ImmediateAbortSignalHandler);
+ alarm(fsh_options.alarm_on_failure_secs);
+ }
+#endif
+
+ // First write to stderr.
+ WriteFailureInfo(signo, ucontext, WriteToStderr);
+
+ // Riskier code (because it is less likely to be async-signal-safe)
+ // goes after this point.
+ if (fsh_options.writerfn != nullptr) {
+ WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
+ }
+
+ if (fsh_options.call_previous_handler) {
+ RaiseToPreviousHandler(signo);
+ } else {
+ RaiseToDefaultHandler(signo);
+ }
+}
+
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
+ fsh_options = options;
+ for (auto& it : failure_signal_data) {
+ InstallOneFailureHandler(&it, FailureSignalHandler);
+ }
+}
+
+} // namespace absl
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h
new file mode 100644
index 0000000..c57954e
--- /dev/null
+++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h
@@ -0,0 +1,117 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: failure_signal_handler.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil *failure signal handler* to capture and dump
+// useful debugging information (such as a stacktrace) upon program failure.
+//
+// To use the failure signal handler, call `absl::InstallFailureSignalHandler()`
+// very early in your program, usually in the first few lines of main():
+//
+// int main(int argc, char** argv) {
+// // Initialize the symbolizer to get a human-readable stack trace
+// absl::InitializeSymbolizer(argv[0]);
+//
+// absl::FailureSignalHandlerOptions options;
+// absl::InstallFailureSignalHandler(options);
+// DoSomethingInteresting();
+// return 0;
+// }
+//
+// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the
+// installed failure signal handler and provide debugging information to stderr.
+//
+// Note that you should *not* install the Abseil failure signal handler more
+// than once. You may, of course, have another (non-Abseil) failure signal
+// handler installed (which would be triggered if Abseil's failure signal
+// handler sets `call_previous_handler` to `true`).
+
+#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+
+namespace absl {
+
+// FailureSignalHandlerOptions
+//
+// Struct for holding `absl::InstallFailureSignalHandler()` configuration
+// options.
+struct FailureSignalHandlerOptions {
+ // If true, try to symbolize the stacktrace emitted on failure, provided that
+ // you have initialized a symbolizer for that purpose. (See symbolize.h for
+ // more information.)
+ bool symbolize_stacktrace = true;
+
+ // If true, try to run signal handlers on an alternate stack (if supported on
+ // the given platform). An alternate stack is useful for program crashes due
+ // to a stack overflow; by running on a alternate stack, the signal handler
+ // may run even when normal stack space has been exausted. The downside of
+ // using an alternate stack is that extra memory for the alternate stack needs
+ // to be pre-allocated.
+ bool use_alternate_stack = true;
+
+ // If positive, indicates the number of seconds after which the failure signal
+ // handler is invoked to abort the program. Setting such an alarm is useful in
+ // cases where the failure signal handler itself may become hung or
+ // deadlocked.
+ int alarm_on_failure_secs = 3;
+
+ // If true, call the previously registered signal handler for the signal that
+ // was received (if one was registered) after the existing signal handler
+ // runs. This mechanism can be used to chain signal handlers together.
+ //
+ // If false, the signal is raised to the default handler for that signal
+ // (which normally terminates the program).
+ //
+ // IMPORTANT: If true, the chained fatal signal handlers must not try to
+ // recover from the fatal signal. Instead, they should terminate the program
+ // via some mechanism, like raising the default handler for the signal, or by
+ // calling `_exit()`. Note that the failure signal handler may put parts of
+ // the Abseil library into a state from which they cannot recover.
+ bool call_previous_handler = false;
+
+ // If non-null, indicates a pointer to a callback function that will be called
+ // upon failure, with a std::string argument containing failure data. This function
+ // may be used as a hook to write failure data to a secondary location, such
+ // as a log file. This function may also be called with null data, as a hint
+ // to flush any buffered data before the program may be terminated. Consider
+ // flushing any buffered data in all calls to this function.
+ //
+ // Since this function runs within a signal handler, it should be
+ // async-signal-safe if possible.
+ // See http://man7.org/linux/man-pages/man7/signal-safety.7.html
+ void (*writerfn)(const char*) = nullptr;
+};
+
+// InstallFailureSignalHandler()
+//
+// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist
+// on the given platform). The failure signal handler dumps program failure data
+// useful for debugging in an unspecified format to stderr. This data may
+// include the program counter, a stacktrace, and register information on some
+// systems; do not rely on an exact format for the output, as it is subject to
+// change.
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options);
+
+namespace debugging_internal {
+const char* FailureSignalToString(int signo);
+} // namespace debugging_internal
+
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
diff --git a/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc b/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
new file mode 100644
index 0000000..ba52091
--- /dev/null
+++ b/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
@@ -0,0 +1,155 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "absl/debugging/failure_signal_handler.h"
+
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+#if GTEST_HAS_DEATH_TEST
+
+// For the parameterized death tests. GetParam() returns the signal number.
+using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
+
+// This function runs in a fork()ed process on most systems.
+void InstallHandlerAndRaise(int signo) {
+ absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
+ raise(signo);
+}
+
+TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
+ const int signo = GetParam();
+ std::string exit_regex = absl::StrCat(
+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
+ " received at time=");
+#ifndef _WIN32
+ EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
+ exit_regex);
+#else
+ // Windows doesn't have testing::KilledBySignal().
+ EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
+#endif
+}
+
+ABSL_CONST_INIT FILE* error_file = nullptr;
+
+void WriteToErrorFile(const char* msg) {
+ if (msg != nullptr) {
+ ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
+ "fwrite() failed");
+ }
+ ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
+}
+
+std::string GetTmpDir() {
+ // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
+ static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
+ "TEMPDIR", "TMP"};
+ for (const char* const var : kTmpEnvVars) {
+ const char* tmp_dir = std::getenv(var);
+ if (tmp_dir != nullptr) {
+ return tmp_dir;
+ }
+ }
+
+ // Try something reasonable.
+ return "/tmp";
+}
+
+// This function runs in a fork()ed process on most systems.
+void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
+ error_file = fopen(file, "w");
+ ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file");
+ absl::FailureSignalHandlerOptions options;
+ options.writerfn = WriteToErrorFile;
+ absl::InstallFailureSignalHandler(options);
+ raise(signo);
+}
+
+TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
+ const int signo = GetParam();
+ std::string tmp_dir = GetTmpDir();
+ std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
+
+ std::string exit_regex = absl::StrCat(
+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
+ " received at time=");
+#ifndef _WIN32
+ EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
+ testing::KilledBySignal(signo), exit_regex);
+#else
+ // Windows doesn't have testing::KilledBySignal().
+ EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
+ exit_regex);
+#endif
+
+ // Open the file in this process and check its contents.
+ std::fstream error_output(file);
+ ASSERT_TRUE(error_output.is_open()) << file;
+ std::string error_line;
+ std::getline(error_output, error_line);
+ EXPECT_TRUE(absl::StartsWith(
+ error_line,
+ absl::StrCat("*** ",
+ absl::debugging_internal::FailureSignalToString(signo),
+ " received at ")));
+
+ if (absl::debugging_internal::StackTraceWorksForTest()) {
+ std::getline(error_output, error_line);
+ EXPECT_TRUE(absl::StartsWith(error_line, "PC: "));
+ }
+}
+
+constexpr int kFailureSignals[] = {
+ SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM,
+#ifndef _WIN32
+ SIGBUS, SIGTRAP,
+#endif
+};
+
+std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
+ std::string result = absl::debugging_internal::FailureSignalToString(info.param);
+ if (result.empty()) {
+ result = absl::StrCat(info.param);
+ }
+ return result;
+}
+
+INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
+ ::testing::ValuesIn(kFailureSignals),
+ SignalParamToString);
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace
+
+int main(int argc, char** argv) {
+ absl::InitializeSymbolizer(argv[0]);
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc
index d6d5192..3f747e7 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc
+++ b/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc
@@ -121,7 +121,7 @@
return reinterpret_cast<const void *>(sym->st_value);
}
ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
- return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_);
}
const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
@@ -161,10 +161,6 @@
if (!base) {
return;
}
- const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
- // Fake VDSO has low bit set.
- const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
- base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
const char *const base_as_char = reinterpret_cast<const char *>(base);
if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
@@ -224,21 +220,7 @@
reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
relocation);
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
- ElfW(Xword) value = dynamic_entry->d_un.d_val;
- if (fake_vdso) {
- // A complication: in the real VDSO, dynamic entries are not relocated
- // (it wasn't loaded by a dynamic loader). But when testing with a
- // "fake" dlopen()ed vdso library, the loader relocates some (but
- // not all!) of them before we get here.
- if (dynamic_entry->d_tag == DT_VERDEF) {
- // The only dynamic entry (of the ones we care about) libc-2.3.6
- // loader doesn't relocate.
- value += relocation;
- }
- } else {
- // Real VDSO. Everything needs to be relocated.
- value += relocation;
- }
+ const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation;
switch (dynamic_entry->d_tag) {
case DT_HASH:
hash_ = reinterpret_cast<ElfW(Word) *>(value);
diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
index a861c0a..7ed6b3e 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -14,6 +14,7 @@
#include <cstdint>
#include <iostream>
+#include "absl/base/attributes.h"
#include "absl/debugging/internal/address_is_readable.h"
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
#include "absl/debugging/stacktrace.h"
@@ -24,7 +25,7 @@
// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
static const unsigned char* GetKernelRtSigreturnAddress() {
constexpr uintptr_t kImpossibleAddress = 1;
- static std::atomic<uintptr_t> memoized{kImpossibleAddress};
+ ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress};
uintptr_t address = memoized.load(std::memory_order_relaxed);
if (address != kImpossibleAddress) {
return reinterpret_cast<const unsigned char*>(address);
diff --git a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
index 7ae1383..8d926fe 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
+++ b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
@@ -20,6 +20,7 @@
#include <cstddef>
#include <cstdint>
+#include "absl/base/port.h" // Needed for string vs std::string
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
diff --git a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h
index 870a60a..8002c74 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h
+++ b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h
@@ -41,6 +41,7 @@
#include <atomic>
+#include "absl/base/attributes.h"
#include "absl/debugging/internal/elf_mem_image.h"
#ifdef ABSL_HAVE_ELF_MEM_IMAGE
@@ -132,7 +133,7 @@
// This function pointer may point to InitAndGetCPU,
// GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
- static std::atomic<GetCpuFn> getcpu_fn_;
+ ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
friend int GetCPU(void); // Needs access to getcpu_fn_.
diff --git a/third_party/abseil-cpp/absl/debugging/leak_check.h b/third_party/abseil-cpp/absl/debugging/leak_check.h
index f67fe88..c930684 100644
--- a/third_party/abseil-cpp/absl/debugging/leak_check.h
+++ b/third_party/abseil-cpp/absl/debugging/leak_check.h
@@ -1,5 +1,4 @@
-//
-// Copyright 2017 The Abseil Authors.
+// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,15 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-
// -----------------------------------------------------------------------------
// File: leak_check.h
// -----------------------------------------------------------------------------
//
-// This package contains functions that affect leak checking behavior within
+// This file contains functions that affect leak checking behavior within
// targets built with the LeakSanitizer (LSan), a memory leak detector that is
// integrated within the AddressSanitizer (ASan) as an additional component, or
-// which can be used standalone. LSan and ASan are included or can be provided
+// which can be used standalone. LSan and ASan are included (or can be provided)
// as additional components for most compilers such as Clang, gcc and MSVC.
// Note: this leak checking API is not yet supported in MSVC.
// Leak checking is enabled by default in all ASan builds.
diff --git a/third_party/abseil-cpp/absl/debugging/stacktrace.h b/third_party/abseil-cpp/absl/debugging/stacktrace.h
index 82da3f1..8b831e2 100644
--- a/third_party/abseil-cpp/absl/debugging/stacktrace.h
+++ b/third_party/abseil-cpp/absl/debugging/stacktrace.h
@@ -1,5 +1,4 @@
-//
-// Copyright 2017 The Abseil Authors.
+// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,26 +12,37 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-
-// Routines to extract the current stack trace. These functions are
-// thread-safe and async-signal-safe.
+// -----------------------------------------------------------------------------
+// File: stacktrace.h
+// -----------------------------------------------------------------------------
+//
+// This file contains routines to extract the current stack trace and associated
+// stack frames. These functions are thread-safe and async-signal-safe.
+//
// Note that stack trace functionality is platform dependent and requires
-// additional support from the compiler/build system in many cases. (That is,
-// this generally only works on platforms/builds that have been specifically
-// configured to support it.)
+// additional support from the compiler/build system in most cases. (That is,
+// this functionality generally only works on platforms/builds that have been
+// specifically configured to support it.)
+//
+// Note: stack traces in Abseil that do not utilize a symbolizer will result in
+// frames consisting of function addresses rather than human-readable function
+// names. (See symbolize.h for information on symbolizing these values.)
#ifndef ABSL_DEBUGGING_STACKTRACE_H_
#define ABSL_DEBUGGING_STACKTRACE_H_
namespace absl {
-// Skips the most recent "skip_count" stack frames (also skips the
-// frame generated for the "absl::GetStackFrames" routine itself), and then
-// records the pc values for up to the next "max_depth" frames in
-// "result", and the corresponding stack frame sizes in "sizes".
-// Returns the number of values recorded in "result"/"sizes".
+// GetStackFrames()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, and stores their corresponding values
+// and sizes in `results` and `sizes` buffers. (Note that the frame generated
+// for the `absl::GetStackFrames()` routine itself is also skipped.)
+// routine itself.
//
// Example:
+//
// main() { foo(); }
// foo() { bar(); }
// bar() {
@@ -41,41 +51,66 @@
// int depth = absl::GetStackFrames(result, sizes, 10, 1);
// }
//
-// The absl::GetStackFrames call will skip the frame for "bar". It will
-// return 2 and will produce pc values that map to the following
-// procedures:
-// result[0] foo
-// result[1] main
-// (Actually, there may be a few more entries after "main" to account for
-// startup procedures.)
-// And corresponding stack frame sizes will also be recorded:
+// The current stack frame would consist of three function calls: `bar()`,
+// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
+// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
+// invoked function call. It will therefore return two program counters and will
+// produce values that map to the following function calls:
+//
+// result[0] foo()
+// result[1] main()
+//
+// (Note: in practice, a few more entries after `main()` may be added to account
+// for startup processes.)
+//
+// Corresponding stack frame sizes will also be recorded:
+//
// sizes[0] 16
// sizes[1] 16
-// (Stack frame sizes of 16 above are just for illustration purposes.)
+//
+// (Stack frame sizes of `16` above are just for illustration purposes.)
+//
// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
// be identified.
//
// This routine may return fewer stack frame entries than are
-// available. Also note that "result" and "sizes" must both be non-null.
+// available. Also note that `result` and `sizes` must both be non-null.
extern int GetStackFrames(void** result, int* sizes, int max_depth,
int skip_count);
-// Same as above, but to be used from a signal handler. The "uc" parameter
-// should be the pointer to ucontext_t which was passed as the 3rd parameter
-// to sa_sigaction signal handler. It may help the unwinder to get a
-// better stack trace under certain conditions. The "uc" may safely be null.
+// GetStackFramesWithContext()
//
-// If min_dropped_frames is not null, stores in *min_dropped_frames a
-// lower bound on the number of dropped stack frames. The stored value is
-// guaranteed to be >= 0. The number of real stack frames is guaranteed to
-// be >= skip_count + max_depth + *min_dropped_frames.
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, and stores their corresponding values and sizes in
+// `results` and `sizes` buffers. (Note that the frame generated for the
+// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
int skip_count, const void* uc,
int* min_dropped_frames);
-// This is similar to the absl::GetStackFrames routine, except that it returns
-// the stack trace only, and not the stack frame sizes as well.
+// GetStackTrace()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, and stores their corresponding values
+// in `results`. Note that this function is similar to `absl::GetStackFrames()`
+// except that it returns the stack trace only, and not stack frame sizes.
+//
// Example:
+//
// main() { foo(); }
// foo() { bar(); }
// bar() {
@@ -84,42 +119,57 @@
// }
//
// This produces:
+//
// result[0] foo
// result[1] main
// .... ...
//
-// "result" must not be null.
+// `result` must not be null.
extern int GetStackTrace(void** result, int max_depth, int skip_count);
-// Same as above, but to be used from a signal handler. The "uc" parameter
-// should be the pointer to ucontext_t which was passed as the 3rd parameter
-// to sa_sigaction signal handler. It may help the unwinder to get a
-// better stack trace under certain conditions. The "uc" may safely be null.
+// GetStackTraceWithContext()
//
-// If min_dropped_frames is not null, stores in *min_dropped_frames a
-// lower bound on the number of dropped stack frames. The stored value is
-// guaranteed to be >= 0. The number of real stack frames is guaranteed to
-// be >= skip_count + max_depth + *min_dropped_frames.
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, and stores their corresponding values in
+// `results`. (Note that the frame generated for the
+// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
extern int GetStackTraceWithContext(void** result, int max_depth,
int skip_count, const void* uc,
int* min_dropped_frames);
-// Call this to provide a custom function for unwinding stack frames
-// that will be used every time someone invokes one of the static
+// SetStackUnwinder()
+//
+// Provides a custom function for unwinding stack frames that will be used in
+// place of the default stack unwinder when invoking the static
// GetStack{Frames,Trace}{,WithContext}() functions above.
//
// The arguments passed to the unwinder function will match the
-// arguments passed to absl::GetStackFramesWithContext() except that sizes
+// arguments passed to `absl::GetStackFramesWithContext()` except that sizes
// will be non-null iff the caller is interested in frame sizes.
//
-// If unwinder is null, we revert to the default stack-tracing behavior.
+// If unwinder is set to null, we revert to the default stack-tracing behavior.
//
-// ****************************************************************
-// WARNINGS
+// *****************************************************************************
+// WARNING
+// *****************************************************************************
//
// absl::SetStackUnwinder is not suitable for general purpose use. It is
// provided for custom runtimes.
-// Some things to watch out for when calling absl::SetStackUnwinder:
+// Some things to watch out for when calling `absl::SetStackUnwinder()`:
//
// (a) The unwinder may be called from within signal handlers and
// therefore must be async-signal-safe.
@@ -128,23 +178,31 @@
// threads may still be in the process of using that unwinder.
// Therefore do not clean up any state that may be needed by an old
// unwinder.
-// ****************************************************************
+// *****************************************************************************
extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
int max_depth, int skip_count,
const void* uc,
int* min_dropped_frames));
-// Function that exposes built-in stack-unwinding behavior, ignoring
-// any calls to absl::SetStackUnwinder().
+// DefaultStackUnwinder()
//
-// pcs must NOT be null.
+// Records program counter values of up to `max_depth` frames, skipping the most
+// recent `skip_count` stack frames, and stores their corresponding values in
+// `pcs`. (Note that the frame generated for this call itself is also skipped.)
+// This function acts as a generic stack-unwinder; prefer usage of the more
+// specific `GetStack{Trace,Frames}{,WithContext}()` functions above.
//
-// sizes may be null.
-// uc may be null.
-// min_dropped_frames may be null.
+// If you have set your own stack unwinder (with the `SetStackUnwinder()`
+// function above, you can still get the default stack unwinder by calling
+// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder
+// and use the default one instead.
//
-// The semantics are the same as the corresponding GetStack*() function in the
-// case where absl::SetStackUnwinder() was never called. Equivalents are:
+// Because this function is generic, only `pcs` is guaranteed to be non-null
+// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all
+// be null when called.
+//
+// The semantics are the same as the corresponding `GetStack*()` function in the
+// case where `absl::SetStackUnwinder()` was never called. Equivalents are:
//
// null sizes | non-nullptr sizes
// |==========================================================|
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize.cc b/third_party/abseil-cpp/absl/debugging/symbolize.cc
index 355bf9f..a35e24c 100644
--- a/third_party/abseil-cpp/absl/debugging/symbolize.cc
+++ b/third_party/abseil-cpp/absl/debugging/symbolize.cc
@@ -14,8 +14,15 @@
#include "absl/debugging/symbolize.h"
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
#include "absl/debugging/symbolize_elf.inc"
+#elif defined(_WIN32) && defined(_DEBUG)
+// The Windows Symbolizer only works in debug mode. Note that _DEBUG
+// is the macro that defines whether or not MS C-Runtime debug info is
+// available. Note that the PDB files containing the debug info must
+// also be available to the program at runtime for the symbolizer to
+// work.
+#include "absl/debugging/symbolize_win32.inc"
#else
#include "absl/debugging/symbolize_unimplemented.inc"
#endif
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize.h b/third_party/abseil-cpp/absl/debugging/symbolize.h
index 073a447..24e6e64 100644
--- a/third_party/abseil-cpp/absl/debugging/symbolize.h
+++ b/third_party/abseil-cpp/absl/debugging/symbolize.h
@@ -11,7 +11,44 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
+//
+// -----------------------------------------------------------------------------
+// File: symbolize.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil symbolizer for use in converting instruction
+// pointer addresses (program counters) into human-readable names (function
+// calls, etc.) within Abseil code.
+//
+// The symbolizer may be invoked from several sources:
+//
+// * Implicitly, through the installation of an Abseil failure signal handler.
+// (See failure_signal_handler.h for more information.)
+// * By calling `Symbolize()` directly on a program counter you obtain through
+// `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h
+// for more information.
+// * By calling `Symbolize()` directly on a program counter you obtain through
+// other means (which would be platform-dependent).
+//
+// In all of the above cases, the symbolizer must first be initialized before
+// any program counter values can be symbolized. If you are installing a failure
+// signal handler, initialize the symbolizer before you do so.
+//
+// Example:
+//
+// int main(int argc, char** argv) {
+// // Initialize the Symbolizer before installing the failure signal handler
+// absl::InitializeSymbolizer(argv[0]);
+//
+// // Now you may install the failure signal handler
+// absl::FailureSignalHandlerOptions options;
+// absl::InstallFailureSignalHandler(options);
+//
+// // Start running your main program
+// ...
+// return 0;
+// }
+//
#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_
#define ABSL_DEBUGGING_SYMBOLIZE_H_
@@ -19,15 +56,40 @@
namespace absl {
-// Initializes this module. Symbolize() may fail prior calling this function.
-// `argv0` is the path to this program, which is usually obtained in main()
-// though argv[0].
+// InitializeSymbolizer()
+//
+// Initializes the program counter symbolizer, given the path of the program
+// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer
+// allows you to read program counters (instruction pointer values) using their
+// human-readable names within output such as stack traces.
+//
+// Example:
+//
+// int main(int argc, char *argv[]) {
+// absl::InitializeSymbolizer(argv[0]);
+// // Now you can use the symbolizer
+// }
void InitializeSymbolizer(const char* argv0);
-// Symbolizes a program counter. On success, returns true and write the
-// symbol name to "out". The symbol name is demangled if possible
-// (supports symbols generated by GCC 3.x or newer), may be truncated, and
-// will be '\0' terminated. Otherwise, returns false.
+// Symbolize()
+//
+// Symbolizes a program counter (instruction pointer value) `pc` and, on
+// success, writes the name to `out`. The symbol name is demangled, if possible.
+// Note that the symbolized name may be truncated and will be NUL-terminated.
+// Demangling is supported for symbols generated by GCC 3.x or newer). Returns
+// `false` on failure.
+//
+// Example:
+//
+// // Print a program counter and its symbol name.
+// static void DumpPCAndSymbol(void *pc) {
+// char tmp[1024];
+// const char *symbol = "(unknown)";
+// if (absl::Symbolize(pc, tmp, sizeof(tmp))) {
+// symbol = tmp;
+// }
+// absl::PrintF("%*p %s\n", pc, symbol);
+// }
bool Symbolize(const void *pc, char *out, int out_size);
} // namespace absl
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
index b23a801..5f2af47 100644
--- a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
+++ b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
@@ -68,7 +68,7 @@
return 0;
}
-int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) regular_func() {
+int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() {
return 0;
}
@@ -88,9 +88,7 @@
// Force the binary to be large enough that a THP .text remap will succeed.
static constexpr size_t kHpageSize = 1 << 21;
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
- ".text") = "";
-
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+ .text) = "";
static char try_symbolize_buffer[4096];
@@ -120,6 +118,8 @@
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
}
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+
TEST(Symbolize, Cached) {
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
@@ -236,9 +236,9 @@
const size_t kPageSize = 64 << 10;
// We place a read-only symbols into the .text section and verify that we can
// symbolize them and other symbols after remapping them.
-const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") =
+const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
"";
-const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") =
+const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
"";
static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
@@ -442,6 +442,45 @@
#endif
}
+#elif defined(_WIN32) && defined(_DEBUG)
+
+TEST(Symbolize, Basics) {
+ EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
+
+ // The name of an internal linkage symbol is not specified; allow either a
+ // mangled or an unmangled name here.
+ const char* static_func_symbol = TrySymbolize((void *)(&static_func));
+ ASSERT_TRUE(static_func_symbol != nullptr);
+ EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
+
+ EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
+}
+
+TEST(Symbolize, Truncation) {
+ constexpr char kNonStaticFunc[] = "nonstatic_func";
+ EXPECT_STREQ("nonstatic_func",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) + 1));
+ EXPECT_STREQ("nonstatic_...",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) + 0));
+ EXPECT_STREQ("nonstatic...",
+ TrySymbolizeWithLimit((void *)(&nonstatic_func),
+ strlen(kNonStaticFunc) - 1));
+ EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
+ EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
+ EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
+ EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
+ EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
+ EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
+}
+
+TEST(Symbolize, SymbolizeWithDemangling) {
+ const char* result = TrySymbolize((void *)(&Foo::func));
+ ASSERT_TRUE(result != nullptr);
+ EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
+}
+
#else // Symbolizer unimplemented
TEST(Symbolize, Unimplemented) {
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc b/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc
new file mode 100644
index 0000000..e3fff74
--- /dev/null
+++ b/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See "Retrieving Symbol Information by Address":
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+
+#include <windows.h>
+#include <DbgHelp.h>
+#pragma comment(lib, "DbgHelp")
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+static HANDLE process = NULL;
+
+void InitializeSymbolizer(const char *argv0) {
+ if (process != nullptr) {
+ return;
+ }
+ process = GetCurrentProcess();
+
+ // Symbols are not loaded until a reference is made requiring the
+ // symbols be loaded. This is the fastest, most efficient way to use
+ // the symbol handler.
+ SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
+ if (!SymInitialize(process, nullptr, true)) {
+ // GetLastError() returns a Win32 DWORD, but we assign to
+ // unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform
+ // initialization guarantees this is not a narrowing conversion.
+ const unsigned long long error{GetLastError()}; // NOLINT(runtime/int)
+ ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
+ }
+}
+
+bool Symbolize(const void *pc, char *out, int out_size) {
+ if (out_size <= 0) {
+ return false;
+ }
+ std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
+ alignof(SYMBOL_INFO)>::type buf;
+ SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+ if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
+ return false;
+ }
+ strncpy(out, symbol->Name, out_size);
+ if (out[out_size - 1] != '\0') {
+ // strncpy() does not '\0' terminate when it truncates.
+ static constexpr char kEllipsis[] = "...";
+ int ellipsis_size =
+ std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+ out[out_size - 1] = '\0';
+ }
+ return true;
+}
+
+} // namespace absl
diff --git a/third_party/abseil-cpp/absl/meta/CMakeLists.txt b/third_party/abseil-cpp/absl/meta/CMakeLists.txt
index d56fced..adb0ceb 100644
--- a/third_party/abseil-cpp/absl/meta/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/meta/CMakeLists.txt
@@ -32,6 +32,8 @@
absl_header_library(
TARGET
absl_meta
+ PUBLIC_LIBRARIES
+ absl::base
EXPORT_NAME
meta
)
@@ -42,7 +44,8 @@
SOURCES
${TYPE_TRAITS_TEST_SRC}
PUBLIC_LIBRARIES
- ${TYPE_TRAITS_TEST_PUBLIC_LIBRARIES} absl::meta
+ absl::base
+ absl::meta
)
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel
index 13badb7..1e52312 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -84,6 +84,7 @@
"internal/utf8.cc",
],
hdrs = [
+ "internal/bits.h",
"internal/char_map.h",
"internal/ostringstream.h",
"internal/resize_uninitialized.h",
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.gn b/third_party/abseil-cpp/absl/strings/BUILD.gn
index 798a3b3..2f73f5d 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.gn
+++ b/third_party/abseil-cpp/absl/strings/BUILD.gn
@@ -76,6 +76,7 @@
"internal/utf8.cc",
]
public = [
+ "internal/bits.h",
"internal/char_map.h",
"internal/ostringstream.h",
"internal/resize_uninitialized.h",
diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
index 83cb934..9dc4732 100644
--- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -31,6 +31,7 @@
list(APPEND STRINGS_INTERNAL_HEADERS
+ "internal/bits.h"
"internal/char_map.h"
"internal/memutil.h"
"internal/ostringstream.h"
diff --git a/third_party/abseil-cpp/absl/strings/internal/bits.h b/third_party/abseil-cpp/absl/strings/internal/bits.h
new file mode 100644
index 0000000..901082c
--- /dev/null
+++ b/third_party/abseil-cpp/absl/strings/internal/bits.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_BITS_H_
+#define ABSL_STRINGS_INTERNAL_BITS_H_
+
+#include <cstdint>
+
+#if defined(_MSC_VER) && defined(_M_X64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#endif
+
+namespace absl {
+namespace strings_internal {
+
+// Returns the number of leading 0 bits in a 64-bit value.
+inline int CountLeadingZeros64(uint64_t n) {
+#if defined(__GNUC__)
+ static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
+ "__builtin_clzll does not take 64bit arg");
+ return n == 0 ? 64 : __builtin_clzll(n);
+#elif defined(_MSC_VER) && defined(_M_X64)
+ unsigned long result; // NOLINT(runtime/int)
+ if (_BitScanReverse64(&result, n)) {
+ return 63 - result;
+ }
+ return 64;
+#else
+ int zeroes = 60;
+ if (n >> 32) zeroes -= 32, n >>= 32;
+ if (n >> 16) zeroes -= 16, n >>= 16;
+ if (n >> 8) zeroes -= 8, n >>= 8;
+ if (n >> 4) zeroes -= 4, n >>= 4;
+ return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes;
+#endif
+}
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_BITS_H_
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h b/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h
index c5fdc28..a734758 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h
@@ -234,17 +234,19 @@
result_size += it->size();
}
- STLStringResizeUninitialized(&result, result_size);
+ if (result_size > 0) {
+ STLStringResizeUninitialized(&result, result_size);
- // Joins strings
- char* result_buf = &*result.begin();
- memcpy(result_buf, start->data(), start->size());
- result_buf += start->size();
- for (Iterator it = start; ++it != end;) {
- memcpy(result_buf, s.data(), s.size());
- result_buf += s.size();
- memcpy(result_buf, it->data(), it->size());
- result_buf += it->size();
+ // Joins strings
+ char* result_buf = &*result.begin();
+ memcpy(result_buf, start->data(), start->size());
+ result_buf += start->size();
+ for (Iterator it = start; ++it != end;) {
+ memcpy(result_buf, s.data(), s.size());
+ result_buf += s.size();
+ memcpy(result_buf, it->data(), it->size());
+ result_buf += it->size();
+ }
}
}
diff --git a/third_party/abseil-cpp/absl/strings/match.h b/third_party/abseil-cpp/absl/strings/match.h
index 6005533..108b604 100644
--- a/third_party/abseil-cpp/absl/strings/match.h
+++ b/third_party/abseil-cpp/absl/strings/match.h
@@ -43,8 +43,7 @@
//
// Returns whether a given std::string `haystack` contains the substring `needle`.
inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
- return static_cast<absl::string_view::size_type>(haystack.find(needle, 0)) !=
- haystack.npos;
+ return haystack.find(needle, 0) != haystack.npos;
}
// StartsWith()
diff --git a/third_party/abseil-cpp/absl/strings/numbers.cc b/third_party/abseil-cpp/absl/strings/numbers.cc
index b4140b3..68ef799 100644
--- a/third_party/abseil-cpp/absl/strings/numbers.cc
+++ b/third_party/abseil-cpp/absl/strings/numbers.cc
@@ -32,6 +32,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/ascii.h"
+#include "absl/strings/internal/bits.h"
#include "absl/strings/internal/memutil.h"
#include "absl/strings/str_cat.h"
@@ -302,18 +303,6 @@
return numbers_internal::FastIntToBuffer(u, buffer);
}
-// Returns the number of leading 0 bits in a 64-bit value.
-// TODO(jorg): Replace with builtin_clzll if available.
-// Are we shipping util/bits in absl?
-static inline int CountLeadingZeros64(uint64_t n) {
- int zeroes = 60;
- if (n >> 32) zeroes -= 32, n >>= 32;
- if (n >> 16) zeroes -= 16, n >>= 16;
- if (n >> 8) zeroes -= 8, n >>= 8;
- if (n >> 4) zeroes -= 4, n >>= 4;
- return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes;
-}
-
// Given a 128-bit number expressed as a pair of uint64_t, high half first,
// return that number multiplied by the given 32-bit value. If the result is
// too large to fit in a 128-bit number, divide it by 2 until it fits.
@@ -351,7 +340,7 @@
uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
if (bits128_up == 0) return {bits64_127, bits0_63};
- int shift = 64 - CountLeadingZeros64(bits128_up);
+ int shift = 64 - strings_internal::CountLeadingZeros64(bits128_up);
uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
return {hi, lo};
@@ -382,7 +371,7 @@
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
result = Mul32(result, powers_of_five[expfive & 15]);
- int shift = CountLeadingZeros64(result.first);
+ int shift = strings_internal::CountLeadingZeros64(result.first);
if (shift != 0) {
result.first = (result.first << shift) + (result.second >> (64 - shift));
result.second = (result.second << shift);
diff --git a/third_party/abseil-cpp/absl/strings/str_cat.h b/third_party/abseil-cpp/absl/strings/str_cat.h
index e38369c..e5501a5 100644
--- a/third_party/abseil-cpp/absl/strings/str_cat.h
+++ b/third_party/abseil-cpp/absl/strings/str_cat.h
@@ -80,7 +80,7 @@
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
// would produce hexadecimal strings such as " A"," F".
-enum PadSpec {
+enum PadSpec : uint8_t {
kNoPad = 1,
kZeroPad2,
kZeroPad3,
diff --git a/third_party/abseil-cpp/absl/strings/str_join_test.cc b/third_party/abseil-cpp/absl/strings/str_join_test.cc
index 03b60f0..c941f9c 100644
--- a/third_party/abseil-cpp/absl/strings/str_join_test.cc
+++ b/third_party/abseil-cpp/absl/strings/str_join_test.cc
@@ -24,7 +24,6 @@
#include <map>
#include <memory>
#include <ostream>
-#include <set>
#include <tuple>
#include <type_traits>
#include <vector>
diff --git a/third_party/abseil-cpp/absl/strings/string_view.cc b/third_party/abseil-cpp/absl/strings/string_view.cc
index 0e17295..4ceeb6b 100644
--- a/third_party/abseil-cpp/absl/strings/string_view.cc
+++ b/third_party/abseil-cpp/absl/strings/string_view.cc
@@ -22,8 +22,6 @@
#include <ostream>
#include "absl/strings/internal/memutil.h"
-#include "absl/strings/internal/resize_uninitialized.h"
-#include "absl/strings/match.h"
namespace absl {
diff --git a/third_party/abseil-cpp/absl/strings/string_view.h b/third_party/abseil-cpp/absl/strings/string_view.h
index 9162bb3..a7f9199 100644
--- a/third_party/abseil-cpp/absl/strings/string_view.h
+++ b/third_party/abseil-cpp/absl/strings/string_view.h
@@ -36,7 +36,7 @@
namespace absl {
using std::string_view;
-};
+} // namespace absl
#else // ABSL_HAVE_STD_STRING_VIEW
diff --git a/third_party/abseil-cpp/absl/strings/substitute.cc b/third_party/abseil-cpp/absl/strings/substitute.cc
index f739f8c..3b20059 100644
--- a/third_party/abseil-cpp/absl/strings/substitute.cc
+++ b/third_party/abseil-cpp/absl/strings/substitute.cc
@@ -94,6 +94,7 @@
assert(target == output->data() + output->size());
}
+static const char kHexDigits[] = "0123456789abcdef";
Arg::Arg(const void* value) {
static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
"fix sizeof(scratch_)");
@@ -102,7 +103,6 @@
} else {
char* ptr = scratch_ + sizeof(scratch_);
uintptr_t num = reinterpret_cast<uintptr_t>(value);
- static const char kHexDigits[] = "0123456789abcdef";
do {
*--ptr = kHexDigits[num & 0xf];
num >>= 4;
@@ -113,5 +113,58 @@
}
}
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Hex hex) {
+ char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+ char* writer = end;
+ uint64_t value = hex.value;
+ do {
+ *--writer = kHexDigits[value & 0xF];
+ value >>= 4;
+ } while (value != 0);
+
+ char* beg;
+ if (end - writer < hex.width) {
+ beg = end - hex.width;
+ std::fill_n(beg, writer - beg, hex.fill);
+ } else {
+ beg = writer;
+ }
+
+ piece_ = absl::string_view(beg, end - beg);
+}
+
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Dec dec) {
+ assert(dec.width <= numbers_internal::kFastToBufferSize);
+ char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+ char* const minfill = end - dec.width;
+ char* writer = end;
+ uint64_t value = dec.value;
+ bool neg = dec.neg;
+ while (value > 9) {
+ *--writer = '0' + (value % 10);
+ value /= 10;
+ }
+ *--writer = '0' + value;
+ if (neg) *--writer = '-';
+
+ ptrdiff_t fillers = writer - minfill;
+ if (fillers > 0) {
+ // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
+ // But...: if the fill character is '0', then it's <+/-><fill><digits>
+ bool add_sign_again = false;
+ if (neg && dec.fill == '0') { // If filling with '0',
+ ++writer; // ignore the sign we just added
+ add_sign_again = true; // and re-add the sign later.
+ }
+ writer -= fillers;
+ std::fill_n(writer, fillers, dec.fill);
+ if (add_sign_again) *--writer = '-';
+ }
+
+ piece_ = absl::string_view(writer, end - writer);
+}
+
} // namespace substitute_internal
} // namespace absl
diff --git a/third_party/abseil-cpp/absl/strings/substitute.h b/third_party/abseil-cpp/absl/strings/substitute.h
index 5596a5d..5747d38 100644
--- a/third_party/abseil-cpp/absl/strings/substitute.h
+++ b/third_party/abseil-cpp/absl/strings/substitute.h
@@ -76,7 +76,7 @@
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/numbers.h"
-#include "absl/strings/str_join.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
@@ -113,10 +113,10 @@
// what to do.
Arg(char value) // NOLINT(runtime/explicit)
: piece_(scratch_, 1) { scratch_[0] = value; }
- Arg(short value) // NOLINT(runtime/explicit)
+ Arg(short value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
- Arg(unsigned short value) // NOLINT(runtime/explicit)
+ Arg(unsigned short value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
Arg(int value) // NOLINT(runtime/explicit)
@@ -125,16 +125,16 @@
Arg(unsigned int value) // NOLINT(runtime/explicit)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
- Arg(long value) // NOLINT(runtime/explicit)
+ Arg(long value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
- Arg(unsigned long value) // NOLINT(runtime/explicit)
+ Arg(unsigned long value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
- Arg(long long value) // NOLINT(runtime/explicit)
+ Arg(long long value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
- Arg(unsigned long long value) // NOLINT(runtime/explicit)
+ Arg(unsigned long long value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
Arg(float value) // NOLINT(runtime/explicit)
@@ -145,6 +145,10 @@
}
Arg(bool value) // NOLINT(runtime/explicit)
: piece_(value ? "true" : "false") {}
+
+ Arg(Hex hex); // NOLINT(runtime/explicit)
+ Arg(Dec dec); // NOLINT(runtime/explicit)
+
// `void*` values, with the exception of `char*`, are printed as
// "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
Arg(const void* value); // NOLINT(runtime/explicit)
diff --git a/third_party/abseil-cpp/absl/strings/substitute_test.cc b/third_party/abseil-cpp/absl/strings/substitute_test.cc
index 7c9af6b..144df01 100644
--- a/third_party/abseil-cpp/absl/strings/substitute_test.cc
+++ b/third_party/abseil-cpp/absl/strings/substitute_test.cc
@@ -43,6 +43,24 @@
-1234567890, 3234567890U, -1234567890L, 3234567890UL,
-int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
+ // Hex format
+ EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef",
+ absl::Substitute("$0$1$2$3$4 $5", //
+ absl::Hex(0), absl::Hex(1, absl::kSpacePad2),
+ absl::Hex(0xf, absl::kSpacePad2),
+ absl::Hex(int16_t{-1}, absl::kSpacePad5),
+ absl::Hex(int16_t{-1}, absl::kZeroPad5),
+ absl::Hex(0x123456789abcdef, absl::kZeroPad16)));
+
+ // Dec format
+ EXPECT_EQ("0 115 -1-0001 81985529216486895",
+ absl::Substitute("$0$1$2$3$4 $5", //
+ absl::Dec(0), absl::Dec(1, absl::kSpacePad2),
+ absl::Dec(0xf, absl::kSpacePad2),
+ absl::Dec(int16_t{-1}, absl::kSpacePad5),
+ absl::Dec(int16_t{-1}, absl::kZeroPad5),
+ absl::Dec(0x123456789abcdef, absl::kZeroPad16)));
+
// Pointer.
const int* int_p = reinterpret_cast<const int*>(0x12345);
std::string str = absl::Substitute("$0", int_p);
diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
index 69f9c81..0537690 100644
--- a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
@@ -77,6 +77,7 @@
"//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
"//absl/debugging:stacktrace",
+ "//absl/debugging:symbolize",
"//absl/time",
],
)
diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.gn b/third_party/abseil-cpp/absl/synchronization/BUILD.gn
index 65f9d3b..dfca941 100644
--- a/third_party/abseil-cpp/absl/synchronization/BUILD.gn
+++ b/third_party/abseil-cpp/absl/synchronization/BUILD.gn
@@ -73,6 +73,7 @@
"../base:dynamic_annotations",
"../base:malloc_internal",
"../debugging:stacktrace",
+ "../debugging:symbolize",
"../time",
]
}
diff --git a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
index c8f84fa..c19f572 100644
--- a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
@@ -33,7 +33,7 @@
-# syncrhonisation library
+# synchronization library
list(APPEND SYNCHRONIZATION_SRC
"barrier.cc"
"blocking_counter.cc"
@@ -44,7 +44,8 @@
"notification.cc"
"mutex.cc"
)
-set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::time)
+
+set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
absl_library(
TARGET
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc
index 3c3e939..a207b71 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -50,6 +50,7 @@
#include "absl/base/internal/thread_identity.h"
#include "absl/base/port.h"
#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
#include "absl/synchronization/internal/graphcycles.h"
#include "absl/synchronization/internal/per_thread_sem.h"
#include "absl/time/time.h"
@@ -111,7 +112,8 @@
ABSL_CONST_INIT absl::base_internal::AtomicHook<
void (*)(const char *msg, const void *cv)> cond_var_tracer;
ABSL_CONST_INIT absl::base_internal::AtomicHook<
- bool (*)(const void *pc, char *out, int out_size)> symbolizer;
+ bool (*)(const void *pc, char *out, int out_size)>
+ symbolizer(absl::Symbolize);
} // namespace
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index c4e026f..368684b 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -979,6 +979,12 @@
// to 'out.'
//
// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+//
+// DEPRECATED: The default symbolizer function is absl::Symbolize() and the
+// ability to register a different hook for symbolizing stack traces will be
+// removed on or after 2023-05-01.
+ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed "
+ "on or after 2023-05-01")
void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
// EnableMutexInvariantDebugging()
diff --git a/third_party/abseil-cpp/absl/time/BUILD.bazel b/third_party/abseil-cpp/absl/time/BUILD.bazel
index d4f653f..7126f14 100644
--- a/third_party/abseil-cpp/absl/time/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/time/BUILD.bazel
@@ -51,6 +51,7 @@
cc_library(
name = "test_util",
+ testonly = 1,
srcs = [
"internal/test_util.cc",
"internal/zoneinfo.inc",
@@ -64,6 +65,7 @@
":time",
"//absl/base",
"//absl/time/internal/cctz:time_zone",
+ "@com_google_googletest//:gtest",
],
)
diff --git a/third_party/abseil-cpp/absl/time/BUILD.gn b/third_party/abseil-cpp/absl/time/BUILD.gn
index d440aaa..9f728f4 100644
--- a/third_party/abseil-cpp/absl/time/BUILD.gn
+++ b/third_party/abseil-cpp/absl/time/BUILD.gn
@@ -45,6 +45,7 @@
}
source_set("test_util") {
+ testonly = true
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
@@ -62,6 +63,8 @@
":time",
"../base",
"../time/internal/cctz:time_zone",
+ "//testing/gtest",
+ "//testing/gmock",
]
visibility = []
visibility += [ "../time:*" ]
diff --git a/third_party/abseil-cpp/absl/time/format_test.cc b/third_party/abseil-cpp/absl/time/format_test.cc
index 09d1fe6..7c84c33 100644
--- a/third_party/abseil-cpp/absl/time/format_test.cc
+++ b/third_party/abseil-cpp/absl/time/format_test.cc
@@ -155,8 +155,7 @@
"2013-06-28 19:08:09 -0800", &t, &err))
<< err;
absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false,
- "UTC-8");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
}
@@ -179,8 +178,7 @@
absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
<< e;
absl::Time::Breakdown bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true,
- "PDT");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
// But the timezone is ignored when a UTC offset is present.
@@ -188,8 +186,7 @@
"2013-06-28 19:08:09 +0800", tz, &t, &e))
<< e;
bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false,
- "UTC+8");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
}
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel b/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel
index fe17b3e..468470b 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel
@@ -80,6 +80,7 @@
name = "time_zone_format_test",
size = "small",
srcs = ["src/time_zone_format_test.cc"],
+ data = [":zoneinfo"],
deps = [
":civil_time",
":time_zone",
@@ -91,6 +92,7 @@
name = "time_zone_lookup_test",
size = "small",
srcs = ["src/time_zone_lookup_test.cc"],
+ data = [":zoneinfo"],
deps = [
":civil_time",
":time_zone",
@@ -103,3 +105,8 @@
### examples
### binaries
+
+filegroup(
+ name = "zoneinfo",
+ srcs = glob(["testdata/zoneinfo/**"]),
+)
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index 4c39c7d..d52eddc 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -20,8 +20,8 @@
#include <ostream>
#include <type_traits>
-// Disable constexpr support unless we are using clang in C++14 mode.
-#if __clang__ && __cpp_constexpr >= 201304
+// Disable constexpr support unless we are in C++14 mode.
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
#define CONSTEXPR_D constexpr // data
#define CONSTEXPR_F constexpr // function
#define CONSTEXPR_M constexpr // member
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc
index 6df0395..f6648c8 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc
@@ -37,7 +37,7 @@
} // namespace
-#if __clang__ && __cpp_constexpr >= 201304
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
// Construction constexpr tests
TEST(CivilTime, Normal) {
@@ -319,7 +319,7 @@
constexpr int yd = get_yearday(cd);
static_assert(yd == 28, "YearDay");
}
-#endif // __clang__ && __cpp_constexpr >= 201304
+#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910
// The remaining tests do not use constexpr.
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc
index 8d3b144..65eba35 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -27,7 +27,7 @@
namespace {
// The prefix used for the internal names of fixed-offset zones.
-const char kFixedOffsetPrefix[] = "Fixed/";
+const char kFixedOffsetPrefix[] = "Fixed/UTC";
int Parse02d(const char* p) {
static const char kDigits[] = "0123456789";
@@ -50,13 +50,11 @@
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
const char* const ep = kFixedOffsetPrefix + prefix_len;
- if (name.size() != prefix_len + 12) // "<prefix>UTC+99:99:99"
+ if (name.size() != prefix_len + 9) // <prefix>+99:99:99
return false;
if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
return false;
const char* np = name.data() + prefix_len;
- if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
- return false;
if (np[0] != '+' && np[0] != '-')
return false;
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
@@ -97,8 +95,8 @@
}
int hours = minutes / 60;
minutes %= 60;
- char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
- snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
+ char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")];
+ snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d",
kFixedOffsetPrefix, sign, hours, minutes, seconds);
return buf;
}
@@ -106,22 +104,14 @@
std::string FixedOffsetToAbbr(const sys_seconds& offset) {
std::string abbr = FixedOffsetToName(offset);
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
- const char* const ep = kFixedOffsetPrefix + prefix_len;
- if (abbr.size() >= prefix_len) {
- if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
- abbr.erase(0, prefix_len);
- if (abbr.size() == 12) { // UTC+99:99:99
- abbr.erase(9, 1); // UTC+99:9999
- abbr.erase(6, 1); // UTC+999999
- if (abbr[8] == '0' && abbr[9] == '0') { // UTC+999900
- abbr.erase(8, 2); // UTC+9999
- if (abbr[6] == '0' && abbr[7] == '0') { // UTC+9900
- abbr.erase(6, 2); // UTC+99
- if (abbr[4] == '0') { // UTC+09
- abbr.erase(4, 1); // UTC+9
- }
- }
- }
+ if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
+ abbr.erase(0, prefix_len); // +99:99:99
+ abbr.erase(6, 1); // +99:9999
+ abbr.erase(3, 1); // +999999
+ if (abbr[5] == '0' && abbr[6] == '0') { // +999900
+ abbr.erase(5, 2); // +9999
+ if (abbr[3] == '0' && abbr[4] == '0') { // +9900
+ abbr.erase(3, 2); // +99
}
}
}
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
index fbd86e1..d549d86 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -134,6 +134,9 @@
time_zone tz;
load_time_zone(name, &tz); // Falls back to UTC.
+ // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+ // arrange for %z to generate "-0000" when we don't know the local
+ // offset because the load_time_zone() failed and we're using UTC.
return tz;
}
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index a5d73d5..f97eab0 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -415,7 +415,6 @@
"CST6CDT",
"Canada/Atlantic",
"Canada/Central",
- "Canada/East-Saskatchewan",
"Canada/Eastern",
"Canada/Mountain",
"Canada/Newfoundland",
@@ -1119,18 +1118,6 @@
auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
tp += seconds(1);
-#ifndef TZDATA_2017B_IS_UBIQUITOUS
- // The 2017b tzdata release moved the shift from -004430 to +00
- // from 1972-05-01 to 1972-01-07, so we temporarily accept both
- // outcomes until 2017b is ubiquitous.
- if (tz.lookup(tp).offset == -44.5 * 60) {
- tp = convert(civil_second(1972, 4, 30, 23, 59, 59), tz);
- ExpectTime(tp, tz, 1972, 4, 30, 23, 59, 59, -44.5 * 60, false, "LRT");
- tp += seconds(1);
- ExpectTime(tp, tz, 1972, 5, 1, 0, 44, 30, 0 * 60, false, "GMT");
- return;
- }
-#endif
ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
}
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version
index 05c3ec2..fe86b5c 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2018d-2-g8d1dac0
+2018e-2-g99dd695
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
index 358f11e..f5d40ba 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
index de5c2b1..dc24926 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
index 4eabe5c..ba82f31 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
index 4eabe5c..ba82f31 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/third_party/abseil-cpp/absl/time/internal/test_util.cc b/third_party/abseil-cpp/absl/time/internal/test_util.cc
index 4483f2a..bbbef7d 100644
--- a/third_party/abseil-cpp/absl/time/internal/test_util.cc
+++ b/third_party/abseil-cpp/absl/time/internal/test_util.cc
@@ -26,6 +26,12 @@
namespace absl {
namespace time_internal {
+#if GTEST_USES_SIMPLE_RE
+extern const char kZoneAbbrRE[] = ".*"; // just punt
+#else
+extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
+#endif
+
TimeZone LoadTimeZone(const std::string& name) {
TimeZone tz;
ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
diff --git a/third_party/abseil-cpp/absl/time/internal/test_util.h b/third_party/abseil-cpp/absl/time/internal/test_util.h
index 81a2d29..8fd5fb9 100644
--- a/third_party/abseil-cpp/absl/time/internal/test_util.h
+++ b/third_party/abseil-cpp/absl/time/internal/test_util.h
@@ -17,6 +17,8 @@
#include <string>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "absl/time/time.h"
// This helper is a macro so that failed expectations show up with the
@@ -24,22 +26,26 @@
//
// This is for internal testing of the Base Time library itself. This is not
// part of a public API.
-#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst, zone) \
- do { \
- EXPECT_EQ(y, bd.year); \
- EXPECT_EQ(m, bd.month); \
- EXPECT_EQ(d, bd.day); \
- EXPECT_EQ(h, bd.hour); \
- EXPECT_EQ(min, bd.minute); \
- EXPECT_EQ(s, bd.second); \
- EXPECT_EQ(off, bd.offset); \
- EXPECT_EQ(isdst, bd.is_dst); \
- EXPECT_STREQ(zone, bd.zone_abbr); \
+#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \
+ do { \
+ EXPECT_EQ(y, bd.year); \
+ EXPECT_EQ(m, bd.month); \
+ EXPECT_EQ(d, bd.day); \
+ EXPECT_EQ(h, bd.hour); \
+ EXPECT_EQ(min, bd.minute); \
+ EXPECT_EQ(s, bd.second); \
+ EXPECT_EQ(off, bd.offset); \
+ EXPECT_EQ(isdst, bd.is_dst); \
+ EXPECT_THAT(bd.zone_abbr, \
+ testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \
} while (0)
namespace absl {
namespace time_internal {
+// A regular expression that matches all zone abbreviations (%Z).
+extern const char kZoneAbbrRE[];
+
// Loads the named timezone, but dies on any failure.
absl::TimeZone LoadTimeZone(const std::string& name);
diff --git a/third_party/abseil-cpp/absl/time/time.cc b/third_party/abseil-cpp/absl/time/time.cc
index 1dde40d..03720f6 100644
--- a/third_party/abseil-cpp/absl/time/time.cc
+++ b/third_party/abseil-cpp/absl/time/time.cc
@@ -71,7 +71,7 @@
bd.yearday = 365;
bd.offset = 0;
bd.is_dst = false;
- bd.zone_abbr = "-0000";
+ bd.zone_abbr = "-00";
return bd;
}
@@ -88,7 +88,7 @@
bd.yearday = 1;
bd.offset = 0;
bd.is_dst = false;
- bd.zone_abbr = "-0000";
+ bd.zone_abbr = "-00";
return bd;
}
diff --git a/third_party/abseil-cpp/absl/time/time_norm_test.cc b/third_party/abseil-cpp/absl/time/time_norm_test.cc
index 005756e..4436242 100644
--- a/third_party/abseil-cpp/absl/time/time_norm_test.cc
+++ b/third_party/abseil-cpp/absl/time/time_norm_test.cc
@@ -18,6 +18,7 @@
#include <cstdint>
#include <limits>
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/time/internal/test_util.h"
#include "absl/time/time.h"
@@ -32,31 +33,31 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false);
}
TEST(TimeNormCase, SimpleUnderflow) {
@@ -66,31 +67,31 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false);
tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false);
tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false);
tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false);
tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false);
}
TEST(TimeNormCase, MultipleOverflow) {
@@ -99,7 +100,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false);
}
TEST(TimeNormCase, MultipleUnderflow) {
@@ -108,7 +109,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false);
}
TEST(TimeNormCase, OverflowLimits) {
@@ -122,7 +123,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false);
const int kintmin = std::numeric_limits<int>::min();
tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
@@ -130,8 +131,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false,
- "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false);
const int64_t max_year = std::numeric_limits<int64_t>::max();
tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
@@ -154,31 +154,31 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false);
}
TEST(TimeNormCase, ComplexUnderflow) {
@@ -189,37 +189,37 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false);
tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false);
}
TEST(TimeNormCase, Mishmash) {
@@ -231,14 +231,14 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false);
tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
32 - 1234567, 14 + 123456789, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false);
// Here is a normalization case we got wrong for a while. Because the
// day is converted to "1" within a 400-year (146097-day) period, we
@@ -247,7 +247,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false);
// Even though the month overflow compensates for the day underflow,
// this should still be marked as normalized.
@@ -255,7 +255,7 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false);
}
TEST(TimeNormCase, LeapYears) {
@@ -266,25 +266,25 @@
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
absl::Time::Breakdown bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false);
tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
EXPECT_FALSE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false);
tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
EXPECT_FALSE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false);
tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
EXPECT_TRUE(tc.normalized);
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
bd = tc.pre.In(utc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false);
}
// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
diff --git a/third_party/abseil-cpp/absl/time/time_test.cc b/third_party/abseil-cpp/absl/time/time_test.cc
index 6408388..4f8f58a 100644
--- a/third_party/abseil-cpp/absl/time/time_test.cc
+++ b/third_party/abseil-cpp/absl/time/time_test.cc
@@ -85,7 +85,7 @@
TEST(Time, UnixEpoch) {
absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
- ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
EXPECT_EQ(4, bd.weekday); // Thursday
}
@@ -96,14 +96,14 @@
// The Unix epoch as seen in NYC.
absl::Time::Breakdown bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false, "EST");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
EXPECT_EQ(3, bd.weekday); // Wednesday
// Just before the epoch.
t -= absl::Nanoseconds(1);
bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false, "EST");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false);
EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
EXPECT_EQ(3, bd.weekday); // Wednesday
@@ -112,7 +112,7 @@
t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
absl::Nanoseconds(9);
bd = t.In(tz);
- ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true, "EDT");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true);
EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
EXPECT_EQ(2, bd.weekday); // Tuesday
}
@@ -983,16 +983,18 @@
// Checks how Time::In() saturates on infinities.
absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
- 59, 59, 0, false, "-0000");
+ 59, 59, 0, false);
EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
EXPECT_EQ(4, bd.weekday); // Thursday
EXPECT_EQ(365, bd.yearday);
+ EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
bd = absl::InfinitePast().In(utc);
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
- 0, 0, false, "-0000");
+ 0, 0, false);
EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
EXPECT_EQ(7, bd.weekday); // Sunday
EXPECT_EQ(1, bd.yearday);
+ EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
// Approach the maximal Time value from below.
t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
@@ -1054,13 +1056,11 @@
// The maximal time converted in each zone.
bd = max.In(syd);
- ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true,
- "AEDT");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true);
t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
EXPECT_EQ(max, t);
bd = max.In(nyc);
- ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false,
- "EST");
+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false);
t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
EXPECT_EQ(max, t);
diff --git a/third_party/abseil-cpp/absl/types/BUILD.bazel b/third_party/abseil-cpp/absl/types/BUILD.bazel
index 0bdb2f7..f8d53c2 100644
--- a/third_party/abseil-cpp/absl/types/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/types/BUILD.bazel
@@ -223,3 +223,18 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_test(
+ name = "variant_exception_safety_test",
+ size = "small",
+ srcs = [
+ "variant_exception_safety_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":variant",
+ "//absl/base:exception_safety_testing",
+ "//absl/memory",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/third_party/abseil-cpp/absl/types/CMakeLists.txt b/third_party/abseil-cpp/absl/types/CMakeLists.txt
index f51d126..fbd8374 100644
--- a/third_party/abseil-cpp/absl/types/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/types/CMakeLists.txt
@@ -29,6 +29,9 @@
TARGET
absl_any
PUBLIC_LIBRARIES
+ absl::bad_any_cast
+ absl::base
+ absl::meta
absl::utility
PRIVATE_COMPILE_FLAGS
${ABSL_EXCEPTIONS_FLAG}
@@ -59,7 +62,6 @@
SOURCES
${BAD_ANY_CAST_SRC}
PUBLIC_LIBRARIES
- absl::base absl::any
EXPORT_NAME
bad_any_cast
)
@@ -76,7 +78,11 @@
SOURCES
${OPTIONAL_SRC}
PUBLIC_LIBRARIES
+ absl::bad_optional_access
absl::base
+ absl::memory
+ absl::meta
+ absl::utility
EXPORT_NAME
optional
)
@@ -143,7 +149,11 @@
# test any_exception_safety_test
set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
-set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES absl::any absl::base absl::base_internal_exception_safety_testing)
+set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+ absl::any
+ absl::base
+ absl_base_internal_exception_safety_testing
+)
absl_test(
TARGET
diff --git a/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc b/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc
index 82c176b..36955f6 100644
--- a/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc
+++ b/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc
@@ -20,21 +20,16 @@
#include "gtest/gtest.h"
#include "absl/base/internal/exception_safety_testing.h"
-using Thrower = absl::ThrowingValue<>;
+using Thrower = testing::ThrowingValue<>;
using NoThrowMoveThrower =
- absl::ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign>;
+ testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
using ThrowerList = std::initializer_list<Thrower>;
using ThrowerVec = std::vector<Thrower>;
-using ThrowingAlloc = absl::ThrowingAllocator<Thrower>;
+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
namespace {
-class AnyExceptionSafety : public ::testing::Test {
- private:
- absl::ConstructorTracker inspector_;
-};
-
testing::AssertionResult AnyInvariants(absl::any* a) {
using testing::AssertionFailure;
using testing::AssertionSuccess;
@@ -84,30 +79,33 @@
<< absl::any_cast<Thrower>(*a).Get();
}
-TEST_F(AnyExceptionSafety, Ctors) {
+TEST(AnyExceptionSafety, Ctors) {
Thrower val(1);
- auto with_val = absl::TestThrowingCtor<absl::any>(val);
- auto copy = absl::TestThrowingCtor<absl::any>(with_val);
- auto in_place =
- absl::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
- auto in_place_list = absl::TestThrowingCtor<absl::any>(
- absl::in_place_type_t<ThrowerVec>(), ThrowerList{val});
- auto in_place_list_again =
- absl::TestThrowingCtor<absl::any,
- absl::in_place_type_t<ThrowingThrowerVec>,
- ThrowerList, ThrowingAlloc>(
- absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
+ testing::TestThrowingCtor<absl::any>(val);
+
+ Thrower copy(val);
+ testing::TestThrowingCtor<absl::any>(copy);
+
+ testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
+
+ testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(),
+ ThrowerList{val});
+
+ testing::TestThrowingCtor<absl::any,
+ absl::in_place_type_t<ThrowingThrowerVec>,
+ ThrowerList, ThrowingAlloc>(
+ absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
}
-TEST_F(AnyExceptionSafety, Assignment) {
+TEST(AnyExceptionSafety, Assignment) {
auto original =
- absl::any(absl::in_place_type_t<Thrower>(), 1, absl::no_throw_ctor);
+ absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor);
auto any_is_strong = [original](absl::any* ap) {
return testing::AssertionResult(ap->has_value() &&
absl::any_cast<Thrower>(original) ==
absl::any_cast<Thrower>(*ap));
};
- auto any_strong_tester = absl::MakeExceptionSafetyTester()
+ auto any_strong_tester = testing::MakeExceptionSafetyTester()
.WithInitialValue(original)
.WithInvariants(AnyInvariants, any_is_strong);
@@ -129,7 +127,7 @@
return testing::AssertionResult{!ap->has_value()};
};
auto strong_empty_any_tester =
- absl::MakeExceptionSafetyTester()
+ testing::MakeExceptionSafetyTester()
.WithInitialValue(absl::any{})
.WithInvariants(AnyInvariants, empty_any_is_strong);
@@ -139,16 +137,16 @@
}
// libstdc++ std::any fails this test
#if !defined(ABSL_HAVE_STD_ANY)
-TEST_F(AnyExceptionSafety, Emplace) {
+TEST(AnyExceptionSafety, Emplace) {
auto initial_val =
- absl::any{absl::in_place_type_t<Thrower>(), 1, absl::no_throw_ctor};
- auto one_tester = absl::MakeExceptionSafetyTester()
+ absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor};
+ auto one_tester = testing::MakeExceptionSafetyTester()
.WithInitialValue(initial_val)
.WithInvariants(AnyInvariants, AnyIsEmpty);
auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
auto emp_throwervec = [](absl::any* ap) {
- std::initializer_list<Thrower> il{Thrower(2, absl::no_throw_ctor)};
+ std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)};
ap->emplace<ThrowerVec>(il);
};
auto emp_movethrower = [](absl::any* ap) {
diff --git a/third_party/abseil-cpp/absl/types/optional.h b/third_party/abseil-cpp/absl/types/optional.h
index 98b29e5..80a2d14 100644
--- a/third_party/abseil-cpp/absl/types/optional.h
+++ b/third_party/abseil-cpp/absl/types/optional.h
@@ -776,10 +776,13 @@
// `optional` is empty, behavior is undefined.
//
// If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
- const T* operator->() const { return this->pointer(); }
+ const T* operator->() const {
+ assert(this->engaged_);
+ return std::addressof(this->data_);
+ }
T* operator->() {
assert(this->engaged_);
- return this->pointer();
+ return std::addressof(this->data_);
}
// optional::operator*()
@@ -817,6 +820,12 @@
// only if `*this` is empty.
constexpr bool has_value() const noexcept { return this->engaged_; }
+// Suppress bogus warning on MSVC: MSVC complains call to reference() after
+// throw_bad_optional_access() is unreachable.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4702)
+#endif // _MSC_VER
// optional::value()
//
// Returns a reference to an `optional`s underlying value. The constness
@@ -845,6 +854,9 @@
? reference()
: (optional_internal::throw_bad_optional_access(), reference()));
}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
// optional::value_or()
//
@@ -871,10 +883,6 @@
}
private:
- // Private accessors for internal storage viewed as pointer to T.
- const T* pointer() const { return std::addressof(this->data_); }
- T* pointer() { return std::addressof(this->data_); }
-
// Private accessors for internal storage viewed as reference to T.
constexpr const T& reference() const { return this->data_; }
T& reference() { return this->data_; }
@@ -958,7 +966,8 @@
-> decltype(optional_internal::convertible_to_bool(*x == *y)) {
return static_cast<bool>(x) != static_cast<bool>(y)
? false
- : static_cast<bool>(x) == false ? true : *x == *y;
+ : static_cast<bool>(x) == false ? true
+ : static_cast<bool>(*x == *y);
}
// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
@@ -968,31 +977,32 @@
-> decltype(optional_internal::convertible_to_bool(*x != *y)) {
return static_cast<bool>(x) != static_cast<bool>(y)
? true
- : static_cast<bool>(x) == false ? false : *x != *y;
+ : static_cast<bool>(x) == false ? false
+ : static_cast<bool>(*x != *y);
}
// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
template <typename T, typename U>
constexpr auto operator<(const optional<T>& x, const optional<U>& y)
-> decltype(optional_internal::convertible_to_bool(*x < *y)) {
- return !y ? false : !x ? true : *x < *y;
+ return !y ? false : !x ? true : static_cast<bool>(*x < *y);
}
// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
template <typename T, typename U>
constexpr auto operator>(const optional<T>& x, const optional<U>& y)
-> decltype(optional_internal::convertible_to_bool(*x > *y)) {
- return !x ? false : !y ? true : *x > *y;
+ return !x ? false : !y ? true : static_cast<bool>(*x > *y);
}
// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
template <typename T, typename U>
constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
-> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
- return !x ? true : !y ? false : *x <= *y;
+ return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
}
// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
template <typename T, typename U>
constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
-> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
- return !y ? true : !x ? false : *x >= *y;
+ return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
}
// Comparison with nullopt [optional.nullops]
@@ -1054,62 +1064,62 @@
template <typename T, typename U>
constexpr auto operator==(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x == v)) {
- return static_cast<bool>(x) ? *x == v : false;
+ return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
}
template <typename T, typename U>
constexpr auto operator==(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v == *x)) {
- return static_cast<bool>(x) ? v == *x : false;
+ return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
}
template <typename T, typename U>
constexpr auto operator!=(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x != v)) {
- return static_cast<bool>(x) ? *x != v : true;
+ return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
}
template <typename T, typename U>
constexpr auto operator!=(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v != *x)) {
- return static_cast<bool>(x) ? v != *x : true;
+ return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
}
template <typename T, typename U>
constexpr auto operator<(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x < v)) {
- return static_cast<bool>(x) ? *x < v : true;
+ return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
}
template <typename T, typename U>
constexpr auto operator<(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v < *x)) {
- return static_cast<bool>(x) ? v < *x : false;
+ return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
}
template <typename T, typename U>
constexpr auto operator<=(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x <= v)) {
- return static_cast<bool>(x) ? *x <= v : true;
+ return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
}
template <typename T, typename U>
constexpr auto operator<=(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v <= *x)) {
- return static_cast<bool>(x) ? v <= *x : false;
+ return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
}
template <typename T, typename U>
constexpr auto operator>(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x > v)) {
- return static_cast<bool>(x) ? *x > v : false;
+ return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
}
template <typename T, typename U>
constexpr auto operator>(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v > *x)) {
- return static_cast<bool>(x) ? v > *x : true;
+ return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
}
template <typename T, typename U>
constexpr auto operator>=(const optional<T>& x, const U& v)
-> decltype(optional_internal::convertible_to_bool(*x >= v)) {
- return static_cast<bool>(x) ? *x >= v : false;
+ return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
}
template <typename T, typename U>
constexpr auto operator>=(const U& v, const optional<T>& x)
-> decltype(optional_internal::convertible_to_bool(v >= *x)) {
- return static_cast<bool>(x) ? v >= *x : true;
+ return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
}
} // namespace absl
diff --git a/third_party/abseil-cpp/absl/types/span.h b/third_party/abseil-cpp/absl/types/span.h
index d365f17..f781353 100644
--- a/third_party/abseil-cpp/absl/types/span.h
+++ b/third_party/abseil-cpp/absl/types/span.h
@@ -290,7 +290,8 @@
constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
: Span(a, N) {}
- // Explicit reference constructor for a mutable `Span<T>` type
+ // Explicit reference constructor for a mutable `Span<T>` type. Can be
+ // replaced with MakeSpan() to infer the type parameter.
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfMutableView<V>>
explicit Span(V& v) noexcept // NOLINT(runtime/references)
@@ -458,10 +459,20 @@
// Span::subspan()
//
- // Returns a `Span` starting at element `pos` and of length `len`, with
- // proper bounds checking to ensure `len` does not exceed the ptr+size of the
- // original array. (Spans whose `len` would point past the end of the array
- // will throw a `std::out_of_range`.)
+ // Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
+ // and `len` are of type `size_type` and thus non-negative. Parameter `pos`
+ // must be <= size(). Any `len` value that points past the end of the span
+ // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
+ // ensures the returned subspan continues until the end of the span.
+ //
+ // Examples:
+ //
+ // std::vector<int> vec = {10, 11, 12, 13};
+ // absl::MakeSpan(vec).subspan(1, 2); // {11, 12}
+ // absl::MakeSpan(vec).subspan(2, 8); // {12, 13}
+ // absl::MakeSpan(vec).subspan(1); // {11, 12, 13}
+ // absl::MakeSpan(vec).subspan(4); // {}
+ // absl::MakeSpan(vec).subspan(5); // throws std::out_of_range
constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
return (pos <= len_)
? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
diff --git a/third_party/abseil-cpp/absl/types/variant.h b/third_party/abseil-cpp/absl/types/variant.h
index 52a311e..7ae65ab 100644
--- a/third_party/abseil-cpp/absl/types/variant.h
+++ b/third_party/abseil-cpp/absl/types/variant.h
@@ -350,7 +350,7 @@
// get_if()
//
// Returns a pointer to the value currently stored within a given variant, if
-// present, using either a unique alternative type amonst the variant's set of
+// present, using either a unique alternative type amongst the variant's set of
// alternative types, or the variant's index value. If such a value does not
// exist, returns `nullptr`.
//
diff --git a/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc b/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc
new file mode 100644
index 0000000..377e4af
--- /dev/null
+++ b/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc
@@ -0,0 +1,519 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/types/variant.h"
+
+#include <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+namespace {
+
+using ::testing::MakeExceptionSafetyTester;
+using ::testing::nothrow_guarantee;
+using ::testing::strong_guarantee;
+using ::testing::TestThrowingCtor;
+
+using Thrower = testing::ThrowingValue<>;
+using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
+using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
+using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
+using ThrowingVariant =
+ absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
+
+struct ConversionException {};
+
+template <class T>
+struct ExceptionOnConversion {
+ operator T() const { // NOLINT
+ throw ConversionException();
+ }
+};
+
+// Forces a variant into the valueless by exception state.
+void ToValuelessByException(ThrowingVariant& v) { // NOLINT
+ try {
+ v.emplace<Thrower>();
+ v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
+ } catch (ConversionException& /*e*/) {
+ // This space intentionally left blank.
+ }
+}
+
+// Check that variant is still in a usable state after an exception is thrown.
+testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
+ using testing::AssertionFailure;
+ using testing::AssertionSuccess;
+
+ // Try using the active alternative
+ if (absl::holds_alternative<Thrower>(*v)) {
+ auto& t = absl::get<Thrower>(*v);
+ t = Thrower{-100};
+ if (t.Get() != -100) {
+ return AssertionFailure() << "Thrower should be assigned -100";
+ }
+ } else if (absl::holds_alternative<ThrowerVec>(*v)) {
+ auto& tv = absl::get<ThrowerVec>(*v);
+ tv.clear();
+ tv.emplace_back(-100);
+ if (tv.size() != 1 || tv[0].Get() != -100) {
+ return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
+ }
+ } else if (absl::holds_alternative<CopyNothrow>(*v)) {
+ auto& t = absl::get<CopyNothrow>(*v);
+ t = CopyNothrow{-100};
+ if (t.Get() != -100) {
+ return AssertionFailure() << "CopyNothrow should be assigned -100";
+ }
+ } else if (absl::holds_alternative<MoveNothrow>(*v)) {
+ auto& t = absl::get<MoveNothrow>(*v);
+ t = MoveNothrow{-100};
+ if (t.Get() != -100) {
+ return AssertionFailure() << "MoveNothrow should be assigned -100";
+ }
+ }
+
+ // Try making variant valueless_by_exception
+ if (!v->valueless_by_exception()) ToValuelessByException(*v);
+ if (!v->valueless_by_exception()) {
+ return AssertionFailure() << "Variant should be valueless_by_exception";
+ }
+ try {
+ auto unused = absl::get<Thrower>(*v);
+ static_cast<void>(unused);
+ return AssertionFailure() << "Variant should not contain Thrower";
+ } catch (absl::bad_variant_access) {
+ } catch (...) {
+ return AssertionFailure() << "Unexpected exception throw from absl::get";
+ }
+
+ // Try using the variant
+ v->emplace<Thrower>(100);
+ if (!absl::holds_alternative<Thrower>(*v) ||
+ absl::get<Thrower>(*v) != Thrower(100)) {
+ return AssertionFailure() << "Variant should contain Thrower(100)";
+ }
+ v->emplace<ThrowerVec>({Thrower(100)});
+ if (!absl::holds_alternative<ThrowerVec>(*v) ||
+ absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
+ return AssertionFailure()
+ << "Variant should contain ThrowerVec{Thrower(100)}";
+ }
+ return AssertionSuccess();
+}
+
+Thrower ExpectedThrower() { return Thrower(42); }
+ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
+ThrowingVariant ValuelessByException() {
+ ThrowingVariant v;
+ ToValuelessByException(v);
+ return v;
+}
+ThrowingVariant WithThrower() { return Thrower(39); }
+ThrowingVariant WithThrowerVec() {
+ return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
+}
+ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
+ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
+
+TEST(VariantExceptionSafetyTest, DefaultConstructor) {
+ TestThrowingCtor<ThrowingVariant>();
+}
+
+TEST(VariantExceptionSafetyTest, CopyConstructor) {
+ {
+ ThrowingVariant v(ExpectedThrower());
+ TestThrowingCtor<ThrowingVariant>(v);
+ }
+ {
+ ThrowingVariant v(ExpectedThrowerVec());
+ TestThrowingCtor<ThrowingVariant>(v);
+ }
+ {
+ ThrowingVariant v(ValuelessByException());
+ TestThrowingCtor<ThrowingVariant>(v);
+ }
+}
+
+TEST(VariantExceptionSafetyTest, MoveConstructor) {
+ {
+ ThrowingVariant v(ExpectedThrower());
+ TestThrowingCtor<ThrowingVariant>(std::move(v));
+ }
+ {
+ ThrowingVariant v(ExpectedThrowerVec());
+ TestThrowingCtor<ThrowingVariant>(std::move(v));
+ }
+ {
+ ThrowingVariant v(ValuelessByException());
+ TestThrowingCtor<ThrowingVariant>(std::move(v));
+ }
+}
+
+TEST(VariantExceptionSafetyTest, ValueConstructor) {
+ TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
+ TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
+ TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
+ ExpectedThrower());
+ TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
+ ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
+ TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
+ ExpectedThrower());
+ TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
+ ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, CopyAssign) {
+ // variant& operator=(const variant& rhs);
+ // Let j be rhs.index()
+ {
+ // - neither *this nor rhs holds a value
+ const ThrowingVariant rhs = ValuelessByException();
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(ValuelessByException())
+ .WithInvariants(nothrow_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+ {
+ // - *this holds a value but rhs does not
+ const ThrowingVariant rhs = ValuelessByException();
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(nothrow_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+ // - index() == j
+ {
+ const ThrowingVariant rhs(ExpectedThrower());
+ auto tester =
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+ EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+ }
+ {
+ const ThrowingVariant rhs(ExpectedThrowerVec());
+ auto tester =
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrowerVec())
+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+ EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+ }
+ // libstdc++ std::variant has bugs on copy assignment regarding exception
+ // safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+ // index() != j
+ // if is_nothrow_copy_constructible_v<Tj> or
+ // !is_nothrow_move_constructible<Tj> is true, equivalent to
+ // emplace<j>(get<j>(rhs))
+ {
+ // is_nothrow_copy_constructible_v<Tj> == true
+ // should not throw because emplace() invokes Tj's copy ctor
+ // which should not throw.
+ const ThrowingVariant rhs(CopyNothrow{});
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(nothrow_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+ {
+ // is_nothrow_copy_constructible<Tj> == false &&
+ // is_nothrow_move_constructible<Tj> == false
+ // should provide basic guarantee because emplace() invokes Tj's copy ctor
+ // which may throw.
+ const ThrowingVariant rhs(ExpectedThrower());
+ auto tester =
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithCopyNoThrow())
+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+ EXPECT_TRUE(tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return lhs->valueless_by_exception();
+ })
+ .Test());
+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+ }
+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+ {
+ // is_nothrow_copy_constructible_v<Tj> == false &&
+ // is_nothrow_move_constructible_v<Tj> == true
+ // should provide strong guarantee because it is equivalent to
+ // operator=(variant(rhs)) which creates a temporary then invoke the move
+ // ctor which shouldn't throw.
+ const ThrowingVariant rhs(MoveNothrow{});
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(CheckInvariants, strong_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+}
+
+TEST(VariantExceptionSafetyTest, MoveAssign) {
+ // variant& operator=(variant&& rhs);
+ // Let j be rhs.index()
+ {
+ // - neither *this nor rhs holds a value
+ ThrowingVariant rhs = ValuelessByException();
+
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(ValuelessByException())
+ .WithInvariants(nothrow_guarantee)
+ .Test([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ }));
+ }
+ {
+ // - *this holds a value but rhs does not
+ ThrowingVariant rhs = ValuelessByException();
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(nothrow_guarantee)
+ .Test([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ }));
+ }
+ {
+ // - index() == j
+ // assign get<j>(std::move(rhs)) to the value contained in *this.
+ // If an exception is thrown during call to Tj's move assignment, the state
+ // of the contained value is as defined by the exception safety guarantee of
+ // Tj's move assignment; index() will be j.
+ ThrowingVariant rhs(ExpectedThrower());
+ size_t j = rhs.index();
+ // Since Thrower's move assignment has basic guarantee, so should variant's.
+ auto tester = MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ });
+ EXPECT_TRUE(tester
+ .WithInvariants(
+ CheckInvariants,
+ [j](ThrowingVariant* lhs) { return lhs->index() == j; })
+ .Test());
+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+ }
+ {
+ // - otherwise (index() != j), equivalent to
+ // emplace<j>(get<j>(std::move(rhs)))
+ // - If an exception is thrown during the call to Tj's move construction
+ // (with j being rhs.index()), the variant will hold no value.
+ ThrowingVariant rhs(CopyNothrow{});
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return lhs->valueless_by_exception();
+ })
+ .Test([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ }));
+ }
+}
+
+TEST(VariantExceptionSafetyTest, ValueAssign) {
+ // template<class T> variant& operator=(T&& t);
+ // Let Tj be the type that is selected by overload resolution to be assigned.
+ {
+ // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
+ // *this. If an exception is thrown during the assignment of
+ // std::forward<T>(t) to the value contained in *this, the state of the
+ // contained value and t are as defined by the exception safety guarantee of
+ // the assignment expression; valueless_by_exception() will be false.
+ // Since Thrower's copy/move assignment has basic guarantee, so should
+ // variant's.
+ Thrower rhs = ExpectedThrower();
+ // copy assign
+ auto copy_tester =
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+ EXPECT_TRUE(copy_tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return !lhs->valueless_by_exception();
+ })
+ .Test());
+ EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+ // move assign
+ auto move_tester = MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ });
+ EXPECT_TRUE(move_tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return !lhs->valueless_by_exception();
+ })
+ .Test());
+
+ EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+ }
+ // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
+ // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
+ // emplace<j>(std::forward<T>(t)).
+ // We simplify the test by letting T = `const Tj&` or `Tj&&`, so we can reuse
+ // the CopyNothrow and MoveNothrow types.
+
+ // if is_nothrow_constructible_v<Tj, T>
+ // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
+ // invokes the copy/move constructor and it should not throw.
+ {
+ const CopyNothrow rhs;
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(nothrow_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+ {
+ MoveNothrow rhs;
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(nothrow_guarantee)
+ .Test([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ }));
+ }
+ // if is_nothrow_constructible_v<Tj, T> == false &&
+ // is_nothrow_move_constructible<Tj> == false
+ // emplace() invokes the copy/move constructor which may throw so it should
+ // provide basic guarantee and variant object might not hold a value.
+ {
+ Thrower rhs = ExpectedThrower();
+ // copy
+ auto copy_tester =
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithCopyNoThrow())
+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+ EXPECT_TRUE(copy_tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return lhs->valueless_by_exception();
+ })
+ .Test());
+ EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+ // move
+ auto move_tester = MakeExceptionSafetyTester()
+ .WithInitialValue(WithCopyNoThrow())
+ .WithOperation([rhs](ThrowingVariant* lhs) mutable {
+ *lhs = std::move(rhs);
+ });
+ EXPECT_TRUE(move_tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* lhs) {
+ return lhs->valueless_by_exception();
+ })
+ .Test());
+ EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+ }
+ // Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
+ // is_nothrow_move_constructible<Tj> == true),
+ // equivalent to operator=(variant(std::forward<T>(t)))
+ // This should have strong guarantee because it creates a temporary variant
+ // and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
+ // libstdc++ std::variant has bugs on conversion assignment regarding
+ // exception safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+ {
+ MoveNothrow rhs;
+ EXPECT_TRUE(MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(CheckInvariants, strong_guarantee)
+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+ }
+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+}
+
+TEST(VariantExceptionSafetyTest, Emplace) {
+ // If an exception during the initialization of the contained value, the
+ // variant might not hold a value. The standard requires emplace() to provide
+ // only basic guarantee.
+ {
+ Thrower args = ExpectedThrower();
+ auto tester = MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithOperation([&args](ThrowingVariant* v) {
+ v->emplace<Thrower>(args);
+ });
+ EXPECT_TRUE(tester
+ .WithInvariants(CheckInvariants,
+ [](ThrowingVariant* v) {
+ return v->valueless_by_exception();
+ })
+ .Test());
+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+ }
+}
+
+TEST(VariantExceptionSafetyTest, Swap) {
+ // if both are valueless_by_exception(), no effect
+ {
+ ThrowingVariant rhs = ValuelessByException();
+ EXPECT_TRUE(
+ MakeExceptionSafetyTester()
+ .WithInitialValue(ValuelessByException())
+ .WithInvariants(nothrow_guarantee)
+ .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+ }
+ // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
+ // where i is index().
+ {
+ ThrowingVariant rhs = ExpectedThrower();
+ EXPECT_TRUE(
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithThrower())
+ .WithInvariants(CheckInvariants)
+ .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+ }
+ // Otherwise, exchanges the value of rhs and *this. The exception safety
+ // involves variant in moved-from state which is not specified in the
+ // standard, and since swap is 3-step it's impossible for it to provide a
+ // overall strong guarantee. So, we are only checking basic guarantee here.
+ {
+ ThrowingVariant rhs = ExpectedThrower();
+ EXPECT_TRUE(
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithCopyNoThrow())
+ .WithInvariants(CheckInvariants)
+ .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+ }
+ {
+ ThrowingVariant rhs = ExpectedThrower();
+ EXPECT_TRUE(
+ MakeExceptionSafetyTester()
+ .WithInitialValue(WithCopyNoThrow())
+ .WithInvariants(CheckInvariants)
+ .Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); }));
+ }
+}
+
+} // namespace
+} // namespace absl
diff --git a/third_party/abseil-cpp/absl/types/variant_test.cc b/third_party/abseil-cpp/absl/types/variant_test.cc
index c4676c1..262bd94 100644
--- a/third_party/abseil-cpp/absl/types/variant_test.cc
+++ b/third_party/abseil-cpp/absl/types/variant_test.cc
@@ -119,19 +119,9 @@
template <class T>
struct ExceptionOnConversion {
- // Suppress MSVC 2017 warning "noreturn function has a non-void return type".
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4646)
-#endif // _MSC_VER
-
- [[noreturn]] operator T() const { // NOLINT(runtime/explicit)
+ operator T() const { // NOLINT(runtime/explicit)
throw ConversionException();
}
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER
};
// Forces a variant into the valueless by exception state.
diff --git a/third_party/abseil-cpp/absl/utility/CMakeLists.txt b/third_party/abseil-cpp/absl/utility/CMakeLists.txt
index df21b85..dc3a631 100644
--- a/third_party/abseil-cpp/absl/utility/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/utility/CMakeLists.txt
@@ -22,6 +22,8 @@
absl_header_library(
TARGET
absl_utility
+ PUBLIC_LIBRARIES
+ absl::base
EXPORT_NAME
utility
)
@@ -33,7 +35,12 @@
# test utility_test
set(UTILITY_TEST_SRC "utility_test.cc")
-set(UTILITY_TEST_PUBLIC_LIBRARIES absl::utility)
+set(UTILITY_TEST_PUBLIC_LIBRARIES
+ absl::base
+ absl::memory
+ absl::strings
+ absl::utility
+)
absl_test(
TARGET
diff --git a/third_party/abseil-cpp/absl/utility/utility.h b/third_party/abseil-cpp/absl/utility/utility.h
index 5b9b84e..d73602c 100644
--- a/third_party/abseil-cpp/absl/utility/utility.h
+++ b/third_party/abseil-cpp/absl/utility/utility.h
@@ -24,6 +24,7 @@
// * make_index_sequence<N> == std::make_index_sequence<N>
// * index_sequence_for<Ts...> == std::index_sequence_for<Ts...>
// * apply<Functor, Tuple> == std::apply<Functor, Tuple>
+// * exchange<T> == std::exchange<T>
//
// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
// and `in_place_index_t`, as well as the constant `in_place`, and
@@ -264,6 +265,27 @@
absl::make_index_sequence<std::tuple_size<
typename std::remove_reference<Tuple>::type>::value>{});
}
+
+// exchange
+//
+// Replaces the value of `obj` with `new_value` and returns the old value of
+// `obj`. `absl::exchange` is designed to be a drop-in replacement for C++14's
+// `std::exchange`.
+//
+// Example:
+//
+// Foo& operator=(Foo&& other) {
+// ptr1_ = absl::exchange(other.ptr1_, nullptr);
+// int1_ = absl::exchange(other.int1_, -1);
+// return *this;
+// }
+template <typename T, typename U = T>
+T exchange(T& obj, U&& new_value) {
+ T old_value = absl::move(obj);
+ obj = absl::forward<U>(new_value);
+ return old_value;
+}
+
} // namespace absl
#endif // ABSL_UTILITY_UTILITY_H_
diff --git a/third_party/abseil-cpp/absl/utility/utility_test.cc b/third_party/abseil-cpp/absl/utility/utility_test.cc
index 342165e..3c447b2 100644
--- a/third_party/abseil-cpp/absl/utility/utility_test.cc
+++ b/third_party/abseil-cpp/absl/utility/utility_test.cc
@@ -333,5 +333,13 @@
EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj)));
}
+TEST(ExchangeTest, MoveOnly) {
+ auto a = Factory(1);
+ EXPECT_EQ(1, *a);
+ auto b = absl::exchange(a, Factory(2));
+ EXPECT_EQ(2, *a);
+ EXPECT_EQ(1, *b);
+}
+
} // namespace
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
index 592e50d..1b6b8c0 100644
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -22,7 +22,6 @@
'<(DEPTH)/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp:*',
'<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*',
'<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*',
- '<(DEPTH)/chrome/browser/resources/ntp4/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/cr_components/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*',
diff --git a/third_party/closure_compiler/externs/OWNERS b/third_party/closure_compiler/externs/OWNERS
index 33acaf1..8d19f08 100644
--- a/third_party/closure_compiler/externs/OWNERS
+++ b/third_party/closure_compiler/externs/OWNERS
@@ -1,3 +1,6 @@
michaelpg@chromium.org
rdevlin.cronin@chromium.org
stevenjb@chromium.org
+
+per-file accessibility_private.js=file://ui/accessibility/OWNERS
+per-file automation.js=file://ui/accessibility/OWNERS
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js
index 1bb06e0..ecbf465 100644
--- a/third_party/closure_compiler/externs/automation.js
+++ b/third_party/closure_compiler/externs/automation.js
@@ -285,6 +285,7 @@
*/
chrome.automation.ActionType = {
BLUR: 'blur',
+ CLEAR_ACCESSIBILITY_FOCUS: 'clearAccessibilityFocus',
CUSTOM_ACTION: 'customAction',
DECREMENT: 'decrement',
DO_DEFAULT: 'doDefault',
@@ -302,6 +303,7 @@
SCROLL_TO_MAKE_VISIBLE: 'scrollToMakeVisible',
SCROLL_TO_POINT: 'scrollToPoint',
SCROLL_UP: 'scrollUp',
+ SET_ACCESSIBILITY_FOCUS: 'setAccessibilityFocus',
SET_SCROLL_OFFSET: 'setScrollOffset',
SET_SELECTION: 'setSelection',
SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT: 'setSequentialFocusNavigationStartingPoint',
diff --git a/third_party/opus/README.chromium b/third_party/opus/README.chromium
index 853f7eb..53425f0 100644
--- a/third_party/opus/README.chromium
+++ b/third_party/opus/README.chromium
@@ -16,3 +16,5 @@
* set 'x' flags: "chmod 750 win32/genversion.bat"
* Apply https://git.xiph.org/?p=opus.git;a=commitdiff;h=46560534fcb5710a894a341c2f9526db58fd7087#patch1
* Apply https://github.com/xiph/opus/pull/73
+* Apply https://github.com/xiph/opus/pull/87
+* Make sure HB_gain is not NaN in an attempt to fix chromium:826914
diff --git a/third_party/opus/src/silk/API.h b/third_party/opus/src/silk/API.h
index 0131acb..4d90ff9 100644
--- a/third_party/opus/src/silk/API.h
+++ b/third_party/opus/src/silk/API.h
@@ -80,7 +80,8 @@
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
- const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+ const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
+ int activity /* I Decision of Opus voice activity detector */
);
/****************************************/
diff --git a/third_party/opus/src/silk/define.h b/third_party/opus/src/silk/define.h
index 1286048..22fd720 100644
--- a/third_party/opus/src/silk/define.h
+++ b/third_party/opus/src/silk/define.h
@@ -58,6 +58,11 @@
#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
#define DTX_ACTIVITY_THRESHOLD 0.1f
+/* VAD decision */
+#define VAD_NO_DECISION -1
+#define VAD_NO_ACTIVITY 0
+#define VAD_ACTIVITY 1
+
/* Maximum sampling frequency */
#define MAX_FS_KHZ 16
#define MAX_API_FS_KHZ 48
diff --git a/third_party/opus/src/silk/enc_API.c b/third_party/opus/src/silk/enc_API.c
index 701c290..0a62a3c 100644
--- a/third_party/opus/src/silk/enc_API.c
+++ b/third_party/opus/src/silk/enc_API.c
@@ -144,7 +144,8 @@
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
- const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+ const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
+ opus_int activity /* I Decision of Opus voice activity detector */
)
{
opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
@@ -425,7 +426,7 @@
psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
}
- silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] );
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity );
} else {
psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
}
@@ -440,7 +441,7 @@
silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
}
- silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] );
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity );
/* Encode */
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
diff --git a/third_party/opus/src/silk/fixed/encode_frame_FIX.c b/third_party/opus/src/silk/fixed/encode_frame_FIX.c
index 0efa9e6..f6ee813 100644
--- a/third_party/opus/src/silk/fixed/encode_frame_FIX.c
+++ b/third_party/opus/src/silk/fixed/encode_frame_FIX.c
@@ -43,18 +43,25 @@
);
void silk_encode_do_VAD_FIX(
- silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int activity /* I Decision of Opus voice activity detector */
)
{
+ const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 );
+
/****************************/
/* Voice Activity Detection */
/****************************/
silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+ /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */
+ if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) {
+ psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1;
+ }
/**************************************************/
/* Convert speech activity into VAD and DTX flags */
/**************************************************/
- if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) {
psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
psEnc->sCmn.noSpeechCounter++;
if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) {
diff --git a/third_party/opus/src/silk/fixed/main_FIX.h b/third_party/opus/src/silk/fixed/main_FIX.h
index 780afa3..6d2112e 100644
--- a/third_party/opus/src/silk/fixed/main_FIX.h
+++ b/third_party/opus/src/silk/fixed/main_FIX.h
@@ -66,7 +66,8 @@
/* Encoder main function */
void silk_encode_do_VAD_FIX(
- silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int activity /* I Decision of Opus voice activity detector */
);
/* Encoder main function */
diff --git a/third_party/opus/src/silk/float/encode_frame_FLP.c b/third_party/opus/src/silk/float/encode_frame_FLP.c
index 5db85c7..49956a2 100644
--- a/third_party/opus/src/silk/float/encode_frame_FLP.c
+++ b/third_party/opus/src/silk/float/encode_frame_FLP.c
@@ -42,18 +42,25 @@
);
void silk_encode_do_VAD_FLP(
- silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int activity /* I Decision of Opus voice activity detector */
)
{
+ const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 );
+
/****************************/
/* Voice Activity Detection */
/****************************/
silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+ /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */
+ if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) {
+ psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1;
+ }
/**************************************************/
/* Convert speech activity into VAD and DTX flags */
/**************************************************/
- if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) {
psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
psEnc->sCmn.noSpeechCounter++;
if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) {
diff --git a/third_party/opus/src/silk/float/main_FLP.h b/third_party/opus/src/silk/float/main_FLP.h
index f47fc93..5dc0ccf 100644
--- a/third_party/opus/src/silk/float/main_FLP.h
+++ b/third_party/opus/src/silk/float/main_FLP.h
@@ -56,7 +56,8 @@
/* Encoder main function */
void silk_encode_do_VAD_FLP(
- silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int activity /* I Decision of Opus voice activity detector */
);
/* Encoder main function */
diff --git a/third_party/opus/src/src/opus_encoder.c b/third_party/opus/src/src/opus_encoder.c
index cd37fcd..2149c20 100644
--- a/third_party/opus/src/src/opus_encoder.c
+++ b/third_party/opus/src/src/opus_encoder.c
@@ -1661,6 +1661,7 @@
if (st->mode != MODE_CELT_ONLY)
{
opus_int32 total_bitRate, celt_rate;
+ opus_int activity;
#ifdef FIXED_POINT
const opus_int16 *pcm_silk;
#else
@@ -1668,6 +1669,14 @@
ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
#endif
+ activity = VAD_NO_DECISION;
+#ifndef DISABLE_FLOAT_API
+ if( analysis_info.valid ) {
+ /* Inform SILK about the Opus VAD decision */
+ activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD );
+ }
+#endif
+
/* Distribute bits between SILK and CELT */
total_bitRate = 8 * bytes_target * frame_rate;
if( st->mode == MODE_HYBRID ) {
@@ -1679,6 +1688,12 @@
/* Increasingly attenuate high band when it gets allocated fewer bits */
celt_rate = total_bitRate - st->silk_mode.bitRate;
HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1);
+#ifndef FIXED_POINT
+ /* Sanity check of high band gain */
+ if (celt_isnan(HB_gain)) {
+ HB_gain = Q15ONE;
+ }
+#endif
}
} else {
/* SILK gets all bits */
@@ -1813,7 +1828,7 @@
for (i=0;i<st->encoder_buffer*st->channels;i++)
pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
#endif
- silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
+ silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1, activity );
}
#ifdef FIXED_POINT
@@ -1822,7 +1837,7 @@
for (i=0;i<frame_size*st->channels;i++)
pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]);
#endif
- ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
+ ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity );
if( ret ) {
/*fprintf (stderr, "SILK encode error: %d\n", ret);*/
/* Handle error */