diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index b8960fd796b76..0c335913b5c2b 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -26,7 +26,6 @@ #define SHARE_RUNTIME_ATOMIC_HPP #include "cppstdlib/type_traits.hpp" -#include "metaprogramming/enableIf.hpp" #include "metaprogramming/primitiveConversions.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/globalDefinitions.hpp" @@ -89,8 +88,12 @@ // value will be initialized as if by translating the value that would be // provided by default constructing an atomic type for the value type's // decayed type. - -// (3) Atomic pointers and atomic integers additionally provide +// +// (3) Constructors for all atomic types are constexpr, to ensure non-local +// atomic variables are constant initialized (C++17 6.6.2) when initialized +// with suitable arguments. +// +// (4) Atomic pointers and atomic integers additionally provide // // member functions: // v.add_then_fetch(i [, o]) -> T @@ -102,7 +105,7 @@ // type of i must be signed, or both must be unsigned. Atomic pointers perform // element arithmetic. // -// (4) Atomic integers additionally provide +// (5) Atomic integers additionally provide // // member functions: // v.and_then_fetch(x [, o]) -> T @@ -112,7 +115,7 @@ // v.fetch_then_or(x [, o]) -> T // v.fetch_then_xor(x [, o]) -> T // -// (5) Atomic pointers additionally provide +// (6) Atomic pointers additionally provide // // nested types: // ElementType -> std::remove_pointer_t @@ -217,7 +220,7 @@ class AtomicImpl::CommonCore { T volatile _value; protected: - explicit CommonCore(T value) : _value(value) {} + explicit constexpr CommonCore(T value) : _value(value) {} ~CommonCore() = default; T volatile* value_ptr() { return &_value; } @@ -290,7 +293,7 @@ class AtomicImpl::SupportsArithmetic : public CommonCore { } protected: - explicit SupportsArithmetic(T value) : CommonCore(value) {} + explicit constexpr SupportsArithmetic(T value) : CommonCore(value) {} ~SupportsArithmetic() = default; public: @@ -333,7 +336,7 @@ class AtomicImpl::Atomic : public SupportsArithmetic { public: - explicit Atomic(T value = 0) : SupportsArithmetic(value) {} + explicit constexpr Atomic(T value = 0) : SupportsArithmetic(value) {} NONCOPYABLE(Atomic); @@ -373,7 +376,7 @@ class AtomicImpl::Atomic : public CommonCore { public: - explicit Atomic(T value = 0) : CommonCore(value) {} + explicit constexpr Atomic(T value = 0) : CommonCore(value) {} NONCOPYABLE(Atomic); @@ -389,7 +392,7 @@ class AtomicImpl::Atomic : public SupportsArithmetic { public: - explicit Atomic(T value = nullptr) : SupportsArithmetic(value) {} + explicit constexpr Atomic(T value = nullptr) : SupportsArithmetic(value) {} NONCOPYABLE(Atomic); @@ -410,12 +413,21 @@ class AtomicImpl::Atomic { Atomic _value; - static Decayed decay(T x) { return Translator::decay(x); } + // The decay function and the constructors are constexpr so that a non-local + // atomic object constructed with constant arguments will be a constant + // initialization. One might ask why it's not a problem that some + // specializations of these functions are not constant expressions. The + // answer lies in C++17 10.1.5/6, along with us having *some* constexpr + // translator decay functions, constexpr ctors for some translated types, + // and constexpr ctors for some decayed types. Also, C++23 removes those + // restrictions on constexpr functions and ctors. + + static constexpr Decayed decay(T x) { return Translator::decay(x); } static T recover(Decayed x) { return Translator::recover(x); } // Support for default construction via the default construction of _value. struct UseDecayedCtor {}; - explicit Atomic(UseDecayedCtor) : _value() {} + explicit constexpr Atomic(UseDecayedCtor) : _value() {} using DefaultCtorSelect = std::conditional_t, T, UseDecayedCtor>; @@ -424,9 +436,9 @@ class AtomicImpl::Atomic { // If T is default constructible, construct from a default constructed T. // Otherwise, default construct the underlying Atomic. - Atomic() : Atomic(DefaultCtorSelect()) {} + constexpr Atomic() : Atomic(DefaultCtorSelect()) {} - explicit Atomic(T value) : _value(decay(value)) {} + explicit constexpr Atomic(T value) : _value(decay(value)) {} NONCOPYABLE(Atomic);