Skip to content

Commit 6231646

Browse files
author
Kim Barrett
committed
8373208: Make Atomic class template constant initializable
Reviewed-by: stefank, dholmes
1 parent f88cbfb commit 6231646

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

src/hotspot/share/runtime/atomic.hpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#define SHARE_RUNTIME_ATOMIC_HPP
2727

2828
#include "cppstdlib/type_traits.hpp"
29-
#include "metaprogramming/enableIf.hpp"
3029
#include "metaprogramming/primitiveConversions.hpp"
3130
#include "runtime/atomicAccess.hpp"
3231
#include "utilities/globalDefinitions.hpp"
@@ -89,8 +88,12 @@
8988
// value will be initialized as if by translating the value that would be
9089
// provided by default constructing an atomic type for the value type's
9190
// decayed type.
92-
93-
// (3) Atomic pointers and atomic integers additionally provide
91+
//
92+
// (3) Constructors for all atomic types are constexpr, to ensure non-local
93+
// atomic variables are constant initialized (C++17 6.6.2) when initialized
94+
// with suitable arguments.
95+
//
96+
// (4) Atomic pointers and atomic integers additionally provide
9497
//
9598
// member functions:
9699
// v.add_then_fetch(i [, o]) -> T
@@ -102,7 +105,7 @@
102105
// type of i must be signed, or both must be unsigned. Atomic pointers perform
103106
// element arithmetic.
104107
//
105-
// (4) Atomic integers additionally provide
108+
// (5) Atomic integers additionally provide
106109
//
107110
// member functions:
108111
// v.and_then_fetch(x [, o]) -> T
@@ -112,7 +115,7 @@
112115
// v.fetch_then_or(x [, o]) -> T
113116
// v.fetch_then_xor(x [, o]) -> T
114117
//
115-
// (5) Atomic pointers additionally provide
118+
// (6) Atomic pointers additionally provide
116119
//
117120
// nested types:
118121
// ElementType -> std::remove_pointer_t<T>
@@ -217,7 +220,7 @@ class AtomicImpl::CommonCore {
217220
T volatile _value;
218221

219222
protected:
220-
explicit CommonCore(T value) : _value(value) {}
223+
explicit constexpr CommonCore(T value) : _value(value) {}
221224
~CommonCore() = default;
222225

223226
T volatile* value_ptr() { return &_value; }
@@ -290,7 +293,7 @@ class AtomicImpl::SupportsArithmetic : public CommonCore<T> {
290293
}
291294

292295
protected:
293-
explicit SupportsArithmetic(T value) : CommonCore<T>(value) {}
296+
explicit constexpr SupportsArithmetic(T value) : CommonCore<T>(value) {}
294297
~SupportsArithmetic() = default;
295298

296299
public:
@@ -333,7 +336,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Integer>
333336
: public SupportsArithmetic<T>
334337
{
335338
public:
336-
explicit Atomic(T value = 0) : SupportsArithmetic<T>(value) {}
339+
explicit constexpr Atomic(T value = 0) : SupportsArithmetic<T>(value) {}
337340

338341
NONCOPYABLE(Atomic);
339342

@@ -373,7 +376,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Byte>
373376
: public CommonCore<T>
374377
{
375378
public:
376-
explicit Atomic(T value = 0) : CommonCore<T>(value) {}
379+
explicit constexpr Atomic(T value = 0) : CommonCore<T>(value) {}
377380

378381
NONCOPYABLE(Atomic);
379382

@@ -389,7 +392,7 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Pointer>
389392
: public SupportsArithmetic<T>
390393
{
391394
public:
392-
explicit Atomic(T value = nullptr) : SupportsArithmetic<T>(value) {}
395+
explicit constexpr Atomic(T value = nullptr) : SupportsArithmetic<T>(value) {}
393396

394397
NONCOPYABLE(Atomic);
395398

@@ -410,12 +413,21 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Translated> {
410413

411414
Atomic<Decayed> _value;
412415

413-
static Decayed decay(T x) { return Translator::decay(x); }
416+
// The decay function and the constructors are constexpr so that a non-local
417+
// atomic object constructed with constant arguments will be a constant
418+
// initialization. One might ask why it's not a problem that some
419+
// specializations of these functions are not constant expressions. The
420+
// answer lies in C++17 10.1.5/6, along with us having *some* constexpr
421+
// translator decay functions, constexpr ctors for some translated types,
422+
// and constexpr ctors for some decayed types. Also, C++23 removes those
423+
// restrictions on constexpr functions and ctors.
424+
425+
static constexpr Decayed decay(T x) { return Translator::decay(x); }
414426
static T recover(Decayed x) { return Translator::recover(x); }
415427

416428
// Support for default construction via the default construction of _value.
417429
struct UseDecayedCtor {};
418-
explicit Atomic(UseDecayedCtor) : _value() {}
430+
explicit constexpr Atomic(UseDecayedCtor) : _value() {}
419431
using DefaultCtorSelect =
420432
std::conditional_t<std::is_default_constructible_v<T>, T, UseDecayedCtor>;
421433

@@ -424,9 +436,9 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Translated> {
424436

425437
// If T is default constructible, construct from a default constructed T.
426438
// Otherwise, default construct the underlying Atomic<Decayed>.
427-
Atomic() : Atomic(DefaultCtorSelect()) {}
439+
constexpr Atomic() : Atomic(DefaultCtorSelect()) {}
428440

429-
explicit Atomic(T value) : _value(decay(value)) {}
441+
explicit constexpr Atomic(T value) : _value(decay(value)) {}
430442

431443
NONCOPYABLE(Atomic);
432444

0 commit comments

Comments
 (0)