8376810: Make Atomic<T> default constructor non-explicit

Reviewed-by: kbarrett, aboldtch, azafari, tschatzl
This commit is contained in:
Stefan Karlsson 2026-02-04 08:41:38 +00:00
parent b0829a54cd
commit 3f3dcb708d
2 changed files with 95 additions and 6 deletions

View File

@ -58,9 +58,10 @@
// ValueType -> T
//
// special functions:
// explicit constructor(T)
// constexpr constructor() // See (2) below
// explicit constexpr constructor(T)
// noncopyable
// destructor
// destructor // Trivial
//
// static member functions:
// value_offset_in_bytes() -> int // constexpr
@ -343,7 +344,8 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Integer>
: public SupportsArithmetic<T>
{
public:
explicit constexpr Atomic(T value = 0) : SupportsArithmetic<T>(value) {}
constexpr Atomic() : Atomic(0) {}
explicit constexpr Atomic(T value) : SupportsArithmetic<T>(value) {}
NONCOPYABLE(Atomic);
@ -383,7 +385,8 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Byte>
: public CommonCore<T>
{
public:
explicit constexpr Atomic(T value = 0) : CommonCore<T>(value) {}
constexpr Atomic() : Atomic(0) {}
explicit constexpr Atomic(T value) : CommonCore<T>(value) {}
NONCOPYABLE(Atomic);
@ -399,7 +402,8 @@ class AtomicImpl::Atomic<T, AtomicImpl::Category::Pointer>
: public SupportsArithmetic<T>
{
public:
explicit constexpr Atomic(T value = nullptr) : SupportsArithmetic<T>(value) {}
constexpr Atomic() : Atomic(nullptr) {}
explicit constexpr Atomic(T value) : SupportsArithmetic<T>(value) {}
NONCOPYABLE(Atomic);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,15 +22,100 @@
*
*/
#include "cppstdlib/new.hpp"
#include "cppstdlib/type_traits.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
#include "unittest.hpp"
// These tests of Atomic<T> only verify functionality. They don't verify
// atomicity.
template<typename T>
struct AtomicInitializationTestSupport {
struct Holder {
Atomic<T> _explicitly_initialized;
Atomic<T> _default_initialized;
Atomic<T> _value_initialized;
Holder()
: _explicitly_initialized(T()),
/* _default_initialized */
_value_initialized{}
{}
};
struct HolderNoConstructor {
Atomic<T> _default_initialized;
};
void test() {
T t = T();
{
Holder h;
EXPECT_EQ(t, h._explicitly_initialized.load_relaxed());
EXPECT_EQ(t, h._default_initialized.load_relaxed());
EXPECT_EQ(t, h._value_initialized.load_relaxed());
}
{
Holder h{};
EXPECT_EQ(t, h._explicitly_initialized.load_relaxed());
EXPECT_EQ(t, h._default_initialized.load_relaxed());
EXPECT_EQ(t, h._value_initialized.load_relaxed());
}
{
alignas(Holder) char mem[sizeof(Holder)];
memset(mem, 0xFF, sizeof(Holder));
Holder* h = new (mem) Holder();
EXPECT_EQ(t, h->_explicitly_initialized.load_relaxed());
EXPECT_EQ(t, h->_default_initialized.load_relaxed());
EXPECT_EQ(t, h->_value_initialized.load_relaxed());
}
// No-constructor variant
{
HolderNoConstructor h;
EXPECT_EQ(t, h._default_initialized.load_relaxed());
}
{
HolderNoConstructor h{};
EXPECT_EQ(t, h._default_initialized.load_relaxed());
}
{
alignas(HolderNoConstructor) char mem[sizeof(HolderNoConstructor)];
memset(mem, 0xFF, sizeof(HolderNoConstructor));
HolderNoConstructor* h = new (mem) HolderNoConstructor();
EXPECT_EQ(t, h->_default_initialized.load_relaxed());
}
}
};
TEST_VM(AtomicInitializationTest, byte) {
AtomicInitializationTestSupport<char>().test();
}
TEST_VM(AtomicInitializationTest, integer) {
AtomicInitializationTestSupport<int32_t>().test();
}
TEST_VM(AtomicInitializationTest, pointer) {
AtomicInitializationTestSupport<void*>().test();
}
template<typename T>
struct AtomicIntegerArithmeticTestSupport {
Atomic<T> _test_value;