From b56cbdd23834a65682c0b46f367f8679e83bc894 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 18 Sep 2020 15:55:15 -0700 Subject: Abseil LTS 20200923 What's New: * `absl::StatusOr` has been released. See our [blog post](https://abseil.io/blog/2020-091021-status) for more information. * Abseil Flags reflection interfaces have been released. * Abseil Flags memory usage has been significantly optimized. * Abseil now supports a "hardened" build mode. This build mode enables runtime checks that guard against programming errors that may lead to security vulnerabilities. Notable Fixes: * Sanitizer dynamic annotations like `AnnotateRWLockCreate` that are also defined by the compiler sanitizer implementation are no longer also defined by Abseil. * Sanitizer macros are now prefixed with `ABSL_` to avoid naming collisions. * Sanitizer usage is now automatically detected and no longer requires macros like `ADDRESS_SANITIZER` to be defined on the command line. Breaking Changes: * Abseil no longer contains a `dynamic_annotations` library. Users using a supported build system (Bazel or CMake) are unaffected by this, but users manually specifying link libraries may get an error about a missing linker input. Baseline: 7680a5f8efe32de4753baadbd63e74e59d95bac1 Cherry picks: None --- absl/flags/flag.h | 193 +++++++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 88 deletions(-) (limited to 'absl/flags/flag.h') diff --git a/absl/flags/flag.h b/absl/flags/flag.h index cff02c1f..a9cb2b79 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -33,14 +33,12 @@ #include #include "absl/base/attributes.h" -#include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/flags/config.h" -#include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" -#include "absl/flags/marshalling.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -110,50 +108,53 @@ class Flag { impl_(nullptr) {} #endif - flags_internal::Flag* GetImpl() const { + flags_internal::Flag& GetImpl() const { if (!inited_.load(std::memory_order_acquire)) { absl::MutexLock l(flags_internal::GetGlobalConstructionGuard()); if (inited_.load(std::memory_order_acquire)) { - return impl_; + return *impl_; } - impl_ = - new flags_internal::Flag(name_, filename_, - {flags_internal::FlagHelpMsg(help_gen_), - flags_internal::FlagHelpKind::kGenFunc}, - default_value_gen_); + impl_ = new flags_internal::Flag( + name_, filename_, + {flags_internal::FlagHelpMsg(help_gen_), + flags_internal::FlagHelpKind::kGenFunc}, + {flags_internal::FlagDefaultSrc(default_value_gen_), + flags_internal::FlagDefaultKind::kGenFunc}); inited_.store(true, std::memory_order_release); } - return impl_; + return *impl_; } // Public methods of `absl::Flag` are NOT part of the Abseil Flags API. // See https://abseil.io/docs/cpp/guides/flags - bool IsRetired() const { return GetImpl()->IsRetired(); } - bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); } - absl::string_view Name() const { return GetImpl()->Name(); } - std::string Help() const { return GetImpl()->Help(); } - bool IsModified() const { return GetImpl()->IsModified(); } + bool IsRetired() const { return GetImpl().IsRetired(); } + absl::string_view Name() const { return GetImpl().Name(); } + std::string Help() const { return GetImpl().Help(); } + bool IsModified() const { return GetImpl().IsModified(); } bool IsSpecifiedOnCommandLine() const { - return GetImpl()->IsSpecifiedOnCommandLine(); + return GetImpl().IsSpecifiedOnCommandLine(); } - absl::string_view Typename() const { return GetImpl()->Typename(); } - std::string Filename() const { return GetImpl()->Filename(); } - std::string DefaultValue() const { return GetImpl()->DefaultValue(); } - std::string CurrentValue() const { return GetImpl()->CurrentValue(); } + std::string Filename() const { return GetImpl().Filename(); } + std::string DefaultValue() const { return GetImpl().DefaultValue(); } + std::string CurrentValue() const { return GetImpl().CurrentValue(); } template inline bool IsOfType() const { - return GetImpl()->template IsOfType(); + return GetImpl().template IsOfType(); } - T Get() const { return GetImpl()->Get(); } - bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); } - void Set(const T& v) { GetImpl()->Set(v); } - void SetCallback(const flags_internal::FlagCallbackFunc mutation_callback) { - GetImpl()->SetCallback(mutation_callback); + T Get() const { + return flags_internal::FlagImplPeer::InvokeGet(GetImpl()); + } + void Set(const T& v) { + flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v); + } + void InvokeCallback() { GetImpl().InvokeCallback(); } + + const CommandLineFlag& Reflect() const { + return flags_internal::FlagImplPeer::InvokeReflect(GetImpl()); } - void InvokeCallback() { GetImpl()->InvokeCallback(); } // The data members are logically private, but they need to be public for // this to be an aggregate type. @@ -185,7 +186,7 @@ class Flag { // std::string first_name = absl::GetFlag(FLAGS_firstname); template ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag& flag) { - return flag.Get(); + return flags_internal::FlagImplPeer::InvokeGet(flag); } // SetFlag() @@ -197,7 +198,7 @@ ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag& flag) { // but especially within performance-critical code. template void SetFlag(absl::Flag* flag, const T& v) { - flag->Set(v); + flags_internal::FlagImplPeer::InvokeSet(*flag, v); } // Overload of `SetFlag()` to allow callers to pass in a value that is @@ -206,7 +207,22 @@ void SetFlag(absl::Flag* flag, const T& v) { template void SetFlag(absl::Flag* flag, const V& v) { T value(v); - flag->Set(value); + flags_internal::FlagImplPeer::InvokeSet(*flag, value); +} + +// GetFlagReflectionHandle() +// +// Returns the reflection handle corresponding to specified Abseil Flag +// instance. Use this handle to access flag's reflection information, like name, +// location, default value etc. +// +// Example: +// +// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue(); + +template +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag& f) { + return flags_internal::FlagImplPeer::InvokeReflect(f); } ABSL_NAMESPACE_END @@ -269,27 +285,29 @@ ABSL_NAMESPACE_END // ----------------------------------------------------------------------------- // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES +#if !defined(_MSC_VER) || defined(__clang__) +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag +#define ABSL_FLAG_IMPL_HELP_ARG(name) \ + absl::flags_internal::HelpArg( \ + FLAGS_help_storage_##name) +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \ + absl::flags_internal::DefaultArg(0) +#else +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag.GetImpl() +#define ABSL_FLAG_IMPL_HELP_ARG(name) &AbslFlagHelpGenFor##name::NonConst +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) &AbslFlagDefaultGenFor##name::Gen +#endif #if ABSL_FLAGS_STRIP_NAMES #define ABSL_FLAG_IMPL_FLAGNAME(txt) "" #define ABSL_FLAG_IMPL_FILENAME() "" -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(&flag) -#else #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(flag.GetImpl()) -#endif + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag)) #else #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt #define ABSL_FLAG_IMPL_FILENAME() __FILE__ -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(&flag) -#else #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(flag.GetImpl()) -#endif + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag)) #endif // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP @@ -305,50 +323,48 @@ ABSL_NAMESPACE_END // between the two via the call to HelpArg in absl::Flag instantiation below. // If help message expression is constexpr evaluable compiler will optimize // away this whole struct. -#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ - struct AbslFlagHelpGenFor##name { \ - template \ - static constexpr const char* Const() { \ - return absl::flags_internal::HelpConstexprWrap( \ - ABSL_FLAG_IMPL_FLAGHELP(txt)); \ - } \ - static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \ - } - -#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - static void* AbslFlagsInitFlag##name() { \ - return absl::flags_internal::MakeFromDefaultValue(default_value); \ - } +// TODO(rogeeff): place these generated structs into local namespace and apply +// ABSL_INTERNAL_UNIQUE_SHORT_NAME. +// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name +#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ + struct AbslFlagHelpGenFor##name { \ + /* The expression is run in the caller as part of the */ \ + /* default value argument. That keeps temporaries alive */ \ + /* long enough for NonConst to work correctly. */ \ + static constexpr absl::string_view Value( \ + absl::string_view v = ABSL_FLAG_IMPL_FLAGHELP(txt)) { \ + return v; \ + } \ + static std::string NonConst() { return std::string(Value()); } \ + }; \ + constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) = \ + absl::flags_internal::HelpStringAsArray( \ + 0); + +#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + struct AbslFlagDefaultGenFor##name { \ + Type value = absl::flags_internal::InitDefaultValue(default_value); \ + static void Gen(void* p) { \ + new (p) Type(AbslFlagDefaultGenFor##name{}.value); \ + } \ + }; // ABSL_FLAG_IMPL // // Note: Name of registrar object is not arbitrary. It is used to "grab" // global name for FLAGS_no symbol, thus preventing the possibility // of defining two flags with names foo and nofoo. -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - absl::flags_internal::HelpArg(0), \ - &AbslFlagsInitFlag##name}; \ - extern bool FLAGS_no##name; \ - bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#else -// MSVC version uses aggregate initialization. We also do not try to -// optimize away help wrapper. -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \ - extern bool FLAGS_no##name; \ - bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#endif +#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ + namespace absl /* block flags in namespaces */ {} \ + ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \ + ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ + ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ + ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \ + extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \ + absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \ + ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) // ABSL_RETIRED_FLAG // @@ -369,11 +385,12 @@ ABSL_NAMESPACE_END // // `default_value` is only used as a double check on the type. `explanation` is // unused. -// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into -// the unnamed namespace. -#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \ - ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \ - ([] { return type(default_value); }, \ - absl::flags_internal::RetiredFlag(#flagname)) +// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of +// retired flags are cleaned up. +#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \ + static absl::flags_internal::RetiredFlag RETIRED_FLAGS_##name; \ + ABSL_ATTRIBUTE_UNUSED static const auto RETIRED_FLAGS_REG_##name = \ + (RETIRED_FLAGS_##name.Retire(#name), \ + ::absl::flags_internal::FlagRegistrarEmpty{}) #endif // ABSL_FLAGS_FLAG_H_ -- cgit v1.2.3