diff --git a/.gitignore b/.gitignore index 31f3374..d54fa5a 100644 --- a/.gitignore +++ b/.gitignore
@@ -11,5 +11,5 @@ # Ignore VS Code files .vscode/* # Ignore generated python artifacts -copts/copts.pyc +*.pyc copts/__pycache__/
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index 7c81bea..6d26169 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake
@@ -16,6 +16,7 @@ include(CMakeParseArguments) include(AbseilConfigureCopts) +include(GNUInstallDirs) # The IDE folder for Abseil that will be used if Abseil is included in a CMake # project that sets @@ -35,13 +36,13 @@ # COPTS: List of private compile options # DEFINES: List of public defines # LINKOPTS: List of link options -# PUBLIC: Add this so that this library will be exported under absl:: (see Note). +# PUBLIC: Add this so that this library will be exported under absl:: # Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal. # TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake. # # Note: -# By default, absl_cc_library will always create a library named absl_internal_${NAME}, -# and alias target absl::${NAME}. +# By default, absl_cc_library will always create a library named absl_${NAME}, +# and alias target absl::${NAME}. The absl:: form should always be used. # This is to reduce namespace pollution. # # absl_cc_library( @@ -59,20 +60,17 @@ # "b.cc" # DEPS # absl_internal_awesome # not "awesome"! +# PUBLIC # ) # -# If PUBLIC is set, absl_cc_library will instead create a target named -# absl_${NAME} and still an alias absl::${NAME}. -# # absl_cc_library( # NAME # main_lib # ... -# PUBLIC +# DEPS +# absl::fantastic_lib # since fantastic_lib is public # ) # -# User can then use the library as absl::main_lib (although absl_main_lib is defined too). -# # TODO: Implement "ALWAYSLINK" function(absl_cc_library) cmake_parse_arguments(ABSL_CC_LIB @@ -83,11 +81,7 @@ ) if (NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS) - if (ABSL_CC_LIB_PUBLIC) - set(_NAME "absl_${ABSL_CC_LIB_NAME}") - else() - set(_NAME "absl_internal_${ABSL_CC_LIB_NAME}") - endif() + set(_NAME "${ABSL_CC_LIB_NAME}") # Check if this is a header-only library # Note that as of February 2019, many popular OS's (for example, Ubuntu @@ -109,7 +103,10 @@ add_library(${_NAME} STATIC "") target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) target_include_directories(${_NAME} - PUBLIC ${ABSL_COMMON_INCLUDE_DIRS}) + PUBLIC + $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + ) target_compile_options(${_NAME} PRIVATE ${ABSL_CC_LIB_COPTS}) target_link_libraries(${_NAME} @@ -130,17 +127,37 @@ # INTERFACE libraries can't have the CXX_STANDARD property set set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + + # When being installed, we lose the absl_ prefix. We want to put it back + # to have properly named lib files. This is a no-op when we are not being + # installed. + set_target_properties(${_NAME} PROPERTIES + OUTPUT_NAME "absl_${_NAME}" + ) else() # Generating header-only library add_library(${_NAME} INTERFACE) target_include_directories(${_NAME} - INTERFACE ${ABSL_COMMON_INCLUDE_DIRS}) + INTERFACE + $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + ) target_link_libraries(${_NAME} INTERFACE ${ABSL_CC_LIB_DEPS} ${ABSL_CC_LIB_LINKOPTS} ) target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) endif() + # TODO currently we don't install googletest alongside abseil sources, so + # installed abseil can't be tested. + if (NOT ABSL_CC_LIB_TESTONLY) + install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + endif() + add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME}) endif() endfunction()
diff --git a/CMake/abslConfig.cmake.in b/CMake/abslConfig.cmake.in new file mode 100644 index 0000000..bf8c4f6 --- /dev/null +++ b/CMake/abslConfig.cmake.in
@@ -0,0 +1,6 @@ +## absl CMake configuration file. Note that there is no corresponding +# abslConfigVersion.cmake since non-LTS Abseil isn't versioned. + +@PACKAGE_INIT@ + +include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") \ No newline at end of file
diff --git a/CMake/install_test_project/CMakeLists.txt b/CMake/install_test_project/CMakeLists.txt new file mode 100644 index 0000000..b8e27dd --- /dev/null +++ b/CMake/install_test_project/CMakeLists.txt
@@ -0,0 +1,27 @@ +# +# Copyright 2019 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 +# +# https://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. + +# A simple CMakeLists.txt for testing cmake installation + +cmake_minimum_required(VERSION 3.5) +project(absl_cmake_testing) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(simple simple.cc) + +find_package(absl REQUIRED) + +target_link_libraries(simple absl::strings)
diff --git a/CMake/install_test_project/simple.cc b/CMake/install_test_project/simple.cc new file mode 100644 index 0000000..e9e3529 --- /dev/null +++ b/CMake/install_test_project/simple.cc
@@ -0,0 +1,23 @@ +// +// Copyright 2019 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 +// +// https://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 <iostream> +#include "absl/strings/substitute.h" + +int main(int argc, char** argv) { + for (int i = 0; i < argc; ++i) { + std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]); + } +}
diff --git a/CMake/install_test_project/test.sh b/CMake/install_test_project/test.sh new file mode 100755 index 0000000..3e77e79 --- /dev/null +++ b/CMake/install_test_project/test.sh
@@ -0,0 +1,110 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +# "Unit" and integration tests for Absl CMake installation + +# TODO(absl-team): This script isn't fully hermetic because +# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed +# version of GoogleTest. This means that an upstream change to GoogleTest could +# break this test. Fix this by allowing this script to pin to a known-good +# version of GoogleTest. + +# Fail on any error. Treat unset variables an error. Print commands as executed. +set -euox pipefail +absl_dir=/abseil-cpp +absl_build_dir=/buildfs/absl-build +project_dir="${absl_dir}"/CMake/install_test_project +project_build_dir=/buildfs/project-build +install_dir="${project_build_dir}"/install + +mkdir -p "${absl_build_dir}" +mkdir -p "${project_build_dir}" +mkdir -p "${install_dir}" + +install_absl() { + pushd "${absl_build_dir}" + if [[ "${#}" -eq 1 ]]; then + cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}" + else + cmake "${absl_dir}" + fi + cmake --build . --target install -- -j + popd +} + +uninstall_absl() { + xargs rm < "${absl_build_dir}"/install_manifest.txt + rm -rf "${absl_build_dir}" + mkdir -p "${absl_build_dir}" +} + +# Test build, install, and link against installed abseil +install_absl "${install_dir}" +pushd "${project_build_dir}" +cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}" +cmake --build . --target simple + +output="$(${project_build_dir}/simple "printme" 2>&1)" +if [[ "${output}" != *"Arg 1: printme"* ]]; then + echo "Faulty output on simple project:" + echo "${output}" + exit 1 +fi + +# Test that we haven't accidentally made absl::abslblah +pushd "${install_dir}" + +# Starting in CMake 3.12 the default install dir is lib$bit_width +if [[ -d lib ]]; then + libdir="lib" +elif [[ -d lib64 ]]; then + libdir="lib64" +else + echo "ls *, */*, */*/*:" + ls * + ls */* + ls */*/* + echo "unknown lib dir" +fi + +if ! grep absl::strings "${libdir}"/cmake/absl/abslTargets.cmake; then + cat "${libdir}"/cmake/absl/abslTargets.cmake + echo "CMake targets named incorrectly" + exit 1 +fi + +uninstall_absl +popd + +# Test that we warn if installed without a prefix or a system prefix +output="$(install_absl 2>&1)" +if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then + echo "Install without prefix didn't warn as expected. Output:" + echo "${output}" + exit 1 +fi +uninstall_absl + +output="$(install_absl /usr 2>&1)" +if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then + echo "Install with /usr didn't warn as expected. Output:" + echo "${output}" + exit 1 +fi +uninstall_absl + +echo "Install test complete!" +exit 0
diff --git a/CMakeLists.txt b/CMakeLists.txt index a56d238..3f4fbdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -14,23 +14,38 @@ # limitations under the License. # -# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of -# CXX_STANDARD in our targets. -cmake_minimum_required(VERSION 3.1) +# Most widely used distributions have cmake 3.5 or greater available as of March +# 2019. A notable exception is RHEL-7 (CentOS7). You can install a current +# version of CMake by first installing Extra Packages for Enterprise Linux +# (https://fedoraproject.org/wiki/EPEL#Extra_Packages_for_Enterprise_Linux_.28EPEL.29) +# and then issuing `yum install cmake3` on the command line. +cmake_minimum_required(VERSION 3.5) # Compiler id for Apple Clang is now AppleClang. if (POLICY CMP0025) cmake_policy(SET CMP0025 NEW) endif() +# if command can use IN_LIST +cmake_policy(SET CMP0057 NEW) + project(absl) +# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) +# in the source tree of a project that uses it, install rules are disabled. +if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") + set(ABSL_ENABLE_INSTALL FALSE) +else() + set(ABSL_ENABLE_INSTALL TRUE) +endif() + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/CMake ${CMAKE_CURRENT_LIST_DIR}/absl/copts ) include(GNUInstallDirs) +include(CMakePackageConfigHelpers) include(AbseilHelpers) @@ -70,11 +85,23 @@ enable_testing() endif() +# We don't support system-wide installation +list(APPEND SYSTEM_INSTALL_DIRS "/usr/local" "/usr" "/opt/" "/opt/local" "c:/Program Files/${PROJECT_NAME}") +if(NOT DEFINED CMAKE_INSTALL_PREFIX OR CMAKE_INSTALL_PREFIX IN_LIST SYSTEM_INSTALL_DIRS) + message(WARNING "\ +The default and system-level install directories are unsupported except in LTS \ +releases of Abseil. Please set CMAKE_INSTALL_PREFIX to install Abseil in your \ +source or build tree directly.\ + ") +endif() + ## check targets if(BUILD_TESTING) if(${ABSL_USE_GOOGLETEST_HEAD}) include(CMake/DownloadGTest.cmake) + set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src) + set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) endif() check_target(gtest) @@ -90,3 +117,26 @@ endif() add_subdirectory(absl) + +# install as a subdirectory only +install(EXPORT ${PROJECT_NAME}Targets + NAMESPACE absl:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" +) + +configure_package_config_file( + CMake/abslConfig.cmake.in + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" +) + +install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" +) + +install(DIRECTORY absl + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING + PATTERN "*.inc" + PATTERN "*.h" +)
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index 7348d63..752e47b 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h
@@ -36,7 +36,6 @@ // For template parameter and variable naming, `C` indicates the container type // to which the function is applied, `Pred` indicates the predicate object type // to be used by the function and `T` indicates the applicable element type. -// #ifndef ABSL_ALGORITHM_CONTAINER_H_ #define ABSL_ALGORITHM_CONTAINER_H_ @@ -648,7 +647,6 @@ // and `unique()` are omitted, because it's not clear whether or not such // functions should call erase on their supplied sequences afterwards. Either // behavior would be surprising for a different set of users. -// // c_remove_copy() //
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 19c5045..804f62a 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -326,7 +326,7 @@ name = "spinlock_benchmark_common", testonly = 1, srcs = ["internal/spinlock_benchmark.cc"], - copts = ABSL_DEFAULT_COPTS, + copts = ABSL_TEST_COPTS, visibility = [ "//absl/base:__pkg__", ],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index f2bacb2..d8a311c 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt
@@ -241,7 +241,7 @@ "throw_delegate_test.cc" DEPS absl::base - absl_internal_throw_delegate + absl::throw_delegate gtest_main )
diff --git a/absl/base/const_init.h b/absl/base/const_init.h index 1b2b8c2..17858a7 100644 --- a/absl/base/const_init.h +++ b/absl/base/const_init.h
@@ -60,7 +60,6 @@ // // The absl::kConstInit tag should only be used to define objects with static // or thread_local storage duration. -// namespace absl {
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h index cdeb18c..ac33df9 100644 --- a/absl/base/dynamic_annotations.h +++ b/absl/base/dynamic_annotations.h
@@ -139,6 +139,7 @@ #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ #endif /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ + /* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the appropriate feature ID. */ #if defined(__clang__) && (!defined(SWIG)) \
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h index 7874db7..794564e 100644 --- a/absl/base/internal/cycleclock.h +++ b/absl/base/internal/cycleclock.h
@@ -28,7 +28,6 @@ // not necessarily "CPU cycles" and code should not rely on that behavior, even // if experimentally observed. // -// // An arbitrary offset may have been added to the counter at power on. // // On some platforms, the rate and offset of the counter may differ
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h index f83c7bc..b35673d 100644 --- a/absl/base/internal/low_level_alloc.h +++ b/absl/base/internal/low_level_alloc.h
@@ -119,4 +119,5 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc index d2d3182..34a080c 100644 --- a/absl/base/internal/low_level_alloc_test.cc +++ b/absl/base/internal/low_level_alloc_test.cc
@@ -137,6 +137,7 @@ TEST_ASSERT(LowLevelAlloc::DeleteArena(arena)); } } + // LowLevelAlloc is designed to be safe to call before main(). static struct BeforeMain { BeforeMain() {
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h index 2a5a384..0fcc8d3 100644 --- a/absl/base/internal/low_level_scheduling.h +++ b/absl/base/internal/low_level_scheduling.h
@@ -86,6 +86,7 @@ //------------------------------------------------------------------------------ // End of public interfaces. //------------------------------------------------------------------------------ + inline bool SchedulingGuard::ReschedulingIsAllowed() { return false; } @@ -98,7 +99,7 @@ return; } - } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index 4cbbbe5..6a4c093 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h
@@ -38,6 +38,7 @@ // ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); // This will print an almost standard log line like this to stderr only: // E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file + #define ABSL_RAW_LOG(severity, ...) \ do { \ constexpr const char* absl_raw_logging_internal_basename = \
diff --git a/absl/base/internal/scoped_set_env.cc b/absl/base/internal/scoped_set_env.cc index 9b16412..3ac3f68 100644 --- a/absl/base/internal/scoped_set_env.cc +++ b/absl/base/internal/scoped_set_env.cc
@@ -33,7 +33,7 @@ void SetEnvVar(const char* name, const char* value) { #ifdef _WIN32 - SetEnvironmentVariable(name, value); + SetEnvironmentVariableA(name, value); #else if (value == nullptr) { ::unsetenv(name); @@ -49,7 +49,7 @@ : var_name_(var_name), was_unset_(false) { #ifdef _WIN32 char buf[kMaxEnvVarValueSize]; - auto get_res = GetEnvironmentVariable(var_name_.c_str(), buf, sizeof(buf)); + auto get_res = GetEnvironmentVariableA(var_name_.c_str(), buf, sizeof(buf)); ABSL_INTERNAL_CHECK(get_res < sizeof(buf), "value exceeds buffer size"); if (get_res == 0) { @@ -58,7 +58,7 @@ old_value_.assign(buf, get_res); } - SetEnvironmentVariable(var_name_.c_str(), new_value); + SetEnvironmentVariableA(var_name_.c_str(), new_value); #else const char* val = ::getenv(var_name_.c_str()); if (val == nullptr) {
diff --git a/absl/base/internal/scoped_set_env_test.cc b/absl/base/internal/scoped_set_env_test.cc index 4bd68c4..5cbad24 100644 --- a/absl/base/internal/scoped_set_env_test.cc +++ b/absl/base/internal/scoped_set_env_test.cc
@@ -26,8 +26,8 @@ std::string GetEnvVar(const char* name) { #ifdef _WIN32 char buf[1024]; - auto get_res = GetEnvironmentVariable(name, buf, sizeof(buf)); - if (get_res == sizeof(buf)) { + auto get_res = GetEnvironmentVariableA(name, buf, sizeof(buf)); + if (get_res >= sizeof(buf)) { return "TOO_BIG"; }
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h index dde3e01..b34674a 100644 --- a/absl/base/internal/thread_identity.h +++ b/absl/base/internal/thread_identity.h
@@ -237,4 +237,5 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h index d5e186a..58950cc 100644 --- a/absl/base/internal/unscaledcycleclock.h +++ b/absl/base/internal/unscaledcycleclock.h
@@ -83,6 +83,7 @@ defined(_M_IX86) || defined(_M_X64)) #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #endif + namespace absl { namespace time_internal { class UnscaledCycleClockWrapperForGetCurrentTime; @@ -114,6 +115,7 @@ } // namespace base_internal } // namespace absl + #endif // ABSL_USE_UNSCALED_CYCLECLOCK #endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index 4b9833e..b19a7ff 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h
@@ -11,7 +11,6 @@ // 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_BASE_INTERNAL_LOG_SEVERITY_H_ #define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc index b32cea2..e62b2ea 100644 --- a/absl/base/spinlock_test_common.cc +++ b/absl/base/spinlock_test_common.cc
@@ -54,6 +54,7 @@ static constexpr int kArrayLength = 10; static uint32_t values[kArrayLength]; + static SpinLock static_spinlock(base_internal::kLinkerInitialized); static SpinLock static_cooperative_spinlock( base_internal::kLinkerInitialized, @@ -189,6 +190,7 @@ SpinLockTest::DecodeWaitCycles(before_max_value); EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); } + TEST(SpinLockWithThreads, StaticSpinLock) { ThreadedTest(&static_spinlock); }
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h index a8162d4..0b2c306 100644 --- a/absl/base/thread_annotations.h +++ b/absl/base/thread_annotations.h
@@ -21,7 +21,6 @@ // code. The annotations can also help program analysis tools to identify // potential thread safety issues. // -// // These annotations are implemented using compiler attributes. Using the macros // defined here instead of raw attributes allow for portability and future // compatibility. @@ -34,6 +33,7 @@ #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_ + #if defined(__clang__) #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else
diff --git a/absl/compiler_config_setting.bzl b/absl/compiler_config_setting.bzl index e03f94e..6696229 100644 --- a/absl/compiler_config_setting.bzl +++ b/absl/compiler_config_setting.bzl
@@ -12,7 +12,6 @@ # 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. -# """Creates config_setting that allows selecting based on 'compiler' value."""
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index b6592ca..cd914ba 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -112,10 +112,20 @@ ) cc_library( + name = "inlined_vector_internal", + hdrs = ["internal/inlined_vector.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + "//absl/meta:type_traits", + ], +) + +cc_library( name = "inlined_vector", hdrs = ["inlined_vector.h"], copts = ABSL_DEFAULT_COPTS, deps = [ + ":inlined_vector_internal", "//absl/algorithm", "//absl/base:core_headers", "//absl/base:throw_delegate",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 76542be..292fea2 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt
@@ -109,6 +109,18 @@ absl_cc_library( NAME + inlined_vector_internal + HDRS + "internal/inlined_vector.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::type_traits + PUBLIC +) + +absl_cc_library( + NAME inlined_vector HDRS "inlined_vector.h"
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index 0161d0a..2a8240a 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h
@@ -515,4 +515,5 @@ static_cast<void>(n); // Mark used when not in asan mode } } // namespace absl + #endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h index dfc497b..00cc4dc 100644 --- a/absl/container/flat_hash_map.h +++ b/absl/container/flat_hash_map.h
@@ -219,8 +219,12 @@ // Erases the element at `position` of the `flat_hash_map`, returning // `void`. // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // NOTE: returning `void` in this case is different than that of STL + // containers in general and `std::unordered_map` in particular (which + // return an iterator to the element following the erased element). If that + // iterator is needed, simply post increment the iterator: + // + // map.erase(it++); // // iterator erase(const_iterator first, const_iterator last): //
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc index 562305e..ebcb560 100644 --- a/absl/container/flat_hash_map_test.cc +++ b/absl/container/flat_hash_map_test.cc
@@ -141,6 +141,7 @@ int conversions = 0; int hashes = 0; flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes}); + m.reserve(3); m[LazyInt(1, &conversions)] = 1; EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1))); @@ -205,7 +206,9 @@ m.insert(std::move(node)); EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9))); } -#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) + +#if (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && \ + !defined(__EMSCRIPTEN__) TEST(FlatHashMap, Any) { absl::flat_hash_map<int, absl::any> m; m.emplace(1, 7); @@ -236,7 +239,8 @@ ASSERT_NE(it2, m2.end()); EXPECT_EQ(7, it2->second); } -#endif // __ANDROID__ +#endif // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && + // !defined(__EMSCRIPTEN__) } // namespace } // namespace container_internal
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h index f27f174..6bf5183 100644 --- a/absl/container/flat_hash_set.h +++ b/absl/container/flat_hash_set.h
@@ -212,8 +212,12 @@ // Erases the element at `position` of the `flat_hash_set`, returning // `void`. // - // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // NOTE: returning `void` in this case is different than that of STL + // containers in general and `std::unordered_set` in particular (which + // return an iterator to the element following the erased element). If that + // iterator is needed, simply post increment the iterator: + // + // set.erase(it++); // // iterator erase(const_iterator first, const_iterator last): //
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index 80929e3..7798805 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h
@@ -1,4 +1,4 @@ -// Copyright 2018 The Abseil Authors. +// Copyright 2019 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. @@ -50,6 +50,7 @@ #include "absl/base/internal/throw_delegate.h" #include "absl/base/optimization.h" #include "absl/base/port.h" +#include "absl/container/internal/inlined_vector.h" #include "absl/memory/memory.h" namespace absl { @@ -65,10 +66,13 @@ // designed to cover the same API footprint as covered by `std::vector`. template <typename T, size_t N, typename A = std::allocator<T>> class InlinedVector { - static_assert(N > 0, "InlinedVector requires inline capacity greater than 0"); - constexpr static typename A::size_type GetInlinedCapacity() { - return static_cast<typename A::size_type>(N); - } + static_assert( + N > 0, "InlinedVector cannot be instantiated with `0` inlined elements."); + + using Storage = inlined_vector_internal::Storage<InlinedVector>; + using Tag = typename Storage::Tag; + using AllocatorAndTag = typename Storage::AllocatorAndTag; + using Allocation = typename Storage::Allocation; template <typename Iterator> using IsAtLeastForwardIterator = std::is_convertible< @@ -83,21 +87,21 @@ using DisableIfAtLeastForwardIterator = absl::enable_if_t<!IsAtLeastForwardIterator<Iterator>::value>; - using rvalue_reference = typename A::value_type&&; + using rvalue_reference = typename Storage::rvalue_reference; public: - using allocator_type = A; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator<iterator>; - using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using allocator_type = typename Storage::allocator_type; + using value_type = typename Storage::value_type; + using pointer = typename Storage::pointer; + using const_pointer = typename Storage::const_pointer; + using reference = typename Storage::reference; + using const_reference = typename Storage::const_reference; + using size_type = typename Storage::size_type; + using difference_type = typename Storage::difference_type; + using iterator = typename Storage::iterator; + using const_iterator = typename Storage::const_iterator; + using reverse_iterator = typename Storage::reverse_iterator; + using const_reverse_iterator = typename Storage::const_reverse_iterator; // --------------------------------------------------------------------------- // InlinedVector Constructors and Destructor @@ -105,30 +109,30 @@ // Creates an empty inlined vector with a default initialized allocator. InlinedVector() noexcept(noexcept(allocator_type())) - : allocator_and_tag_(allocator_type()) {} + : storage_(allocator_type()) {} // Creates an empty inlined vector with a specified allocator. explicit InlinedVector(const allocator_type& alloc) noexcept - : allocator_and_tag_(alloc) {} + : storage_(alloc) {} // Creates an inlined vector with `n` copies of `value_type()`. explicit InlinedVector(size_type n, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { InitAssign(n); } // Creates an inlined vector with `n` copies of `v`. InlinedVector(size_type n, const_reference v, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { InitAssign(n, v); } // Creates an inlined vector of copies of the values in `list`. InlinedVector(std::initializer_list<value_type> list, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { AppendForwardRange(list.begin(), list.end()); } @@ -142,7 +146,7 @@ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr> InlinedVector(ForwardIterator first, ForwardIterator last, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { AppendForwardRange(first, last); } @@ -152,7 +156,7 @@ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> InlinedVector(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()) - : allocator_and_tag_(alloc) { + : storage_(alloc) { std::copy(first, last, std::back_inserter(*this)); } @@ -162,7 +166,7 @@ // Creates a copy of an `other` inlined vector using a specified allocator. InlinedVector(const InlinedVector& other, const allocator_type& alloc) - : allocator_and_tag_(alloc) { + : storage_(alloc) { reserve(other.size()); if (allocated()) { UninitializedCopy(other.begin(), other.end(), allocated_space()); @@ -191,7 +195,7 @@ InlinedVector(InlinedVector&& other) noexcept( absl::allocator_is_nothrow<allocator_type>::value || std::is_nothrow_move_constructible<value_type>::value) - : allocator_and_tag_(other.allocator()) { + : storage_(other.allocator()) { if (other.allocated()) { // We can just steal the underlying buffer from the source. // That leaves the source empty, so we clear its size. @@ -222,7 +226,7 @@ // ownership of `other`'s allocated memory. InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept( absl::allocator_is_nothrow<allocator_type>::value) - : allocator_and_tag_(alloc) { + : storage_(alloc) { if (other.allocated()) { if (alloc == other.allocator()) { // We can just steal the allocation from the source. @@ -282,7 +286,7 @@ // will no longer be inlined and `capacity()` will equal its capacity on the // allocated heap. size_type capacity() const noexcept { - return allocated() ? allocation().capacity() : GetInlinedCapacity(); + return allocated() ? allocation().capacity() : static_cast<size_type>(N); } // `InlinedVector::data()` @@ -800,19 +804,19 @@ // `InlinedVector::shrink_to_fit()` // // Reduces memory usage by freeing unused memory. After this call, calls to - // `capacity()` will be equal to `(std::max)(GetInlinedCapacity(), size())`. + // `capacity()` will be equal to `max(N, size())`. // - // If `size() <= GetInlinedCapacity()` and the elements are currently stored - // on the heap, they will be moved to the inlined storage and the heap memory - // will be deallocated. + // If `size() <= N` and the elements are currently stored on the heap, they + // will be moved to the inlined storage and the heap memory will be + // deallocated. // - // If `size() > GetInlinedCapacity()` and `size() < capacity()` the elements - // will be moved to a smaller heap allocation. + // If `size() > N` and `size() < capacity()` the elements will be moved to a + // smaller heap allocation. void shrink_to_fit() { const auto s = size(); if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return; - if (s <= GetInlinedCapacity()) { + if (s <= N) { // Move the elements to the inlined storage. // We have to do this using a temporary, because `inlined_storage` and // `allocation_storage` are in a union field. @@ -845,88 +849,33 @@ template <typename H, typename TheT, size_t TheN, typename TheA> friend auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H; - // Holds whether the vector is allocated or not in the lowest bit and the size - // in the high bits: - // `size_ = (size << 1) | is_allocated;` - class Tag { - public: - Tag() : size_(0) {} - size_type size() const { return size_ / 2; } - void add_size(size_type n) { size_ += n * 2; } - void set_inline_size(size_type n) { size_ = n * 2; } - void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } - bool allocated() const { return size_ % 2; } + const Tag& tag() const { return storage_.allocator_and_tag_.tag(); } - private: - size_type size_; - }; - - // Derives from `allocator_type` to use the empty base class optimization. - // If the `allocator_type` is stateless, we can store our instance for free. - class AllocatorAndTag : private allocator_type { - public: - explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} - - Tag& tag() { return tag_; } - const Tag& tag() const { return tag_; } - - allocator_type& allocator() { return *this; } - const allocator_type& allocator() const { return *this; } - - private: - Tag tag_; - }; - - class Allocation { - public: - Allocation(allocator_type& a, size_type capacity) - : capacity_(capacity), buffer_(Create(a, capacity)) {} - - void Dealloc(allocator_type& a) { - std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_); - } - - size_type capacity() const { return capacity_; } - - const_pointer buffer() const { return buffer_; } - - pointer buffer() { return buffer_; } - - private: - static pointer Create(allocator_type& a, size_type n) { - return std::allocator_traits<allocator_type>::allocate(a, n); - } - - size_type capacity_; - pointer buffer_; - }; - - const Tag& tag() const { return allocator_and_tag_.tag(); } - - Tag& tag() { return allocator_and_tag_.tag(); } + Tag& tag() { return storage_.allocator_and_tag_.tag(); } Allocation& allocation() { - return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation); + return reinterpret_cast<Allocation&>( + storage_.rep_.allocation_storage.allocation); } const Allocation& allocation() const { return reinterpret_cast<const Allocation&>( - rep_.allocation_storage.allocation); + storage_.rep_.allocation_storage.allocation); } void init_allocation(const Allocation& allocation) { - new (&rep_.allocation_storage.allocation) Allocation(allocation); + new (&storage_.rep_.allocation_storage.allocation) Allocation(allocation); } // TODO(absl-team): investigate whether the reinterpret_cast is appropriate. pointer inlined_space() { return reinterpret_cast<pointer>( - std::addressof(rep_.inlined_storage.inlined[0])); + std::addressof(storage_.rep_.inlined_storage.inlined[0])); } const_pointer inlined_space() const { return reinterpret_cast<const_pointer>( - std::addressof(rep_.inlined_storage.inlined[0])); + std::addressof(storage_.rep_.inlined_storage.inlined[0])); } pointer allocated_space() { return allocation().buffer(); } @@ -934,10 +883,12 @@ const_pointer allocated_space() const { return allocation().buffer(); } const allocator_type& allocator() const { - return allocator_and_tag_.allocator(); + return storage_.allocator_and_tag_.allocator(); } - allocator_type& allocator() { return allocator_and_tag_.allocator(); } + allocator_type& allocator() { + return storage_.allocator_and_tag_.allocator(); + } bool allocated() const { return tag().allocated(); } @@ -994,7 +945,7 @@ const size_type s = size(); assert(s <= capacity()); - size_type target = (std::max)(GetInlinedCapacity(), s + delta); + size_type target = (std::max)(N, s + delta); // Compute new capacity by repeatedly doubling current capacity // TODO(psrc): Check and avoid overflow? @@ -1097,7 +1048,7 @@ } void InitAssign(size_type n) { - if (n > GetInlinedCapacity()) { + if (n > N) { Allocation new_allocation(allocator(), n); init_allocation(new_allocation); UninitializedFill(allocated_space(), allocated_space() + n); @@ -1109,7 +1060,7 @@ } void InitAssign(size_type n, const_reference v) { - if (n > GetInlinedCapacity()) { + if (n > N) { Allocation new_allocation(allocator(), n); init_allocation(new_allocation); UninitializedFill(allocated_space(), allocated_space() + n, v); @@ -1267,28 +1218,7 @@ assert(a->size() == b_size); } - // Stores either the inlined or allocated representation - union Rep { - using ValueTypeBuffer = - absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>; - using AllocationBuffer = - absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>; - - // Structs wrap the buffers to perform indirection that solves a bizarre - // compilation error on Visual Studio (all known versions). - struct InlinedRep { - ValueTypeBuffer inlined[N]; - }; - struct AllocatedRep { - AllocationBuffer allocation; - }; - - InlinedRep inlined_storage; - AllocatedRep allocation_storage; - }; - - AllocatorAndTag allocator_and_tag_; - Rep rep_; + Storage storage_; }; // -----------------------------------------------------------------------------
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc index fc928af..867a29e 100644 --- a/absl/container/inlined_vector_benchmark.cc +++ b/absl/container/inlined_vector_benchmark.cc
@@ -23,17 +23,13 @@ namespace { -using IntVec = absl::InlinedVector<int, 8>; - void BM_InlinedVectorFill(benchmark::State& state) { - const int len = state.range(0); + absl::InlinedVector<int, 8> v; + int val = 10; for (auto _ : state) { - IntVec v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } + benchmark::DoNotOptimize(v); + v.push_back(val); } - state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); } BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); @@ -43,23 +39,25 @@ for (int i = 0; i < len; i++) { ia[i] = i; } + auto* from = ia.get(); + auto* to = from + len; for (auto _ : state) { - IntVec v(ia.get(), ia.get() + len); + benchmark::DoNotOptimize(from); + benchmark::DoNotOptimize(to); + absl::InlinedVector<int, 8> v(from, to); 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); + std::vector<int> v; + int val = 10; for (auto _ : state) { - std::vector<int> v; - for (int i = 0; i < len; i++) { - v.push_back(i); - } + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(val); + v.push_back(val); } - state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); } BENCHMARK(BM_StdVectorFill)->Range(0, 1024); @@ -124,7 +122,7 @@ void* user_data; }; -void BM_InlinedVectorTenAssignments(benchmark::State& state) { +void BM_InlinedVectorAssignments(benchmark::State& state) { const int len = state.range(0); using BufferVec = absl::InlinedVector<Buffer, 2>; @@ -133,18 +131,25 @@ BufferVec dst; for (auto _ : state) { - for (int i = 0; i < 10; ++i) { - dst = src; - } + benchmark::DoNotOptimize(dst); + benchmark::DoNotOptimize(src); + dst = src; } } -BENCHMARK(BM_InlinedVectorTenAssignments) - ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); +BENCHMARK(BM_InlinedVectorAssignments) + ->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); + absl::InlinedVector<int, 4> src{1, 2, 3}; + benchmark::DoNotOptimize(src); + absl::InlinedVector<int, 4> dst(std::move(src)); + benchmark::DoNotOptimize(dst); } } BENCHMARK(BM_CreateFromContainer); @@ -214,6 +219,8 @@ Vec b; for (auto _ : state) { using std::swap; + benchmark::DoNotOptimize(a); + benchmark::DoNotOptimize(b); swap(a, b); } } @@ -259,60 +266,44 @@ 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]); - } + 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]); - } + 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]); - } + 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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.data()); } state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } @@ -321,7 +312,8 @@ 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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.data()); } state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } @@ -330,54 +322,54 @@ 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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(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()); + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v.empty()); } - state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); } BENCHMARK(BM_StdVectorEmpty);
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index aff8d15..a308e78 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h
@@ -34,7 +34,6 @@ // are using a table in an unusual circumstance where allocation or calling a // linux syscall is unacceptable, this could interfere. // -// // This utility is internal-only. Use at your own risk. #ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h new file mode 100644 index 0000000..24059d9 --- /dev/null +++ b/absl/container/internal/inlined_vector.h
@@ -0,0 +1,126 @@ +// Copyright 2019 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 +// +// https://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_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_ +#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_ + +#include <cstddef> +#include <iterator> +#include <memory> + +#include "absl/meta/type_traits.h" + +namespace absl { +namespace inlined_vector_internal { + +template <typename InlinedVector> +class Storage; + +template <template <typename, size_t, typename> class InlinedVector, typename T, + size_t N, typename A> +class Storage<InlinedVector<T, N, A>> { + public: + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using pointer = typename allocator_type::pointer; + using const_pointer = typename allocator_type::const_pointer; + using reference = typename allocator_type::reference; + using const_reference = typename allocator_type::const_reference; + using rvalue_reference = typename allocator_type::value_type&&; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + explicit Storage(const allocator_type& a) : allocator_and_tag_(a) {} + + // TODO(johnsoncj): Make the below types and members private after migration + + // Holds whether the vector is allocated or not in the lowest bit and the size + // in the high bits: + // `size_ = (size << 1) | is_allocated;` + class Tag { + size_type size_; + + public: + Tag() : size_(0) {} + size_type size() const { return size_ / 2; } + void add_size(size_type n) { size_ += n * 2; } + void set_inline_size(size_type n) { size_ = n * 2; } + void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } + bool allocated() const { return size_ % 2; } + }; + + // Derives from `allocator_type` to use the empty base class optimization. + // If the `allocator_type` is stateless, we can store our instance for free. + class AllocatorAndTag : private allocator_type { + Tag tag_; + + public: + explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {} + Tag& tag() { return tag_; } + const Tag& tag() const { return tag_; } + allocator_type& allocator() { return *this; } + const allocator_type& allocator() const { return *this; } + }; + + class Allocation { + size_type capacity_; + pointer buffer_; + + public: + Allocation(allocator_type& a, size_type capacity) + : capacity_(capacity), buffer_(Create(a, capacity)) {} + void Dealloc(allocator_type& a) { + std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_); + } + size_type capacity() const { return capacity_; } + const_pointer buffer() const { return buffer_; } + pointer buffer() { return buffer_; } + static pointer Create(allocator_type& a, size_type n) { + return std::allocator_traits<allocator_type>::allocate(a, n); + } + }; + + // Stores either the inlined or allocated representation + union Rep { + using ValueTypeBuffer = + absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>; + using AllocationBuffer = + absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>; + + // Structs wrap the buffers to perform indirection that solves a bizarre + // compilation error on Visual Studio (all known versions). + struct InlinedRep { + ValueTypeBuffer inlined[N]; + }; + + struct AllocatedRep { + AllocationBuffer allocation; + }; + + InlinedRep inlined_storage; + AllocatedRep allocation_storage; + }; + + AllocatorAndTag allocator_and_tag_; + Rep rep_; +}; + +} // namespace inlined_vector_internal +} // namespace absl + +#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index c4f198b..85e3334 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -446,9 +446,7 @@ template <class Policy, class Hash, class Eq, class Alloc> class raw_hash_set; -inline bool IsValidCapacity(size_t n) { - return ((n + 1) & n) == 0 && n >= Group::kWidth - 1; -} +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } // PRECONDITION: // IsValidCapacity(capacity) @@ -470,13 +468,9 @@ ctrl[capacity] = kSentinel; } -// Rounds up the capacity to the next power of 2 minus 1 and ensures it is -// greater or equal to Group::kWidth - 1. +// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1. inline size_t NormalizeCapacity(size_t n) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - return n <= kMinCapacity - ? kMinCapacity - : (std::numeric_limits<size_t>::max)() >> LeadingZeros(n); + return n ? ~size_t{} >> LeadingZeros(n) : 1; } // We use 7/8th as maximum load factor. @@ -1507,6 +1501,7 @@ void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE { assert(IsValidCapacity(capacity_)); + assert(!is_small()); // Algorithm: // - mark all DELETED slots as EMPTY // - mark all FULL slots as DELETED @@ -1572,7 +1567,7 @@ void rehash_and_grow_if_necessary() { if (capacity_ == 0) { - resize(Group::kWidth - 1); + resize(1); } else if (size() <= CapacityToGrowth(capacity()) / 2) { // Squash DELETED without growing if there is enough capacity. drop_deletes_without_resize(); @@ -1619,17 +1614,15 @@ auto mask = g.MatchEmptyOrDeleted(); if (mask) { #if !defined(NDEBUG) - // We want to force small tables to have random entries too, so - // in debug build we will randomly insert in either the front or back of + // We want to add entropy even when ASLR is not enabled. + // In debug build we will randomly insert in either the front or back of // the group. // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (ShouldInsertBackwards(hash, ctrl_)) + if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) { return {seq.offset(mask.HighestBitSet()), seq.index()}; - else - return {seq.offset(mask.LowestBitSet()), seq.index()}; -#else - return {seq.offset(mask.LowestBitSet()), seq.index()}; + } #endif + return {seq.offset(mask.LowestBitSet()), seq.index()}; } assert(seq.index() < capacity_ && "full table!"); seq.next(); @@ -1732,11 +1725,28 @@ } ctrl_[i] = h; - ctrl_[((i - Group::kWidth) & capacity_) + Group::kWidth] = h; + ctrl_[((i - Group::kWidth) & capacity_) + 1 + + ((Group::kWidth - 1) & capacity_)] = h; } size_t& growth_left() { return settings_.template get<0>(); } + // The representation of the object has two modes: + // - small: For capacities < kWidth-1 + // - large: For the rest. + // + // Differences: + // - In small mode we are able to use the whole capacity. The extra control + // bytes give us at least one "empty" control byte to stop the iteration. + // This is important to make 1 a valid capacity. + // + // - In small mode only the first `capacity()` control bytes after the + // sentinel are valid. The rest contain dummy kEmpty values that do not + // represent a real slot. This is important to take into account on + // find_first_non_full(), where we never try ShouldInsertBackwards() for + // small tables. + bool is_small() const { return capacity_ < Group::kWidth - 1; } + hasher& hash_ref() { return settings_.template get<1>(); } const hasher& hash_ref() const { return settings_.template get<1>(); } key_equal& eq_ref() { return settings_.template get<2>(); }
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index b684571..02fd0bf 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc
@@ -55,13 +55,16 @@ using ::testing::UnorderedElementsAre; TEST(Util, NormalizeCapacity) { - constexpr size_t kMinCapacity = Group::kWidth - 1; - EXPECT_EQ(kMinCapacity, NormalizeCapacity(0)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(1)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(2)); - EXPECT_EQ(kMinCapacity, NormalizeCapacity(kMinCapacity)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 1)); - EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 2)); + EXPECT_EQ(1, NormalizeCapacity(0)); + EXPECT_EQ(1, NormalizeCapacity(1)); + EXPECT_EQ(3, NormalizeCapacity(2)); + EXPECT_EQ(3, NormalizeCapacity(3)); + EXPECT_EQ(7, NormalizeCapacity(4)); + EXPECT_EQ(7, NormalizeCapacity(7)); + EXPECT_EQ(15, NormalizeCapacity(8)); + EXPECT_EQ(15, NormalizeCapacity(15)); + EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1)); + EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2)); } TEST(Util, GrowthAndCapacity) { @@ -72,10 +75,7 @@ size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth)); // The capacity is large enough for `growth` EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth)); - if (growth < Group::kWidth - 1) { - // Fits in one group, that is the minimum capacity. - EXPECT_EQ(capacity, Group::kWidth - 1); - } else { + if (growth != 0 && capacity > 1) { // There is no smaller capacity that works. EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth)); } @@ -135,14 +135,14 @@ } TEST(BitMask, LeadingTrailing) { - EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).LeadingZeros()), 3); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).TrailingZeros()), 6); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).LeadingZeros()), 15); - EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).TrailingZeros()), 0); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0); - EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).LeadingZeros()), 0); - EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).TrailingZeros()), 15); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0); + EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15); EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3); EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1); @@ -814,7 +814,7 @@ TEST(Table, ClearBug) { IntTable t; constexpr size_t capacity = container_internal::Group::kWidth - 1; - constexpr size_t max_size = capacity / 2; + constexpr size_t max_size = capacity / 2 + 1; for (size_t i = 0; i < max_size; ++i) { t.insert(i); } @@ -845,6 +845,25 @@ EXPECT_TRUE(t.find(0) == t.end()); } +TEST(Table, EraseMaintainsValidIterator) { + IntTable t; + const int kNumElements = 100; + for (int i = 0; i < kNumElements; i ++) { + EXPECT_TRUE(t.emplace(i).second); + } + EXPECT_EQ(t.size(), kNumElements); + + int num_erase_calls = 0; + auto it = t.begin(); + while (it != t.end()) { + t.erase(it++); + num_erase_calls++; + } + + EXPECT_TRUE(t.empty()); + EXPECT_EQ(num_erase_calls, kNumElements); +} + // Collect N bad keys by following algorithm: // 1. Create an empty table and reserve it to 2 * N. // 2. Insert N random elements. @@ -1080,6 +1099,7 @@ ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); return {}; } + TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) { ProbeStatsPerSize stats; std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10}; @@ -1173,6 +1193,7 @@ ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); return {}; } + TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) { ProbeStatsPerSize stats; std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10}; @@ -1741,73 +1762,49 @@ EXPECT_FALSE(node); } -StringTable MakeSimpleTable(size_t size) { - StringTable t; - for (size_t i = 0; i < size; ++i) t.emplace(std::string(1, 'A' + i), ""); +IntTable MakeSimpleTable(size_t size) { + IntTable t; + while (t.size() < size) t.insert(t.size()); return t; } -std::string OrderOfIteration(const StringTable& t) { - std::string order; - for (auto& p : t) order += p.first; - return order; +std::vector<int> OrderOfIteration(const IntTable& t) { + return {t.begin(), t.end()}; } +// These IterationOrderChanges tests depend on non-deterministic behavior. +// We are injecting non-determinism from the pointer of the table, but do so in +// a way that only the page matters. We have to retry enough times to make sure +// we are touching different memory pages to cause the ordering to change. +// We also need to keep the old tables around to avoid getting the same memory +// blocks over and over. TEST(Table, IterationOrderChangesByInstance) { - // Needs to be more than kWidth elements to be able to affect order. - const StringTable reference = MakeSimpleTable(20); + for (size_t size : {2, 6, 12, 20}) { + const auto reference_table = MakeSimpleTable(size); + const auto reference = OrderOfIteration(reference_table); - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. It should not take many tries - // for that. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - std::vector<StringTable> garbage; - for (int i = 0; i < 10; ++i) { - auto trial = MakeSimpleTable(20); - if (OrderOfIteration(trial) != OrderOfIteration(reference)) { - // We are done. - return; + std::vector<IntTable> tables; + bool found_difference = false; + for (int i = 0; !found_difference && i < 500; ++i) { + tables.push_back(MakeSimpleTable(size)); + found_difference = OrderOfIteration(tables.back()) != reference; } - garbage.push_back(std::move(trial)); + if (!found_difference) { + FAIL() + << "Iteration order remained the same across many attempts with size " + << size; + } } - FAIL(); } TEST(Table, IterationOrderChangesOnRehash) { - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. It should not take many tries - // for that. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - std::vector<StringTable> garbage; - for (int i = 0; i < 10; ++i) { - // Needs to be more than kWidth elements to be able to affect order. - StringTable t = MakeSimpleTable(20); - const std::string reference = OrderOfIteration(t); + std::vector<IntTable> garbage; + for (int i = 0; i < 500; ++i) { + auto t = MakeSimpleTable(20); + const auto reference = OrderOfIteration(t); // Force rehash to the same size. t.rehash(0); - std::string trial = OrderOfIteration(t); - if (trial != reference) { - // We are done. - return; - } - garbage.push_back(std::move(t)); - } - FAIL(); -} - -TEST(Table, IterationOrderChangesForSmallTables) { - // Since order is non-deterministic we can't just try once and verify. - // We'll try until we find that order changed. - // Important: we have to keep the old tables around. Otherwise tcmalloc will - // just give us the same blocks and we would be doing the same order again. - StringTable reference_table = MakeSimpleTable(5); - const std::string reference = OrderOfIteration(reference_table); - std::vector<StringTable> garbage; - for (int i = 0; i < 50; ++i) { - StringTable t = MakeSimpleTable(5); - std::string trial = OrderOfIteration(t); + auto trial = OrderOfIteration(t); if (trial != reference) { // We are done. return; @@ -1817,6 +1814,24 @@ FAIL() << "Iteration order remained the same across many attempts."; } +// Verify that pointers are invalidated as soon as a second element is inserted. +// This prevents dependency on pointer stability on small tables. +TEST(Table, UnstablePointers) { + IntTable table; + + const auto addr = [&](int i) { + return reinterpret_cast<uintptr_t>(&*table.find(i)); + }; + + table.insert(0); + const uintptr_t old_ptr = addr(0); + + // This causes a rehash. + table.insert(1); + + EXPECT_NE(old_ptr, addr(0)); +} + // Confirm that we assert if we try to erase() end(). TEST(TableDeathTest, EraseOfEndAsserts) { // Use an assert with side-effects to figure out if they are actually enabled. @@ -1857,6 +1872,7 @@ #ifdef ADDRESS_SANITIZER TEST(Sanitizer, PoisoningUnused) { IntTable t; + t.reserve(5); // Insert something to force an allocation. int64_t& v1 = *t.insert(0).first;
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake index f68895d..5084958 100644 --- a/absl/copts/AbseilConfigureCopts.cmake +++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -5,26 +5,33 @@ set(ABSL_HAVE_LSAN OFF) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(ABSL_DEFAULT_COPTS "${GCC_FLAGS}") - set(ABSL_TEST_COPTS "${GCC_FLAGS};${GCC_TEST_FLAGS}") - set(ABSL_EXCEPTIONS_FLAG "${GCC_EXCEPTIONS_FLAGS}") + set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_GCC_EXCEPTIONS_FLAGS}") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # MATCHES so we get both Clang and AppleClang - set(ABSL_DEFAULT_COPTS "${LLVM_FLAGS}") - set(ABSL_TEST_COPTS "${LLVM_FLAGS};${LLVM_TEST_FLAGS}") - set(ABSL_EXCEPTIONS_FLAG "${LLVM_EXCEPTIONS_FLAGS}") - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # AppleClang doesn't have lsan - # https://developer.apple.com/documentation/code_diagnostics - if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5) - set(ABSL_LSAN_LINKOPTS "-fsanitize=leak") - set(ABSL_HAVE_LSAN ON) + if (MSVC) + # clang-cl is half MSVC, half LLVM + set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}") + else() + set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # AppleClang doesn't have lsan + # https://developer.apple.com/documentation/code_diagnostics + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5) + set(ABSL_LSAN_LINKOPTS "-fsanitize=leak") + set(ABSL_HAVE_LSAN ON) + endif() endif() endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(ABSL_DEFAULT_COPTS "${MSVC_FLAGS}") - set(ABSL_TEST_COPTS "${MSVC_FLAGS};${MSVC_TEST_FLAGS}") - set(ABSL_EXCEPTIONS_FLAG "${MSVC_EXCEPTIONS_FLAGS}") + set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}") + set(ABSL_EXCEPTIONS_FLAG "${ABSL_MSVC_EXCEPTIONS_FLAGS}") else() message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags") set(ABSL_DEFAULT_COPTS "") @@ -42,4 +49,4 @@ set(ABSL_CXX_STANDARD 11) else() set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}") -endif() \ No newline at end of file +endif()
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake index 80c9819..9031bfa 100644 --- a/absl/copts/GENERATED_AbseilCopts.cmake +++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -3,11 +3,87 @@ # (1) Edit absl/copts/copts.py. # (2) Run `python <path_to_absl>/copts/generate_copts.py`. -list(APPEND GCC_EXCEPTIONS_FLAGS +list(APPEND ABSL_CLANG_CL_EXCEPTIONS_FLAGS + "/U_HAS_EXCEPTIONS" + "/D_HAS_EXCEPTIONS=1" + "/EHsc" +) + +list(APPEND ABSL_CLANG_CL_FLAGS + "/W3" + "-Wno-c++98-compat-pedantic" + "-Wno-conversion" + "-Wno-covered-switch-default" + "-Wno-deprecated" + "-Wno-disabled-macro-expansion" + "-Wno-double-promotion" + "-Wno-comma" + "-Wno-extra-semi" + "-Wno-extra-semi-stmt" + "-Wno-packed" + "-Wno-padded" + "-Wno-sign-compare" + "-Wno-float-conversion" + "-Wno-float-equal" + "-Wno-format-nonliteral" + "-Wno-gcc-compat" + "-Wno-global-constructors" + "-Wno-exit-time-destructors" + "-Wno-nested-anon-types" + "-Wno-non-modular-include-in-module" + "-Wno-old-style-cast" + "-Wno-range-loop-analysis" + "-Wno-reserved-id-macro" + "-Wno-shorten-64-to-32" + "-Wno-switch-enum" + "-Wno-thread-safety-negative" + "-Wno-undef" + "-Wno-unknown-warning-option" + "-Wno-unreachable-code" + "-Wno-unused-macros" + "-Wno-weak-vtables" + "-Wbitfield-enum-conversion" + "-Wbool-conversion" + "-Wconstant-conversion" + "-Wenum-conversion" + "-Wint-conversion" + "-Wliteral-conversion" + "-Wnon-literal-null-conversion" + "-Wnull-conversion" + "-Wobjc-literal-conversion" + "-Wno-sign-conversion" + "-Wstring-conversion" + "/DNOMINMAX" + "/DWIN32_LEAN_AND_MEAN" + "/D_CRT_SECURE_NO_WARNINGS" + "/D_SCL_SECURE_NO_WARNINGS" + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE" +) + +list(APPEND ABSL_CLANG_CL_TEST_FLAGS + "-Wno-c99-extensions" + "-Wno-missing-noreturn" + "-Wno-missing-prototypes" + "-Wno-missing-variable-declarations" + "-Wno-null-conversion" + "-Wno-shadow" + "-Wno-shift-sign-overflow" + "-Wno-sign-compare" + "-Wno-unused-function" + "-Wno-unused-member-function" + "-Wno-unused-parameter" + "-Wno-unused-private-field" + "-Wno-unused-template" + "-Wno-used-but-marked-unused" + "-Wno-zero-as-null-pointer-constant" + "-Wno-gnu-zero-variadic-macro-arguments" +) + +list(APPEND ABSL_GCC_EXCEPTIONS_FLAGS "-fexceptions" ) -list(APPEND GCC_FLAGS +list(APPEND ABSL_GCC_FLAGS "-Wall" "-Wextra" "-Wcast-qual" @@ -20,10 +96,11 @@ "-Wvarargs" "-Wvla" "-Wwrite-strings" + "-Wno-missing-field-initializers" "-Wno-sign-compare" ) -list(APPEND GCC_TEST_FLAGS +list(APPEND ABSL_GCC_TEST_FLAGS "-Wno-conversion-null" "-Wno-missing-declarations" "-Wno-sign-compare" @@ -32,11 +109,11 @@ "-Wno-unused-private-field" ) -list(APPEND LLVM_EXCEPTIONS_FLAGS +list(APPEND ABSL_LLVM_EXCEPTIONS_FLAGS "-fexceptions" ) -list(APPEND LLVM_FLAGS +list(APPEND ABSL_LLVM_FLAGS "-Wall" "-Wextra" "-Weverything" @@ -84,7 +161,7 @@ "-Wstring-conversion" ) -list(APPEND LLVM_TEST_FLAGS +list(APPEND ABSL_LLVM_TEST_FLAGS "-Wno-c99-extensions" "-Wno-missing-noreturn" "-Wno-missing-prototypes" @@ -103,28 +180,28 @@ "-Wno-gnu-zero-variadic-macro-arguments" ) -list(APPEND MSVC_EXCEPTIONS_FLAGS +list(APPEND ABSL_MSVC_EXCEPTIONS_FLAGS "/U_HAS_EXCEPTIONS" "/D_HAS_EXCEPTIONS=1" "/EHsc" ) -list(APPEND MSVC_FLAGS +list(APPEND ABSL_MSVC_FLAGS "/W3" + "/DNOMINMAX" + "/DWIN32_LEAN_AND_MEAN" + "/D_CRT_SECURE_NO_WARNINGS" + "/D_SCL_SECURE_NO_WARNINGS" + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE" "/wd4005" "/wd4068" "/wd4180" "/wd4244" "/wd4267" "/wd4800" - "/DNOMINMAX" - "/DWIN32_LEAN_AND_MEAN" - "/D_CRT_SECURE_NO_WARNINGS" - "/D_SCL_SECURE_NO_WARNINGS" - "/D_ENABLE_EXTENDED_ALIGNED_STORAGE" ) -list(APPEND MSVC_TEST_FLAGS +list(APPEND ABSL_MSVC_TEST_FLAGS "/wd4018" "/wd4101" "/wd4503"
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl index a001347..e05a58e 100644 --- a/absl/copts/GENERATED_copts.bzl +++ b/absl/copts/GENERATED_copts.bzl
@@ -4,11 +4,87 @@ (2) Run `python <path_to_absl>/copts/generate_copts.py`. """ -GCC_EXCEPTIONS_FLAGS = [ +ABSL_CLANG_CL_EXCEPTIONS_FLAGS = [ + "/U_HAS_EXCEPTIONS", + "/D_HAS_EXCEPTIONS=1", + "/EHsc", +] + +ABSL_CLANG_CL_FLAGS = [ + "/W3", + "-Wno-c++98-compat-pedantic", + "-Wno-conversion", + "-Wno-covered-switch-default", + "-Wno-deprecated", + "-Wno-disabled-macro-expansion", + "-Wno-double-promotion", + "-Wno-comma", + "-Wno-extra-semi", + "-Wno-extra-semi-stmt", + "-Wno-packed", + "-Wno-padded", + "-Wno-sign-compare", + "-Wno-float-conversion", + "-Wno-float-equal", + "-Wno-format-nonliteral", + "-Wno-gcc-compat", + "-Wno-global-constructors", + "-Wno-exit-time-destructors", + "-Wno-nested-anon-types", + "-Wno-non-modular-include-in-module", + "-Wno-old-style-cast", + "-Wno-range-loop-analysis", + "-Wno-reserved-id-macro", + "-Wno-shorten-64-to-32", + "-Wno-switch-enum", + "-Wno-thread-safety-negative", + "-Wno-undef", + "-Wno-unknown-warning-option", + "-Wno-unreachable-code", + "-Wno-unused-macros", + "-Wno-weak-vtables", + "-Wbitfield-enum-conversion", + "-Wbool-conversion", + "-Wconstant-conversion", + "-Wenum-conversion", + "-Wint-conversion", + "-Wliteral-conversion", + "-Wnon-literal-null-conversion", + "-Wnull-conversion", + "-Wobjc-literal-conversion", + "-Wno-sign-conversion", + "-Wstring-conversion", + "/DNOMINMAX", + "/DWIN32_LEAN_AND_MEAN", + "/D_CRT_SECURE_NO_WARNINGS", + "/D_SCL_SECURE_NO_WARNINGS", + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", +] + +ABSL_CLANG_CL_TEST_FLAGS = [ + "-Wno-c99-extensions", + "-Wno-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-missing-variable-declarations", + "-Wno-null-conversion", + "-Wno-shadow", + "-Wno-shift-sign-overflow", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-member-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-template", + "-Wno-used-but-marked-unused", + "-Wno-zero-as-null-pointer-constant", + "-Wno-gnu-zero-variadic-macro-arguments", +] + +ABSL_GCC_EXCEPTIONS_FLAGS = [ "-fexceptions", ] -GCC_FLAGS = [ +ABSL_GCC_FLAGS = [ "-Wall", "-Wextra", "-Wcast-qual", @@ -21,10 +97,11 @@ "-Wvarargs", "-Wvla", "-Wwrite-strings", + "-Wno-missing-field-initializers", "-Wno-sign-compare", ] -GCC_TEST_FLAGS = [ +ABSL_GCC_TEST_FLAGS = [ "-Wno-conversion-null", "-Wno-missing-declarations", "-Wno-sign-compare", @@ -33,11 +110,11 @@ "-Wno-unused-private-field", ] -LLVM_EXCEPTIONS_FLAGS = [ +ABSL_LLVM_EXCEPTIONS_FLAGS = [ "-fexceptions", ] -LLVM_FLAGS = [ +ABSL_LLVM_FLAGS = [ "-Wall", "-Wextra", "-Weverything", @@ -85,7 +162,7 @@ "-Wstring-conversion", ] -LLVM_TEST_FLAGS = [ +ABSL_LLVM_TEST_FLAGS = [ "-Wno-c99-extensions", "-Wno-missing-noreturn", "-Wno-missing-prototypes", @@ -104,28 +181,28 @@ "-Wno-gnu-zero-variadic-macro-arguments", ] -MSVC_EXCEPTIONS_FLAGS = [ +ABSL_MSVC_EXCEPTIONS_FLAGS = [ "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc", ] -MSVC_FLAGS = [ +ABSL_MSVC_FLAGS = [ "/W3", + "/DNOMINMAX", + "/DWIN32_LEAN_AND_MEAN", + "/D_CRT_SECURE_NO_WARNINGS", + "/D_SCL_SECURE_NO_WARNINGS", + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", "/wd4005", "/wd4068", "/wd4180", "/wd4244", "/wd4267", "/wd4800", - "/DNOMINMAX", - "/DWIN32_LEAN_AND_MEAN", - "/D_CRT_SECURE_NO_WARNINGS", - "/D_SCL_SECURE_NO_WARNINGS", - "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", ] -MSVC_TEST_FLAGS = [ +ABSL_MSVC_TEST_FLAGS = [ "/wd4018", "/wd4101", "/wd4503",
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl index 57cd3f6..1655add 100644 --- a/absl/copts/configure_copts.bzl +++ b/absl/copts/configure_copts.bzl
@@ -6,35 +6,35 @@ load( "//absl:copts/GENERATED_copts.bzl", - "GCC_EXCEPTIONS_FLAGS", - "GCC_FLAGS", - "GCC_TEST_FLAGS", - "LLVM_EXCEPTIONS_FLAGS", - "LLVM_FLAGS", - "LLVM_TEST_FLAGS", - "MSVC_EXCEPTIONS_FLAGS", - "MSVC_FLAGS", - "MSVC_TEST_FLAGS", + "ABSL_GCC_EXCEPTIONS_FLAGS", + "ABSL_GCC_FLAGS", + "ABSL_GCC_TEST_FLAGS", + "ABSL_LLVM_EXCEPTIONS_FLAGS", + "ABSL_LLVM_FLAGS", + "ABSL_LLVM_TEST_FLAGS", + "ABSL_MSVC_EXCEPTIONS_FLAGS", + "ABSL_MSVC_FLAGS", + "ABSL_MSVC_TEST_FLAGS", ) ABSL_DEFAULT_COPTS = select({ - "//absl:windows": MSVC_FLAGS, - "//absl:llvm_compiler": LLVM_FLAGS, - "//conditions:default": GCC_FLAGS, + "//absl:windows": ABSL_MSVC_FLAGS, + "//absl:llvm_compiler": ABSL_LLVM_FLAGS, + "//conditions:default": ABSL_GCC_FLAGS, }) # in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts # to their (included header) dependencies and fail to build outside absl ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({ - "//absl:windows": MSVC_TEST_FLAGS, - "//absl:llvm_compiler": LLVM_TEST_FLAGS, - "//conditions:default": GCC_TEST_FLAGS, + "//absl:windows": ABSL_MSVC_TEST_FLAGS, + "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS, + "//conditions:default": ABSL_GCC_TEST_FLAGS, }) ABSL_EXCEPTIONS_FLAG = select({ - "//absl:windows": MSVC_EXCEPTIONS_FLAGS, - "//absl:llvm_compiler": LLVM_EXCEPTIONS_FLAGS, - "//conditions:default": GCC_EXCEPTIONS_FLAGS, + "//absl:windows": ABSL_MSVC_EXCEPTIONS_FLAGS, + "//absl:llvm_compiler": ABSL_LLVM_EXCEPTIONS_FLAGS, + "//conditions:default": ABSL_GCC_EXCEPTIONS_FLAGS, }) ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({
diff --git a/absl/copts/copts.py b/absl/copts/copts.py index 4da8442..3c9d429 100644 --- a/absl/copts/copts.py +++ b/absl/copts/copts.py
@@ -10,8 +10,120 @@ The generated copts are consumed by configure_copts.bzl and AbseilConfigureCopts.cmake. """ + +# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ... +MSVC_BIG_WARNING_FLAGS = [ + "/W3", +] + +LLVM_BIG_WARNING_FLAGS = [ + "-Wall", + "-Wextra", + "-Weverything", +] + +# Docs on single flags is preceded by a comment. +# Docs on groups of flags is preceded by ###. +LLVM_DISABLE_WARNINGS_FLAGS = [ + # Abseil does not support C++98 + "-Wno-c++98-compat-pedantic", + # Turns off all implicit conversion warnings. Most are re-enabled below. + "-Wno-conversion", + "-Wno-covered-switch-default", + "-Wno-deprecated", + "-Wno-disabled-macro-expansion", + "-Wno-double-promotion", + ### + # Turned off as they include valid C++ code. + "-Wno-comma", + "-Wno-extra-semi", + "-Wno-extra-semi-stmt", + "-Wno-packed", + "-Wno-padded", + ### + # Google style does not use unsigned integers, though STL containers + # have unsigned types. + "-Wno-sign-compare", + ### + "-Wno-float-conversion", + "-Wno-float-equal", + "-Wno-format-nonliteral", + # Too aggressive: warns on Clang extensions enclosed in Clang-only + # compilation paths. + "-Wno-gcc-compat", + ### + # Some internal globals are necessary. Don't do this at home. + "-Wno-global-constructors", + "-Wno-exit-time-destructors", + ### + "-Wno-nested-anon-types", + "-Wno-non-modular-include-in-module", + "-Wno-old-style-cast", + # Warns on preferred usage of non-POD types such as string_view + "-Wno-range-loop-analysis", + "-Wno-reserved-id-macro", + "-Wno-shorten-64-to-32", + "-Wno-switch-enum", + "-Wno-thread-safety-negative", + "-Wno-undef", + "-Wno-unknown-warning-option", + "-Wno-unreachable-code", + # Causes warnings on include guards + "-Wno-unused-macros", + "-Wno-weak-vtables", + ### + # Implicit conversion warnings turned off by -Wno-conversion + # which are re-enabled below. + "-Wbitfield-enum-conversion", + "-Wbool-conversion", + "-Wconstant-conversion", + "-Wenum-conversion", + "-Wint-conversion", + "-Wliteral-conversion", + "-Wnon-literal-null-conversion", + "-Wnull-conversion", + "-Wobjc-literal-conversion", + "-Wno-sign-conversion", + "-Wstring-conversion", +] + +LLVM_TEST_DISABLE_WARNINGS_FLAGS = [ + "-Wno-c99-extensions", + "-Wno-missing-noreturn", + "-Wno-missing-prototypes", + "-Wno-missing-variable-declarations", + "-Wno-null-conversion", + "-Wno-shadow", + "-Wno-shift-sign-overflow", + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-member-function", + "-Wno-unused-parameter", + "-Wno-unused-private-field", + "-Wno-unused-template", + "-Wno-used-but-marked-unused", + "-Wno-zero-as-null-pointer-constant", + # gtest depends on this GNU extension being offered. + "-Wno-gnu-zero-variadic-macro-arguments", +] + +MSVC_STYLE_EXCEPTIONS_FLAGS = [ + "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc" +] + +MSVC_DEFINES = [ + "/DNOMINMAX", # Don't define min and max macros (windows.h) + # Don't bloat namespace with incompatible winsock versions. + "/DWIN32_LEAN_AND_MEAN", + # Don't warn about usage of insecure C functions. + "/D_CRT_SECURE_NO_WARNINGS", + "/D_SCL_SECURE_NO_WARNINGS", + # Introduced in VS 2017 15.8, allow overaligned types in aligned_storage + "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", +] + COPT_VARS = { - "GCC_FLAGS": [ + "ABSL_GCC_FLAGS": [ "-Wall", "-Wextra", "-Wcast-qual", @@ -24,11 +136,15 @@ "-Wvarargs", "-Wvla", # variable-length array "-Wwrite-strings", + # gcc-4.x has spurious missing field initializer warnings. + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750 + # Remove when gcc-4.x is no longer supported. + "-Wno-missing-field-initializers", # Google style does not use unsigned integers, though STL containers # have unsigned types. "-Wno-sign-compare", ], - "GCC_TEST_FLAGS": [ + "ABSL_GCC_TEST_FLAGS": [ "-Wno-conversion-null", "-Wno-missing-declarations", "-Wno-sign-compare", @@ -36,98 +152,15 @@ "-Wno-unused-parameter", "-Wno-unused-private-field", ], - "GCC_EXCEPTIONS_FLAGS": ["-fexceptions"], - - # Docs on single flags is preceded by a comment. - # Docs on groups of flags is preceded by ###. - "LLVM_FLAGS": [ - "-Wall", - "-Wextra", - "-Weverything", - # Abseil does not support C++98 - "-Wno-c++98-compat-pedantic", - # Turns off all implicit conversion warnings. Most are re-enabled below. - "-Wno-conversion", - "-Wno-covered-switch-default", - "-Wno-deprecated", - "-Wno-disabled-macro-expansion", - "-Wno-double-promotion", - ### - # Turned off as they include valid C++ code. - "-Wno-comma", - "-Wno-extra-semi", - "-Wno-extra-semi-stmt", - "-Wno-packed", - "-Wno-padded", - ### - # Google style does not use unsigned integers, though STL containers - # have unsigned types. - "-Wno-sign-compare", - ### - "-Wno-float-conversion", - "-Wno-float-equal", - "-Wno-format-nonliteral", - # Too aggressive: warns on Clang extensions enclosed in Clang-only - # compilation paths. - "-Wno-gcc-compat", - ### - # Some internal globals are necessary. Don't do this at home. - "-Wno-global-constructors", - "-Wno-exit-time-destructors", - ### - "-Wno-nested-anon-types", - "-Wno-non-modular-include-in-module", - "-Wno-old-style-cast", - # Warns on preferred usage of non-POD types such as string_view - "-Wno-range-loop-analysis", - "-Wno-reserved-id-macro", - "-Wno-shorten-64-to-32", - "-Wno-switch-enum", - "-Wno-thread-safety-negative", - "-Wno-undef", - "-Wno-unknown-warning-option", - "-Wno-unreachable-code", - # Causes warnings on include guards - "-Wno-unused-macros", - "-Wno-weak-vtables", - ### - # Implicit conversion warnings turned off by -Wno-conversion - # which are re-enabled below. - "-Wbitfield-enum-conversion", - "-Wbool-conversion", - "-Wconstant-conversion", - "-Wenum-conversion", - "-Wint-conversion", - "-Wliteral-conversion", - "-Wnon-literal-null-conversion", - "-Wnull-conversion", - "-Wobjc-literal-conversion", - "-Wno-sign-conversion", - "-Wstring-conversion", - ], - "LLVM_TEST_FLAGS": [ - "-Wno-c99-extensions", - "-Wno-missing-noreturn", - "-Wno-missing-prototypes", - "-Wno-missing-variable-declarations", - "-Wno-null-conversion", - "-Wno-shadow", - "-Wno-shift-sign-overflow", - "-Wno-sign-compare", - "-Wno-unused-function", - "-Wno-unused-member-function", - "-Wno-unused-parameter", - "-Wno-unused-private-field", - "-Wno-unused-template", - "-Wno-used-but-marked-unused", - "-Wno-zero-as-null-pointer-constant", - # gtest depends on this GNU extension being offered. - "-Wno-gnu-zero-variadic-macro-arguments", - ], - "LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"], - # /Wall with msvc includes unhelpful warnings such as C4711, C4710, ... - "MSVC_FLAGS": [ - "/W3", + "ABSL_GCC_EXCEPTIONS_FLAGS": ["-fexceptions"], + "ABSL_LLVM_FLAGS": LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"], + "ABSL_CLANG_CL_FLAGS": (MSVC_BIG_WARNING_FLAGS + + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES), + "ABSL_CLANG_CL_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, + "ABSL_CLANG_CL_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, + "ABSL_MSVC_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [ "/wd4005", # macro-redefinition "/wd4068", # unknown pragma "/wd4180", # qualifier applied to function type has no meaning; ignored @@ -135,21 +168,11 @@ "/wd4267", # conversion from 'size_t' to 'type', possible loss of data # forcing value to bool 'true' or 'false' (performance warning) "/wd4800", - "/DNOMINMAX", # Don't define min and max macros (windows.h) - # Don't bloat namespace with incompatible winsock versions. - "/DWIN32_LEAN_AND_MEAN", - # Don't warn about usage of insecure C functions. - "/D_CRT_SECURE_NO_WARNINGS", - "/D_SCL_SECURE_NO_WARNINGS", - # Introduced in VS 2017 15.8, allow overaligned types in aligned_storage - "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", ], - "MSVC_TEST_FLAGS": [ + "ABSL_MSVC_TEST_FLAGS": [ "/wd4018", # signed/unsigned mismatch "/wd4101", # unreferenced local variable "/wd4503", # decorated name length exceeded, name was truncated ], - "MSVC_EXCEPTIONS_FLAGS": [ - "/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc" - ] + "ABSL_MSVC_EXCEPTIONS_FLAGS": MSVC_STYLE_EXCEPTIONS_FLAGS, }
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h index 64c3f1e..ca8003e 100644 --- a/absl/debugging/internal/address_is_readable.h +++ b/absl/debugging/internal/address_is_readable.h
@@ -11,7 +11,6 @@ // 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_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_ #define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index d410a23..883b92d 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc
@@ -176,6 +176,7 @@ TEST(DemangleRegression, NegativeLength) { TestOnInput("_ZZn4"); } + TEST(DemangleRegression, DeeplyNestedArrayType) { const int depth = 100000; std::string data = "_ZStI";
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc index 248966b..25aa8bd 100644 --- a/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -33,6 +33,7 @@ #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" + #include "absl/base/internal/raw_logging.h" #if defined(__linux__) && defined(__i386__)
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc index a1cae96..ffe3d1b 100644 --- a/absl/debugging/leak_check.cc +++ b/absl/debugging/leak_check.cc
@@ -11,6 +11,7 @@ // 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. + // Wrappers around lsan_interface functions. // When lsan is not linked in, these functions are not available, // therefore Abseil code which depends on these functions is conditioned on the
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc index 9935adf..9de8782 100644 --- a/absl/debugging/stacktrace.cc +++ b/absl/debugging/stacktrace.cc
@@ -46,6 +46,7 @@ #include ABSL_STACKTRACE_INL_HEADER #else # error Cannot calculate stack trace: will need to write for your environment + # include "absl/debugging/internal/stacktrace_aarch64-inl.inc" # include "absl/debugging/internal/stacktrace_arm-inl.inc" # include "absl/debugging/internal/stacktrace_generic-inl.inc"
diff --git a/absl/hash/hash.h b/absl/hash/hash.h index 94cb674..c0ede35 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h
@@ -309,4 +309,5 @@ }; } // namespace absl + #endif // ABSL_HASH_HASH_H_
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index a2430e7..af95938 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -276,6 +276,7 @@ const std::string dup = "foofoo"; const std::string large = "large"; const std::string huge = std::string(5000, 'a'); + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( std::string(), absl::string_view(), std::string(""), absl::string_view(""),
diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h index 1b3b4ef..b43d340 100644 --- a/absl/hash/internal/city.h +++ b/absl/hash/internal/city.h
@@ -49,7 +49,6 @@ #include <stdlib.h> // for size_t. #include <utility> - namespace absl { namespace hash_internal {
diff --git a/absl/memory/memory.h b/absl/memory/memory.h index a0d0714..5a4a1a1 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h
@@ -47,19 +47,14 @@ // X* NewX(int, int); // auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>. // -// The purpose of WrapUnique is to automatically deduce the pointer type. If you -// wish to make the type explicit, for readability reasons or because you prefer -// to use a base-class pointer rather than a derived one, just use +// Do not call WrapUnique with an explicit type, as in +// `WrapUnique<X>(NewX(1, 2))`. The purpose of WrapUnique is to automatically +// deduce the pointer type. If you wish to make the type explicit, just use // `std::unique_ptr` directly. // -// Example: -// X* Factory(int, int); -// auto x = std::unique_ptr<X>(Factory(1, 2)); +// auto x = std::unique_ptr<X>(NewX(1, 2)); // - or - -// std::unique_ptr<X> x(Factory(1, 2)); -// -// This has the added advantage of working whether Factory returns a raw -// pointer or a `std::unique_ptr`. +// std::unique_ptr<X> x(NewX(1, 2)); // // While `absl::WrapUnique` is useful for capturing the output of a raw // pointer factory, prefer 'absl::make_unique<T>(args...)' over
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index 8a788de..fbdc921 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h
@@ -483,6 +483,69 @@ } // namespace type_traits_internal +// An internal namespace that is required to implement the C++17 swap traits. +// It is not further nested in type_traits_internal to avoid long symbol names. +namespace swap_internal { + +// Necessary for the traits. +using std::swap; + +// This declaration prevents global `swap` and `absl::swap` overloads from being +// considered unless ADL picks them up. +void swap(); + +template <class T> +using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>())); + +// NOTE: This dance with the default template parameter is for MSVC. +template <class T, + class IsNoexcept = std::integral_constant< + bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>> +using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type; + +// IsSwappable +// +// Determines whether the standard swap idiom is a valid expression for +// arguments of type `T`. +template <class T> +struct IsSwappable + : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {}; + +// IsNothrowSwappable +// +// Determines whether the standard swap idiom is a valid expression for +// arguments of type `T` and is noexcept. +template <class T> +struct IsNothrowSwappable + : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {}; + +// Swap() +// +// Performs the swap idiom from a namespace where valid candidates may only be +// found in `std` or via ADL. +template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0> +void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) { + swap(lhs, rhs); +} + +// StdSwapIsUnconstrained +// +// Some standard library implementations are broken in that they do not +// constrain `std::swap`. This will effectively tell us if we are dealing with +// one of those implementations. +using StdSwapIsUnconstrained = IsSwappable<void()>; + +} // namespace swap_internal + +namespace type_traits_internal { + +// Make the swap-related traits/function accessible from this namespace. +using swap_internal::IsNothrowSwappable; +using swap_internal::IsSwappable; +using swap_internal::Swap; +using swap_internal::StdSwapIsUnconstrained; + +} // namespace type_traits_internal } // namespace absl #endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index 29a6db6..912336e 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc
@@ -953,4 +953,85 @@ #endif // _LIBCPP_VERSION } +namespace adl_namespace { + +struct DeletedSwap { +}; + +void swap(DeletedSwap&, DeletedSwap&) = delete; + +struct SpecialNoexceptSwap { + SpecialNoexceptSwap(SpecialNoexceptSwap&&) {} + SpecialNoexceptSwap& operator=(SpecialNoexceptSwap&&) { return *this; } + ~SpecialNoexceptSwap() = default; +}; + +void swap(SpecialNoexceptSwap&, SpecialNoexceptSwap&) noexcept {} + +} // namespace adl_namespace + +TEST(TypeTraitsTest, IsSwappable) { + using absl::type_traits_internal::IsSwappable; + using absl::type_traits_internal::StdSwapIsUnconstrained; + + EXPECT_TRUE(IsSwappable<int>::value); + + struct S {}; + EXPECT_TRUE(IsSwappable<S>::value); + + struct NoConstruct { + NoConstruct(NoConstruct&&) = delete; + NoConstruct& operator=(NoConstruct&&) { return *this; } + ~NoConstruct() = default; + }; + + EXPECT_EQ(IsSwappable<NoConstruct>::value, StdSwapIsUnconstrained::value); + struct NoAssign { + NoAssign(NoAssign&&) {} + NoAssign& operator=(NoAssign&&) = delete; + ~NoAssign() = default; + }; + + EXPECT_EQ(IsSwappable<NoAssign>::value, StdSwapIsUnconstrained::value); + + EXPECT_FALSE(IsSwappable<adl_namespace::DeletedSwap>::value); + + EXPECT_TRUE(IsSwappable<adl_namespace::SpecialNoexceptSwap>::value); +} + +TEST(TypeTraitsTest, IsNothrowSwappable) { + using absl::type_traits_internal::IsNothrowSwappable; + using absl::type_traits_internal::StdSwapIsUnconstrained; + + EXPECT_TRUE(IsNothrowSwappable<int>::value); + + struct NonNoexceptMoves { + NonNoexceptMoves(NonNoexceptMoves&&) {} + NonNoexceptMoves& operator=(NonNoexceptMoves&&) { return *this; } + ~NonNoexceptMoves() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NonNoexceptMoves>::value); + + struct NoConstruct { + NoConstruct(NoConstruct&&) = delete; + NoConstruct& operator=(NoConstruct&&) { return *this; } + ~NoConstruct() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NoConstruct>::value); + + struct NoAssign { + NoAssign(NoAssign&&) {} + NoAssign& operator=(NoAssign&&) = delete; + ~NoAssign() = default; + }; + + EXPECT_FALSE(IsNothrowSwappable<NoAssign>::value); + + EXPECT_FALSE(IsNothrowSwappable<adl_namespace::DeletedSwap>::value); + + EXPECT_TRUE(IsNothrowSwappable<adl_namespace::SpecialNoexceptSwap>::value); +} + } // namespace
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index 33f528c..93b62c5 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc
@@ -123,6 +123,28 @@ return MakeUint128(0, static_cast<uint64_t>(v)); } + +#if defined(__clang__) && !defined(__SSE3__) +// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 +// Casting from long double to uint64_t is miscompiled and drops bits. +// It is more work, so only use when we need the workaround. +uint128 MakeUint128FromFloat(long double v) { + // Go 50 bits at a time, that fits in a double + static_assert(std::numeric_limits<double>::digits >= 50, ""); + static_assert(std::numeric_limits<long double>::digits <= 150, ""); + // Undefined behavior if v is not finite or cannot fit into uint128. + assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128)); + + v = std::ldexp(v, -100); + uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w0), 50); + uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + v = std::ldexp(v - static_cast<double>(w1), 50); + uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v))); + return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) | + static_cast<uint128>(w2); +} +#endif // __clang__ && !__SSE3__ } // namespace uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index c0ec03d..2f5b8ad 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h
@@ -53,7 +53,6 @@ namespace absl { - // uint128 // // An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index 216ec50..5e1b5ec 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc
@@ -271,6 +271,20 @@ EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0); EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5); EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9); + + absl::uint128 highest_precision_in_long_double = + ~absl::uint128{} >> (128 - std::numeric_limits<long double>::digits); + EXPECT_EQ(highest_precision_in_long_double, + static_cast<absl::uint128>( + static_cast<long double>(highest_precision_in_long_double))); + // Apply a mask just to make sure all the bits are the right place. + const absl::uint128 arbitrary_mask = + absl::MakeUint128(0xa29f622677ded751, 0xf8ca66add076f468); + EXPECT_EQ(highest_precision_in_long_double & arbitrary_mask, + static_cast<absl::uint128>(static_cast<long double>( + highest_precision_in_long_double & arbitrary_mask))); + + EXPECT_EQ(static_cast<absl::uint128>(-0.1L), 0); } TEST(Uint128, OperatorAssignReturnRef) {
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 8afe817..9640ff4 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -12,7 +12,6 @@ # 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. -# load( "//absl:copts/configure_copts.bzl",
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h index 03ab0ae..fd9be78 100644 --- a/absl/strings/escaping.h +++ b/absl/strings/escaping.h
@@ -19,7 +19,6 @@ // // This header file contains string utilities involved in escaping and // unescaping strings in various ways. -// #ifndef ABSL_STRINGS_ESCAPING_H_ #define ABSL_STRINGS_ESCAPING_H_ @@ -56,7 +55,6 @@ // UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and // 0x99). // -// // If any errors are encountered, this function returns `false`, leaving the // `dest` output parameter in an unspecified state, and stores the first // encountered error in `error`. To disable error reporting, set `error` to
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index c54cd1a..4d48af0 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h
@@ -35,12 +35,14 @@ T, void_t<decltype(AbslFormatConvert( std::declval<const T&>(), std::declval<ConversionSpec>(), std::declval<FormatSink*>()))>> : std::true_type {}; + template <typename T> class StreamedWrapper; // If 'v' can be converted (in the printf sense) according to 'conv', // then convert it, appending to `sink` and return `true`. // Otherwise fail and return `false`. + // Raw pointers. struct VoidPtr { VoidPtr() = default;
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 5d77856..99cc0af 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc
@@ -363,6 +363,7 @@ AllIntTypes; INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes, TypedFormatConvertTest, AllIntTypes); + TEST_F(FormatConvertTest, Uint128) { absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979; absl::uint128 max = absl::Uint128Max();
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index 30235e0..eb81f8a 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h
@@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc index 334a148..4e23fef 100644 --- a/absl/strings/internal/str_format/extension_test.cc +++ b/absl/strings/internal/str_format/extension_test.cc
@@ -18,6 +18,7 @@ #include <random> #include <string> + #include "absl/strings/str_format.h" #include "gtest/gtest.h"
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc index ca93d1e..6e04abe 100644 --- a/absl/strings/internal/str_format/output_test.cc +++ b/absl/strings/internal/str_format/output_test.cc
@@ -17,7 +17,6 @@ #include <sstream> #include <string> - #include "gmock/gmock.h" #include "gtest/gtest.h"
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h index 445d4c3..0423630 100644 --- a/absl/strings/internal/utf8.h +++ b/absl/strings/internal/utf8.h
@@ -13,7 +13,6 @@ // limitations under the License. // // UTF8 utilities, implemented to reduce dependencies. -// #ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ #define ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index b7b03ff..ca2ee48 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc
@@ -785,7 +785,7 @@ if (iters_per_float == 0) iters_per_float = 1; for (float f : floats) { if (f == last) continue; - float testf = nextafter(last, std::numeric_limits<float>::max()); + float testf = std::nextafter(last, std::numeric_limits<float>::max()); runnable(testf); runnable(-testf); last = testf; @@ -799,7 +799,7 @@ last = testf; } } - testf = nextafter(f, 0.0f); + testf = std::nextafter(f, 0.0f); if (testf > last) { runnable(testf); runnable(-testf);
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index 69d6eaa..cba8ceb 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h
@@ -42,7 +42,6 @@ // Floating point numbers are formatted with six-digit precision, which is // the default for "std::cout <<" or printf "%g" (the same as "%.6g"). // -// // You can convert to hexadecimal output rather than decimal output using the // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index 486fe0e..539d951 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h
@@ -513,4 +513,5 @@ } } // namespace absl + #endif // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h index 8eb5508..7333078 100644 --- a/absl/strings/str_split.h +++ b/absl/strings/str_split.h
@@ -71,7 +71,6 @@ // - `ByLength` // - `MaxSplits` // -// // A Delimiter's `Find()` member function will be passed an input `text` that is // to be split and a position (`pos`) to begin searching for the next delimiter // in `text`. The returned absl::string_view should refer to the next occurrence
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h index 524dbeb..f8b2001 100644 --- a/absl/strings/string_view.h +++ b/absl/strings/string_view.h
@@ -32,7 +32,7 @@ #ifdef ABSL_HAVE_STD_STRING_VIEW -#include <string_view> +#include <string_view> // IWYU pragma: export namespace absl { using std::string_view; @@ -101,7 +101,6 @@ // example, when splitting a string, `std::vector<absl::string_view>` is a // natural data type for the output. // -// // When constructed from a source which is nul-terminated, the `string_view` // itself will not include the nul-terminator unless a specific size (including // the nul) is passed to the constructor. As a result, common idioms that work @@ -508,6 +507,7 @@ if (len != y.size()) { return false; } + return x.data() == y.data() || len <= 0 || memcmp(x.data(), y.data(), len) == 0; }
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index a45ff03..507bc4f 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h
@@ -45,7 +45,6 @@ // SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5); // EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s); // -// // Supported types: // * absl::string_view, std::string, const char* (null is equivalent to "") // * int32_t, int64_t, uint32_t, uint64
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index ac01904..5e69847 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel
@@ -178,7 +178,7 @@ name = "mutex_benchmark_common", testonly = 1, srcs = ["mutex_benchmark.cc"], - copts = ABSL_DEFAULT_COPTS, + copts = ABSL_TEST_COPTS, visibility = [ "//absl/synchronization:__pkg__", ],
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h index b2525b7..ebb16c5 100644 --- a/absl/synchronization/internal/create_thread_identity.h +++ b/absl/synchronization/internal/create_thread_identity.h
@@ -50,4 +50,5 @@ } // namespace synchronization_internal } // namespace absl + #endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h index 543c4a0..61c72e7 100644 --- a/absl/synchronization/internal/kernel_timeout.h +++ b/absl/synchronization/internal/kernel_timeout.h
@@ -53,6 +53,7 @@ // We explicitly do not support other custom formats: timespec, int64_t nanos. // Unify on this and absl::Time, please. + bool has_timeout() const { return ns_ != 0; } private: @@ -148,4 +149,5 @@ } // namespace synchronization_internal } // namespace absl + #endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc index d22539d..b7014fb 100644 --- a/absl/synchronization/internal/per_thread_sem.cc +++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -89,6 +89,7 @@ if (identity->blocked_count_ptr != nullptr) { identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed); } + identity->is_idle.store(false, std::memory_order_relaxed); identity->wait_start.store(0, std::memory_order_relaxed); return !timeout;
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h index d373f63..e7da070 100644 --- a/absl/synchronization/internal/per_thread_sem.h +++ b/absl/synchronization/internal/per_thread_sem.h
@@ -104,4 +104,5 @@ absl::synchronization_internal::KernelTimeout t) { return AbslInternalPerThreadSemWait(t); } + #endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc index bab6d1a..74b0965 100644 --- a/absl/synchronization/internal/waiter.cc +++ b/absl/synchronization/internal/waiter.cc
@@ -40,6 +40,7 @@ #include <atomic> #include <cassert> #include <cstdint> + #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/thread_identity.h" #include "absl/base/optimization.h" @@ -81,6 +82,7 @@ #define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF #endif #endif + class Futex { public: static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index f4ed0d0..37ffff3 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc
@@ -118,6 +118,10 @@ } // namespace +static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, + bool locking, bool trylock, + bool read_lock); + void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) { submit_profile_data.Store(fn); } @@ -233,15 +237,14 @@ SYNCH_EV_SIGNALALL, }; -enum { // Event flags - SYNCH_F_R = 0x01, // reader event - SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held - SYNCH_F_ACQ = 0x04, // event is an acquire +enum { // Event flags + SYNCH_F_R = 0x01, // reader event + SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held + SYNCH_F_TRY = 0x04, // TryLock or ReaderTryLock + SYNCH_F_UNLOCK = 0x08, // Unlock or ReaderUnlock SYNCH_F_LCK_W = SYNCH_F_LCK, SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R, - SYNCH_F_ACQ_W = SYNCH_F_ACQ, - SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R, }; } // anonymous namespace @@ -250,21 +253,22 @@ int flags; const char *msg; } event_properties[] = { - { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " }, - { 0, "TryLock failed " }, - { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " }, - { 0, "ReaderTryLock failed " }, - { SYNCH_F_ACQ_W, "Lock blocking " }, - { SYNCH_F_LCK_W, "Lock returning " }, - { SYNCH_F_ACQ_R, "ReaderLock blocking " }, - { SYNCH_F_LCK_R, "ReaderLock returning " }, - { SYNCH_F_LCK_W, "Unlock " }, - { SYNCH_F_LCK_R, "ReaderUnlock " }, - { 0, "Wait on " }, - { 0, "Wait unblocked " }, - { 0, "Signal on " }, - { 0, "SignalAll on " }, + {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "}, + {0, "TryLock failed "}, + {SYNCH_F_LCK_R | SYNCH_F_TRY, "ReaderTryLock succeeded "}, + {0, "ReaderTryLock failed "}, + {0, "Lock blocking "}, + {SYNCH_F_LCK_W, "Lock returning "}, + {0, "ReaderLock blocking "}, + {SYNCH_F_LCK_R, "ReaderLock returning "}, + {SYNCH_F_LCK_W | SYNCH_F_UNLOCK, "Unlock "}, + {SYNCH_F_LCK_R | SYNCH_F_UNLOCK, "ReaderUnlock "}, + {0, "Wait on "}, + {0, "Wait unblocked "}, + {0, "Signal on "}, + {0, "SignalAll on "}, }; + static absl::base_internal::SpinLock synch_event_mu( absl::base_internal::kLinkerInitialized); // protects synch_event @@ -414,9 +418,26 @@ ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj, (e == nullptr ? "" : e->name), buffer); } - if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr && - e->invariant != nullptr) { - (*e->invariant)(e->arg); + const int flags = event_properties[ev].flags; + if ((flags & SYNCH_F_LCK) != 0 && e != nullptr && e->invariant != nullptr) { + // Calling the invariant as is causes problems under ThreadSanitizer. + // We are currently inside of Mutex Lock/Unlock and are ignoring all + // memory accesses and synchronization. If the invariant transitively + // synchronizes something else and we ignore the synchronization, we will + // get false positive race reports later. + // Reuse EvalConditionAnnotated to properly call into user code. + struct local { + static bool pred(SynchEvent *ev) { + (*ev->invariant)(ev->arg); + return false; + } + }; + Condition cond(&local::pred, e); + Mutex *mu = static_cast<Mutex *>(obj); + const bool locking = (flags & SYNCH_F_UNLOCK) == 0; + const bool trylock = (flags & SYNCH_F_TRY) != 0; + const bool read_lock = (flags & SYNCH_F_R) != 0; + EvalConditionAnnotated(&cond, mu, locking, trylock, read_lock); } UnrefSynchEvent(e); } @@ -1552,7 +1573,7 @@ ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how)); this->LockSlowLoop(&waitp, flags); bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop - cond.Eval(); + EvalConditionAnnotated(&cond, this, true, false, how == kShared); ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0); return res; } @@ -1730,12 +1751,17 @@ // Compute cond->Eval() and tell race detectors that we do it under mutex mu. static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, - bool locking, Mutex::MuHow how) { + bool locking, bool trylock, + bool read_lock) { // Delicate annotation dance. // We are currently inside of read/write lock/unlock operation. // All memory accesses are ignored inside of mutex operations + for unlock // operation tsan considers that we've already released the mutex. bool res = false; +#ifdef THREAD_SANITIZER + const int flags = read_lock ? __tsan_mutex_read_lock : 0; + const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0); +#endif if (locking) { // For lock we pretend that we have finished the operation, // evaluate the predicate, then unlock the mutex and start locking it again @@ -1743,24 +1769,26 @@ // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan // will think the lock acquisition is recursive which will trigger // deadlock detector. - ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); + ABSL_TSAN_MUTEX_POST_LOCK(mu, tryflags, 0); res = cond->Eval(); - ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); + // There is no "try" version of Unlock, so use flags instead of tryflags. + ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_PRE_LOCK(mu, tryflags); } else { // Similarly, for unlock we pretend that we have unlocked the mutex, // lock the mutex, evaluate the predicate, and start unlocking it again // to match the annotation at the end of outer unlock operation. - ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); - ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); + ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags); + ABSL_TSAN_MUTEX_PRE_LOCK(mu, flags); + ABSL_TSAN_MUTEX_POST_LOCK(mu, flags, 0); res = cond->Eval(); - ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); + ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags); } // Prevent unused param warnings in non-TSAN builds. static_cast<void>(mu); - static_cast<void>(how); + static_cast<void>(trylock); + static_cast<void>(read_lock); return res; } @@ -1806,7 +1834,8 @@ v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) + how->fast_add, std::memory_order_acquire, std::memory_order_relaxed)) { - if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) { + if (cond == nullptr || + EvalConditionAnnotated(cond, this, true, false, how == kShared)) { return true; } unlock = true; @@ -1824,7 +1853,8 @@ } this->LockSlowLoop(&waitp, flags); return waitp.cond != nullptr || // => cond known true from LockSlowLoop - cond == nullptr || EvalConditionAnnotated(cond, this, true, how); + cond == nullptr || + EvalConditionAnnotated(cond, this, true, false, how == kShared); } // RAW_CHECK_FMT() takes a condition, a printf-style format string, and @@ -1880,7 +1910,8 @@ waitp->how->fast_add, std::memory_order_acquire, std::memory_order_relaxed)) { if (waitp->cond == nullptr || - EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { + EvalConditionAnnotated(waitp->cond, this, true, false, + waitp->how == kShared)) { break; // we timed out, or condition true, so return } this->UnlockSlow(waitp); // got lock but condition false @@ -1923,7 +1954,8 @@ std::memory_order_release, std::memory_order_relaxed)); if (waitp->cond == nullptr || - EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { + EvalConditionAnnotated(waitp->cond, this, true, false, + waitp->how == kShared)) { break; // we timed out, or condition true, so return } this->UnlockSlow(waitp); // got lock but condition false
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index cf0f86d..c38e356 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h
@@ -157,6 +157,7 @@ // ABSL_CONST_INIT Mutex mu(absl::kConstInit); // } explicit constexpr Mutex(absl::ConstInitType); + ~Mutex(); // Mutex::Lock() @@ -900,10 +901,12 @@ #ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {} + #else inline Mutex::Mutex() : mu_(0) { ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); } + inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {} inline CondVar::CondVar() : cv_(0) {} @@ -1047,4 +1050,5 @@ extern "C" { void AbslInternalMutexYield(); } // extern "C" + #endif // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 53c1f74..1021122 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc
@@ -1032,9 +1032,9 @@ ScopedDisableBazelTestWarnings() { #ifdef WIN32 char file[MAX_PATH]; - if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) { + if (GetEnvironmentVariableA(kVarName, file, sizeof(file)) < sizeof(file)) { warnings_output_file_ = file; - SetEnvironmentVariable(kVarName, nullptr); + SetEnvironmentVariableA(kVarName, nullptr); } #else const char *file = getenv(kVarName); @@ -1048,7 +1048,7 @@ ~ScopedDisableBazelTestWarnings() { if (!warnings_output_file_.empty()) { #ifdef WIN32 - SetEnvironmentVariable(kVarName, warnings_output_file_.c_str()); + SetEnvironmentVariableA(kVarName, warnings_output_file_.c_str()); #else setenv(kVarName, warnings_output_file_.c_str(), 0); #endif
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h index 19f51de..82d111a 100644 --- a/absl/synchronization/notification.h +++ b/absl/synchronization/notification.h
@@ -110,4 +110,5 @@ }; } // namespace absl + #endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index d67a486..5909832 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt
@@ -53,6 +53,10 @@ ${ABSL_DEFAULT_COPTS} ) +if(APPLE) + find_library(CoreFoundation CoreFoundation) +endif() + absl_cc_library( NAME time_zone @@ -78,6 +82,8 @@ "internal/cctz/src/zone_info_source.cc" COPTS ${ABSL_DEFAULT_COPTS} + DEPS + $<$<PLATFORM_ID:Darwin>:${CoreFoundation}> ) absl_cc_library(
diff --git a/absl/time/civil_time.h b/absl/time/civil_time.h index f231e4f..2dfcbd2 100644 --- a/absl/time/civil_time.h +++ b/absl/time/civil_time.h
@@ -66,7 +66,6 @@ // // // Valid in C++14 // constexpr absl::CivilDay cd(1969, 07, 20); -// #ifndef ABSL_TIME_CIVIL_TIME_H_ #define ABSL_TIME_CIVIL_TIME_H_
diff --git a/absl/time/duration.cc b/absl/time/duration.cc index 8ce4acb..67791fe 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc
@@ -901,6 +901,7 @@ *d = dur; return true; } + bool ParseFlag(const std::string& text, Duration* dst, std::string* ) { return ParseDuration(text, dst); }
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index 1fb33c2..903499b 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel
@@ -4,7 +4,7 @@ # 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 +# https://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,
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h index 0842fa4..f844182 100644 --- a/absl/time/internal/cctz/include/cctz/civil_time.h +++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h index 1c5d097..a5923f1 100644 --- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h +++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index f28dad1..ef6c4ba 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -4,7 +4,7 @@ // 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 +// https://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, @@ -72,7 +72,7 @@ // // See also: // - http://www.iana.org/time-zones -// - http://en.wikipedia.org/wiki/Zoneinfo +// - https://en.wikipedia.org/wiki/Zoneinfo class time_zone { public: time_zone() : time_zone(nullptr) {} // Equivalent to UTC
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h index 20a7697..2b898d1 100644 --- a/absl/time/internal/cctz/include/cctz/zone_info_source.h +++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc index a00f47b..445366e 100644 --- a/absl/time/internal/cctz/src/cctz_benchmark.cc +++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/civil_time_detail.cc b/absl/time/internal/cctz/src/civil_time_detail.cc index 780d5c9..cb40b6b 100644 --- a/absl/time/internal/cctz/src/civil_time_detail.cc +++ b/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc index faffde4..e590ee3 100644 --- a/absl/time/internal/cctz/src/civil_time_test.cc +++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc index db9a475..81ece72 100644 --- a/absl/time/internal/cctz/src/time_zone_fixed.cc +++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.h b/absl/time/internal/cctz/src/time_zone_fixed.h index 489b857..9c1f5e7 100644 --- a/absl/time/internal/cctz/src/time_zone_fixed.h +++ b/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index a5c72df..2585098 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index b99e1c6..705ccdc 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 380834a..09aaee5 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h index e4bd386..d000b7a 100644 --- a/absl/time/internal/cctz/src/time_zone_if.h +++ b/absl/time/internal/cctz/src/time_zone_if.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc index 3062ccd..3cbc674 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.cc +++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h index 14965ef..b73fad9 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.h +++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 6aa80ff..50f7de5 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -4,7 +4,7 @@ // 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 +// https://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, @@ -25,7 +25,7 @@ // a grain of salt. // // For more information see tzfile(5), http://www.iana.org/time-zones, or -// http://en.wikipedia.org/wiki/Zoneinfo. +// https://en.wikipedia.org/wiki/Zoneinfo. // // Note that we assume the proleptic Gregorian calendar and 60-second // minutes throughout.
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h index 958e9b6..bff639f 100644 --- a/absl/time/internal/cctz/src/time_zone_info.h +++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index 2829170..3ab1623 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 4e40c61..0d18e9a 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index f2d151e..fd04e2d 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -4,7 +4,7 @@ // 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 +// https://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, @@ -20,6 +20,11 @@ #include <dlfcn.h> #endif #endif + +#if defined(__APPLE__) +#include <CoreFoundation/CFTimeZone.h> +#endif + #include <cstdlib> #include <cstring> #include <string> @@ -121,6 +126,11 @@ char* tz_env = nullptr; #if defined(_MSC_VER) _dupenv_s(&tz_env, nullptr, "TZ"); +#elif defined(__APPLE__) + CFTimeZoneRef system_time_zone = CFTimeZoneCopyDefault(); + CFStringRef tz_name = CFTimeZoneGetName(system_time_zone); + tz_env = strdup(CFStringGetCStringPtr(tz_name, CFStringGetSystemEncoding())); + CFRelease(system_time_zone); #else tz_env = std::getenv("TZ"); #endif @@ -153,6 +163,8 @@ #if defined(_MSC_VER) free(localtime_env); free(tz_env); +#elif defined(__APPLE__) + free(tz_env); #endif time_zone tz;
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 2e49e48..8068e2f 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc index 75ad8bc..993901a 100644 --- a/absl/time/internal/cctz/src/time_zone_posix.cc +++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h index ef2a8c1..6a60022 100644 --- a/absl/time/internal/cctz/src/time_zone_posix.h +++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc index 1bc16ae..1324846 100644 --- a/absl/time/internal/cctz/src/zone_info_source.cc +++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -4,7 +4,7 @@ // 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 +// https://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,
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab index c2e0f8e..4e4a5c3 100644 --- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab +++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -10,7 +10,7 @@ # # 1. ISO 3166-1 alpha-2 country code, current as of # ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1 -# http://isotc.iso.org/livelink/livelink/Open/16944257 +# https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. # This is not the same as the English name in the ISO 3166 tables.
diff --git a/absl/time/time.cc b/absl/time/time.cc index 799bf85..977a951 100644 --- a/absl/time/time.cc +++ b/absl/time/time.cc
@@ -41,6 +41,7 @@ #include "absl/time/internal/cctz/include/cctz/time_zone.h" namespace cctz = absl::time_internal::cctz; + namespace absl { namespace {
diff --git a/absl/time/time.h b/absl/time/time.h index 59e1dc6..594396c 100644 --- a/absl/time/time.h +++ b/absl/time/time.h
@@ -58,7 +58,6 @@ // std::string s = absl::FormatTime( // "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S", // landing, syd); -// #ifndef ABSL_TIME_TIME_H_ #define ABSL_TIME_TIME_H_ @@ -569,7 +568,6 @@ // The `absl::Time` class represents an instant in time as a count of clock // ticks of some granularity (resolution) from some starting point (epoch). // -// // `absl::Time` uses a resolution that is high enough to avoid loss in // precision, and a range that is wide enough to avoid overflow, when // converting between tick counts in most Google time scales (i.e., resolution @@ -1450,6 +1448,7 @@ } } // namespace time_internal + constexpr Duration Nanoseconds(int64_t n) { return time_internal::FromInt64(n, std::nano{}); }
diff --git a/absl/types/any.h b/absl/types/any.h index e750f48..f3a3281 100644 --- a/absl/types/any.h +++ b/absl/types/any.h
@@ -58,7 +58,7 @@ #ifdef ABSL_HAVE_STD_ANY -#include <any> +#include <any> // IWYU pragma: export namespace absl { using std::any;
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc index 00d0fb7..5d7d8a5 100644 --- a/absl/types/any_exception_safety_test.cc +++ b/absl/types/any_exception_safety_test.cc
@@ -135,6 +135,7 @@ EXPECT_TRUE(strong_empty_any_tester.Test(assign_val)); EXPECT_TRUE(strong_empty_any_tester.Test(move)); } + // libstdc++ std::any fails this test #if !defined(ABSL_HAVE_STD_ANY) TEST(AnyExceptionSafety, Emplace) {
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h index 4926b32..5ca66e2 100644 --- a/absl/types/internal/variant.h +++ b/absl/types/internal/variant.h
@@ -15,7 +15,6 @@ // Implementation details of absl/types/variant.h, pulled into a // separate file to avoid cluttering the top of the API header with // implementation details. -// #ifndef ABSL_TYPES_variant_internal_H_ #define ABSL_TYPES_variant_internal_H_ @@ -1549,8 +1548,8 @@ variant<Types...>* w; template <std::size_t I> void operator()(SizeT<I>) const { - using std::swap; - swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w)); + type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v), + VariantCoreAccess::Access<I>(*w)); } void operator()(SizeT<variant_npos>) const {}
diff --git a/absl/types/optional.h b/absl/types/optional.h index 0c1213f..f0ae9a1 100644 --- a/absl/types/optional.h +++ b/absl/types/optional.h
@@ -36,11 +36,12 @@ #define ABSL_TYPES_OPTIONAL_H_ #include "absl/base/config.h" +#include "absl/memory/memory.h" #include "absl/utility/utility.h" #ifdef ABSL_HAVE_STD_OPTIONAL -#include <optional> +#include <optional> // IWYU pragma: export namespace absl { using std::bad_optional_access; @@ -60,7 +61,6 @@ #include <utility> #include "absl/base/attributes.h" -#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" #include "absl/types/bad_optional_access.h" @@ -114,10 +114,6 @@ // need the inline variable support in C++17 for external linkage. // * Throws `absl::bad_optional_access` instead of // `std::bad_optional_access`. -// * `optional::swap()` and `absl::swap()` relies on -// `std::is_(nothrow_)swappable()`, which has been introduced in C++17. -// As a workaround, we assume `is_swappable()` is always `true` -// and `is_nothrow_swappable()` is the same as `std::is_trivial()`. // * `make_optional()` cannot be declared `constexpr` due to the absence of // guaranteed copy elision. // * The move constructor's `noexcept` specification is stronger, i.e. if the @@ -404,23 +400,24 @@ }; template <typename T> -constexpr copy_traits get_ctor_copy_traits() { - return std::is_copy_constructible<T>::value - ? copy_traits::copyable - : std::is_move_constructible<T>::value ? copy_traits::movable - : copy_traits::non_movable; -} +struct ctor_copy_traits { + static constexpr copy_traits traits = + std::is_copy_constructible<T>::value + ? copy_traits::copyable + : std::is_move_constructible<T>::value ? copy_traits::movable + : copy_traits::non_movable; +}; template <typename T> -constexpr copy_traits get_assign_copy_traits() { - return absl::is_copy_assignable<T>::value && - std::is_copy_constructible<T>::value - ? copy_traits::copyable - : absl::is_move_assignable<T>::value && - std::is_move_constructible<T>::value - ? copy_traits::movable - : copy_traits::non_movable; -} +struct assign_copy_traits { + static constexpr copy_traits traits = + absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value + ? copy_traits::copyable + : absl::is_move_assignable<T>::value && + std::is_move_constructible<T>::value + ? copy_traits::movable + : copy_traits::non_movable; +}; // Whether T is constructible or convertible from optional<U>. template <typename T, typename U> @@ -486,9 +483,9 @@ template <typename T> class optional : private optional_internal::optional_data<T>, private optional_internal::optional_ctor_base< - optional_internal::get_ctor_copy_traits<T>()>, + optional_internal::ctor_copy_traits<T>::traits>, private optional_internal::optional_assign_base< - optional_internal::get_assign_copy_traits<T>()> { + optional_internal::assign_copy_traits<T>::traits> { using data_base = optional_internal::optional_data<T>; public: @@ -513,10 +510,11 @@ // the arguments `std::forward<Args>(args)...` within the `optional`. // (The `in_place_t` is a tag used to indicate that the contained object // should be constructed in-place.) - // - // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE. - template <typename... Args> - constexpr explicit optional(in_place_t, Args&&... args) + template <typename InPlaceT, typename... Args, + absl::enable_if_t<absl::conjunction< + std::is_same<InPlaceT, in_place_t>, + std::is_constructible<T, Args&&...> >::value>* = nullptr> + constexpr explicit optional(InPlaceT, Args&&... args) : data_base(in_place_t(), absl::forward<Args>(args)...) {} // Constructs a non-empty `optional` direct-initialized value of type `T` from @@ -752,11 +750,10 @@ // Swap, standard semantics void swap(optional& rhs) noexcept( std::is_nothrow_move_constructible<T>::value&& - std::is_trivial<T>::value) { + type_traits_internal::IsNothrowSwappable<T>::value) { if (*this) { if (rhs) { - using std::swap; - swap(**this, *rhs); + type_traits_internal::Swap(**this, *rhs); } else { rhs.construct(std::move(**this)); this->destruct(); @@ -908,12 +905,10 @@ // // Performs a swap between two `absl::optional` objects, using standard // semantics. -// -// NOTE: we assume `is_swappable()` is always `true`. A compile error will -// result if this is not the case. -template <typename T, - typename std::enable_if<std::is_move_constructible<T>::value, - bool>::type = false> +template <typename T, typename std::enable_if< + std::is_move_constructible<T>::value && + type_traits_internal::IsSwappable<T>::value, + bool>::type = false> void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { a.swap(b); }
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index b93aa98..0665488 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc
@@ -157,6 +157,16 @@ NonMovable& operator=(NonMovable&&) = delete; }; +struct NoDefault { + NoDefault() = delete; + NoDefault(const NoDefault&) {} + NoDefault& operator=(const NoDefault&) { return *this; } +}; + +struct ConvertsFromInPlaceT { + ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT +}; + TEST(optionalTest, DefaultConstructor) { absl::optional<int> empty; EXPECT_FALSE(empty); @@ -337,16 +347,18 @@ static_assert((*opt2).x == ConstexprType::kCtorInitializerList, ""); #endif - // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...> - // SFINAE is added to optional::optional(absl::in_place_t, Args&&...). - // struct I { - // I(absl::in_place_t); - // }; + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + const absl::in_place_t&>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<ConvertsFromInPlaceT>, + absl::in_place_t, absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, - // absl::in_place_t>::value)); - // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const - // absl::in_place_t&>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t>::value)); + EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>, + absl::in_place_t&&>::value)); } // template<U=T> optional(U&&); @@ -1624,4 +1636,29 @@ EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value); } +#if !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) +struct NestedClassBug { + struct Inner { + bool dummy = false; + }; + absl::optional<Inner> value; +}; + +TEST(optionalTest, InPlaceTSFINAEBug) { + NestedClassBug b; + ((void)b); + using Inner = NestedClassBug::Inner; + + EXPECT_TRUE((std::is_default_constructible<Inner>::value)); + EXPECT_TRUE((std::is_constructible<Inner>::value)); + EXPECT_TRUE( + (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value)); + + absl::optional<Inner> o(absl::in_place); + EXPECT_TRUE(o.has_value()); + o.emplace(); + EXPECT_TRUE(o.has_value()); +} +#endif // !defined(ABSL_HAVE_STD_OPTIONAL) && !defined(_LIBCPP_VERSION) + } // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h index 9652e3b..ebd52d2 100644 --- a/absl/types/variant.h +++ b/absl/types/variant.h
@@ -47,7 +47,7 @@ #ifdef ABSL_HAVE_STD_VARIANT -#include <variant> +#include <variant> // IWYU pragma: export namespace absl { using std::bad_variant_access; @@ -129,7 +129,12 @@ // type (in which case, they will be swapped) or to two different types (in // which case the values will need to be moved). // -template <typename... Ts> +template < + typename... Ts, + absl::enable_if_t< + absl::conjunction<std::is_move_constructible<Ts>..., + type_traits_internal::IsSwappable<Ts>...>::value, + int> = 0> void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) { v.swap(w); } @@ -688,12 +693,12 @@ // // Swaps the values of two variant objects. // - // TODO(calabrese) - // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()` - // which is introduced in C++17. So we assume `is_swappable()` is always - // true and `is_nothrow_swappable()` is same as `std::is_trivial()`. void swap(variant& rhs) noexcept( - absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) { + absl::conjunction< + std::is_nothrow_move_constructible<T0>, + std::is_nothrow_move_constructible<Tn>..., + type_traits_internal::IsNothrowSwappable<T0>, + type_traits_internal::IsNothrowSwappable<Tn>...>::value) { return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run( variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index()); }
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc index 086fcff..76beb59 100644 --- a/absl/types/variant_exception_safety_test.cc +++ b/absl/types/variant_exception_safety_test.cc
@@ -24,6 +24,7 @@ #include "absl/base/config.h" #include "absl/base/internal/exception_safety_testing.h" #include "absl/memory/memory.h" + // See comment in absl/base/config.h #if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE) @@ -315,6 +316,12 @@ EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test()); } { + // libstdc++ introduced a regression between 2018-09-25 and 2019-01-06. + // The fix is targeted for gcc-9. + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7 + // https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=267614 +#if !(defined(ABSL_HAVE_STD_VARIANT) && \ + defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8) // - 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 @@ -330,6 +337,8 @@ auto copy = rhs; *lhs = std::move(copy); })); +#endif // !(defined(ABSL_HAVE_STD_VARIANT) && + // defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8) } }
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc index 9df702d..ab40ed2 100644 --- a/absl/types/variant_test.cc +++ b/absl/types/variant_test.cc
@@ -561,6 +561,7 @@ } #ifdef ABSL_HAVE_EXCEPTIONS + // See comment in absl/base/config.h #if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE) TEST(VariantTest, DISABLED_TestDtorValuelessByException)
diff --git a/absl/utility/utility.h b/absl/utility/utility.h index 62ce6f3..853c1fb 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h
@@ -35,7 +35,6 @@ // https://en.cppreference.com/w/cpp/utility/integer_sequence // https://en.cppreference.com/w/cpp/utility/apply // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html -// #ifndef ABSL_UTILITY_UTILITY_H_ #define ABSL_UTILITY_UTILITY_H_
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh new file mode 100755 index 0000000..e54b783 --- /dev/null +++ b/ci/cmake_install_test.sh
@@ -0,0 +1,33 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +time docker run \ + --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \ + --workdir=/abseil-cpp \ + --tmpfs=/buildfs:exec \ + --cap-add=SYS_PTRACE \ + --rm \ + -e CFLAGS="-Werror" \ + -e CXXFLAGS="-Werror" \ + gcr.io/google.com/absl-177019/linux_gcc-4.8:20190316 \ + /bin/bash CMake/install_test_project/test.sh +
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh new file mode 100755 index 0000000..741e48c --- /dev/null +++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -0,0 +1,62 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +# This script that can be invoked to test abseil-cpp in a hermetic environment +# using a Docker image on Linux. You must have Docker installed to use this +# script. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +if [ -z ${STD:-} ]; then + STD="c++11 c++14 c++17" +fi + +if [ -z ${COMPILATION_MODE:-} ]; then + COMPILATION_MODE="fastbuild opt" +fi + +for std in ${STD}; do + for compilation_mode in ${COMPILATION_MODE}; do + echo "--------------------------------------------------------------------" + echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}" + + time docker run \ + --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \ + --workdir=/abseil-cpp \ + --cap-add=SYS_PTRACE \ + --rm \ + -e CC="/opt/llvm/clang/bin/clang" \ + -e BAZEL_COMPILER="llvm" \ + -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \ + -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \ + -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \ + gcr.io/google.com/absl-177019/linux_clang-latest:20190313 \ + /usr/local/bin/bazel test ... \ + --compilation_mode=${compilation_mode} \ + --copt=-Werror \ + --define="absl=1" \ + --keep_going \ + --show_timestamps \ + --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ + --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_output=errors \ + --test_tag_filters=-benchmark + done +done
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh new file mode 100755 index 0000000..d703a77 --- /dev/null +++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +# This script that can be invoked to test abseil-cpp in a hermetic environment +# using a Docker image on Linux. You must have Docker installed to use this +# script. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +if [ -z ${STD:-} ]; then + STD="c++11 c++14 c++17" +fi + +if [ -z ${COMPILATION_MODE:-} ]; then + COMPILATION_MODE="fastbuild opt" +fi + +for std in ${STD}; do + for compilation_mode in ${COMPILATION_MODE}; do + echo "--------------------------------------------------------------------" + echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}" + + time docker run \ + --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \ + --workdir=/abseil-cpp \ + --cap-add=SYS_PTRACE \ + --rm \ + -e CC="/opt/llvm/clang/bin/clang" \ + -e BAZEL_COMPILER="llvm" \ + -e BAZEL_CXXOPTS="-std=${std}" \ + -e CPLUS_INCLUDE_PATH="/usr/include/c++/6" \ + gcr.io/google.com/absl-177019/linux_clang-latest:20190313 \ + /usr/local/bin/bazel test ... \ + --compilation_mode=${compilation_mode} \ + --copt=-Werror \ + --define="absl=1" \ + --keep_going \ + --show_timestamps \ + --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ + --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_output=errors \ + --test_tag_filters=-benchmark + done +done
diff --git a/ci/linux_gcc-4.8_libstdcxx_cmake.sh b/ci/linux_gcc-4.8_libstdcxx_cmake.sh new file mode 100755 index 0000000..4f964e2 --- /dev/null +++ b/ci/linux_gcc-4.8_libstdcxx_cmake.sh
@@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +# TODO(absl-team): This script isn't fully hermetic because +# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed +# version of GoogleTest. This means that an upstream change to GoogleTest could +# break this test. Fix this by allowing this script to pin to a known-good +# version of GoogleTest. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then + ABSL_CMAKE_CXX_STANDARDS="11 14" +fi + +if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then + ABSL_CMAKE_BUILD_TYPES="Debug Release" +fi + +for std in ${ABSL_CMAKE_CXX_STANDARDS}; do + for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do + echo "--------------------------------------------------------------------" + echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}" + + time docker run \ + --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \ + --workdir=/abseil-cpp \ + --tmpfs=/buildfs:exec \ + --cap-add=SYS_PTRACE \ + --rm \ + -e CFLAGS="-Werror" \ + -e CXXFLAGS="-Werror" \ + gcr.io/google.com/absl-177019/linux_gcc-4.8:20190316 \ + /bin/bash -c " + cd /buildfs && \ + cmake /abseil-cpp \ + -DABSL_USE_GOOGLETEST_HEAD=ON \ + -DABSL_RUN_TESTS=ON \ + -DCMAKE_BUILD_TYPE=${compilation_mode} \ + -DCMAKE_CXX_STANDARD=${std} && \ + make -j$(nproc) VERBOSE=1 && \ + ctest -j$(nproc) --output-on-failure" + done +done
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh new file mode 100755 index 0000000..e14a019 --- /dev/null +++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -0,0 +1,59 @@ +#!/bin/bash +# +# Copyright 2019 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 +# +# https://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. + +# This script that can be invoked to test abseil-cpp in a hermetic environment +# using a Docker image on Linux. You must have Docker installed to use this +# script. + +set -euox pipefail + +if [ -z ${ABSEIL_ROOT:-} ]; then + ABSEIL_ROOT="$(realpath $(dirname ${0})/..)" +fi + +if [ -z ${STD:-} ]; then + STD="c++11 c++14 c++17" +fi + +if [ -z ${COMPILATION_MODE:-} ]; then + COMPILATION_MODE="fastbuild opt" +fi + +for std in ${STD}; do + for compilation_mode in ${COMPILATION_MODE}; do + echo "--------------------------------------------------------------------" + echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}" + + time docker run \ + --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \ + --workdir=/abseil-cpp \ + --cap-add=SYS_PTRACE \ + --rm \ + -e CC="/usr/local/bin/gcc" \ + -e BAZEL_CXXOPTS="-std=${std}" \ + gcr.io/google.com/absl-177019/linux_gcc-latest:20190318 \ + /usr/local/bin/bazel test ... \ + --compilation_mode=${compilation_mode} \ + --copt=-Werror \ + --define="absl=1" \ + --keep_going \ + --show_timestamps \ + --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \ + --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \ + --test_output=errors \ + --test_tag_filters=-benchmark + done +done