Skip to content

Commit

Permalink
Merge branch 'trunk' into func_def
Browse files Browse the repository at this point in the history
  • Loading branch information
alinas authored Mar 4, 2025
2 parents c14ff91 + 4fd273a commit 4a66432
Show file tree
Hide file tree
Showing 176 changed files with 4,380 additions and 4,241 deletions.
5 changes: 4 additions & 1 deletion .vscode/gdb_launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"program": "bazel-bin/toolchain/testing/file_test",
"programArgs": "--file_tests=${relativeFile}",
"cwd": "${workspaceFolder}",
"env": { "TEST_TMPDIR": "/tmp" }
"env": {
"TEST_TARGET": "//toolchain/testing:file_test",
"TEST_TMPDIR": "/tmp"
}
},
{
"type": "by-gdb",
Expand Down
14 changes: 7 additions & 7 deletions .vscode/lldb_launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
"debuggerRoot": "${workspaceFolder}",
"initCommands": [
"command script import external/+llvm_project+llvm-project/llvm/utils/lldbDataFormatters.py",
"settings set target.source-map \".\" \"${workspaceFolder}\""
],
"env": { "TEST_TMPDIR": "/tmp" },
"sourceMap": {
"/proc/self/cwd/": "${workspaceFolder}"
}
"settings set target.source-map \".\" \"${workspaceFolder}\"",
"settings set target.source-map \"/proc/self/cwd\" \"${workspaceFolder}\"",
"env TEST_TARGET=//toolchain/testing:file_test",
"env TEST_TMPDIR=/tmp"
]
},
{
"type": "lldb-dap",
Expand All @@ -32,7 +31,8 @@
"debuggerRoot": "${workspaceFolder}",
"initCommands": [
"command script import external/+llvm_project+llvm-project/llvm/utils/lldbDataFormatters.py",
"settings set target.source-map \".\" \"${workspaceFolder}\""
"settings set target.source-map \".\" \"${workspaceFolder}\"",
"settings set target.source-map \"/proc/self/cwd\" \"${workspaceFolder}\""
]
}
]
Expand Down
51 changes: 45 additions & 6 deletions bazel/manifest/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

"""Rule for producing a manifest for a filegroup."""

def _manifest(ctx):
out = ctx.actions.declare_file(ctx.label.name)

def _get_files(ctx):
files = []
for src in ctx.attr.srcs:
files.extend([f.path for f in src[DefaultInfo].files.to_list()])
Expand All @@ -17,11 +15,16 @@ def _manifest(ctx):

if ctx.attr.strip_package_dir:
package_dir = ctx.label.package + "/"
content = [f.removeprefix(package_dir) for f in files]
files_stripped = [f.removeprefix(package_dir) for f in files]
else:
content = files
files_stripped = files

ctx.actions.write(out, "\n".join(content) + "\n")
return files_stripped

def _manifest(ctx):
out = ctx.actions.declare_file(ctx.label.name)
files = _get_files(ctx)
ctx.actions.write(out, "\n".join(files) + "\n")

return [
DefaultInfo(
Expand All @@ -30,10 +33,46 @@ def _manifest(ctx):
),
]

# Produces the manifest as a series of lines.
manifest = rule(
implementation = _manifest,
attrs = {
"srcs": attr.label_list(allow_files = True, mandatory = True),
"strip_package_dir": attr.bool(default = False),
},
)

def _manifest_as_cpp(ctx):
out = ctx.actions.declare_file(ctx.label.name)
files = _get_files(ctx)
lines = [
"// Auto-generated by manifest_as_cpp.",
"const char* {0}[] = {{".format(ctx.attr.var_name),
]
lines += [
" \"{0}\",".format(file)
for file in files
]
lines += [
" nullptr,",
"};",
]
ctx.actions.write(out, "\n".join(lines) + "\n")

return [
DefaultInfo(
files = depset(direct = [out]),
runfiles = ctx.runfiles(files = [out]),
),
]

# Produces the manifest as a nullptr-terminated `const char* var_name[]`.
# Use with `extern const char* var_name[];`.
manifest_as_cpp = rule(
implementation = _manifest_as_cpp,
attrs = {
"srcs": attr.label_list(allow_files = True, mandatory = True),
"strip_package_dir": attr.bool(default = False),
"var_name": attr.string(mandatory = True),
},
)
100 changes: 93 additions & 7 deletions common/map_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,26 @@

#include "common/raw_hashtable_test_helpers.h"

// Workaround for std::pair comparison deficiency in libc++ 16.
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
namespace std {
template <class T, class U, class V, class W>
requires(convertible_to<V, T> && convertible_to<W, U>)
inline auto operator==(
pair<std::reference_wrapper<T>, std::reference_wrapper<U>> lhs,
pair<V, W> rhs) -> bool {
return lhs.first == static_cast<T>(rhs.first) &&
lhs.second == static_cast<U>(rhs.second);
}
} // namespace std
#endif

namespace Carbon::Testing {
namespace {

using RawHashtable::FixedHashKeyContext;
using RawHashtable::IndexKeyContext;
using RawHashtable::MoveOnlyTestData;
using RawHashtable::TestData;
using RawHashtable::TestKeyContext;
using ::testing::Pair;
Expand All @@ -29,9 +44,11 @@ auto ExpectMapElementsAre(MapT&& m, MatcherRangeT element_matchers) -> void {
// Now collect the elements into a container.
using KeyT = typename std::remove_reference<MapT>::type::KeyT;
using ValueT = typename std::remove_reference<MapT>::type::ValueT;
std::vector<std::pair<KeyT, ValueT>> map_entries;
std::vector<
std::pair<std::reference_wrapper<KeyT>, std::reference_wrapper<ValueT>>>
map_entries;
m.ForEach([&map_entries](KeyT& k, ValueT& v) {
map_entries.push_back({k, v});
map_entries.push_back({std::ref(k), std::ref(v)});
});

// Use the GoogleMock unordered container matcher to validate and show errors
Expand Down Expand Up @@ -68,6 +85,9 @@ auto MakeKeyValues(ValueCB value_cb, RangeT&& range, RangeTs&&... ranges)
template <typename MapT>
class MapTest : public ::testing::Test {};

template <typename MapT>
class MoveOnlyMapTest : public ::testing::Test {};

using Types = ::testing::Types<
Map<int, int>, Map<int, int, 16>, Map<int, int, 64>,
Map<int, int, 0, TestKeyContext>, Map<int, int, 16, TestKeyContext>,
Expand All @@ -76,6 +96,14 @@ using Types = ::testing::Types<
Map<TestData, TestData, 16, TestKeyContext>>;
TYPED_TEST_SUITE(MapTest, Types);

using MoveOnlyTypes = ::testing::Types<
Map<MoveOnlyTestData, MoveOnlyTestData>,
Map<MoveOnlyTestData, MoveOnlyTestData, 16>,
Map<MoveOnlyTestData, MoveOnlyTestData, 64>,
Map<MoveOnlyTestData, MoveOnlyTestData, 0, TestKeyContext>,
Map<MoveOnlyTestData, MoveOnlyTestData, 16, TestKeyContext>>;
TYPED_TEST_SUITE(MoveOnlyMapTest, MoveOnlyTypes);

TYPED_TEST(MapTest, Basic) {
TypeParam m;

Expand Down Expand Up @@ -201,7 +229,7 @@ TYPED_TEST(MapTest, Move) {
// large.
for (int i : llvm::seq(1, 24)) {
SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
ASSERT_TRUE(m.Insert(i, i * 100).is_inserted());
EXPECT_TRUE(m.Insert(i, i * 100).is_inserted());
}

MapT other_m1 = std::move(m);
Expand Down Expand Up @@ -244,17 +272,75 @@ TYPED_TEST(MapTest, Move) {
ExpectMapElementsAre(
other_m1, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 32)));

// Test copying of a moved-from table over a valid table and self-move-assign.
// The former is required to be valid, and the latter is in at least the case
// of self-move-assign-when-moved-from, but the result can be in any state so
// just do them and ensure we don't crash.
// Test copying of a moved-from table over a valid table and
// self-move-assign. The former is required to be valid, and the latter is
// in at least the case of self-move-assign-when-moved-from, but the result
// can be in any state so just do them and ensure we don't crash.
MapT other_m2 = other_m1;
// NOLINTNEXTLINE(bugprone-use-after-move): Testing required use-after-move.
other_m2 = m;
other_m1 = std::move(other_m1);
m = std::move(m);
}

TYPED_TEST(MoveOnlyMapTest, MoveOnlyTypes) {
using MapT = TypeParam;
static_assert(!std::is_copy_assignable_v<MapT>);
static_assert(!std::is_copy_constructible_v<MapT>);
static_assert(std::is_move_assignable_v<MapT>);
static_assert(std::is_move_constructible_v<MapT>);

auto make_map = [] {
MapT m;
// Make sure we exceed the small size for some of the map types, but not all
// of them, so we cover all the combinations of moving between small and
// large.
for (int i : llvm::seq(1, 24)) {
SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
EXPECT_TRUE(m.Insert(i, i * 100).is_inserted());
}
return m;
};

MapT m = make_map();

MapT other_m1 = std::move(m);
ExpectMapElementsAre(
other_m1, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 24)));

// Add some more elements.
for (int i : llvm::seq(24, 32)) {
SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
ASSERT_TRUE(other_m1.Insert(i, i * 100).is_inserted());
}
ExpectMapElementsAre(
other_m1, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 32)));

// Move back over a moved-from.
m = std::move(other_m1);
ExpectMapElementsAre(
m, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 32)));

// Now add still more elements, crossing the small size limit for all tested
// map types.
for (int i : llvm::seq(32, 72)) {
SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
ASSERT_TRUE(m.Insert(i, i * 100).is_inserted());
}
ExpectMapElementsAre(
m, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 72)));

// Assignment replaces the contents.
m = make_map();
ExpectMapElementsAre(
m, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 24)));

// Self-swap (which does a self-move) works and is a no-op.
std::swap(m, m);
ExpectMapElementsAre(
m, MakeKeyValues([](int k) { return k * 100; }, llvm::seq(1, 24)));
}

TYPED_TEST(MapTest, Conversions) {
using MapT = TypeParam;
using KeyT = MapT::KeyT;
Expand Down
29 changes: 23 additions & 6 deletions common/raw_hashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ struct StorageEntry {
IsTriviallyDestructible && std::is_trivially_move_constructible_v<KeyT> &&
std::is_trivially_move_constructible_v<ValueT>;

static constexpr bool IsCopyable =
IsTriviallyRelocatable || (std::is_copy_constructible_v<KeyT> &&
std::is_copy_constructible_v<ValueT>);

auto key() const -> const KeyT& {
// Ensure we don't need more alignment than available. Inside a method body
// to apply to the complete type.
Expand Down Expand Up @@ -233,6 +237,9 @@ struct StorageEntry<KeyT, void> {
static constexpr bool IsTriviallyRelocatable =
IsTriviallyDestructible && std::is_trivially_move_constructible_v<KeyT>;

static constexpr bool IsCopyable =
IsTriviallyRelocatable || std::is_copy_constructible_v<KeyT>;

auto key() const -> const KeyT& {
// Ensure we don't need more alignment than available.
static_assert(
Expand All @@ -252,7 +259,9 @@ struct StorageEntry<KeyT, void> {
key().~KeyT();
}

auto CopyFrom(const StorageEntry& entry) -> void {
auto CopyFrom(const StorageEntry& entry) -> void
requires(IsCopyable)
{
if constexpr (IsTriviallyRelocatable) {
memcpy(this, &entry, sizeof(StorageEntry));
} else {
Expand Down Expand Up @@ -567,7 +576,8 @@ class BaseImpl {

auto Construct(Storage* small_storage) -> void;
auto Destroy() -> void;
auto CopySlotsFrom(const BaseImpl& arg) -> void;
auto CopySlotsFrom(const BaseImpl& arg) -> void
requires(EntryT::IsCopyable);
auto MoveFrom(BaseImpl&& arg, Storage* small_storage) -> void;

auto InsertIntoEmpty(HashCode hash) -> EntryT*;
Expand Down Expand Up @@ -611,9 +621,11 @@ class TableImpl : public InputBaseT {
using BaseT = InputBaseT;

TableImpl() : BaseT(SmallSize, small_storage()) {}
TableImpl(const TableImpl& arg);
TableImpl(const TableImpl& arg)
requires(BaseT::EntryT::IsCopyable);
TableImpl(TableImpl&& arg) noexcept;
auto operator=(const TableImpl& arg) -> TableImpl&;
auto operator=(const TableImpl& arg) -> TableImpl&
requires(BaseT::EntryT::IsCopyable);
auto operator=(TableImpl&& arg) noexcept -> TableImpl&;
~TableImpl();

Expand Down Expand Up @@ -1202,7 +1214,9 @@ auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::Destroy() -> void {
// storage.
template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::CopySlotsFrom(
const BaseImpl& arg) -> void {
const BaseImpl& arg) -> void
requires(EntryT::IsCopyable)
{
CARBON_DCHECK(alloc_size() == arg.alloc_size());
ssize_t local_size = alloc_size();

Expand Down Expand Up @@ -1545,6 +1559,7 @@ BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::GrowAndInsert(

template <typename InputBaseT, ssize_t SmallSize>
TableImpl<InputBaseT, SmallSize>::TableImpl(const TableImpl& arg)
requires(BaseT::EntryT::IsCopyable)
: BaseT(arg.alloc_size(), arg.growth_budget_, SmallSize) {
// Check for completely broken objects. These invariants should be true even
// in a moved-from state.
Expand All @@ -1561,7 +1576,9 @@ TableImpl<InputBaseT, SmallSize>::TableImpl(const TableImpl& arg)

template <typename InputBaseT, ssize_t SmallSize>
auto TableImpl<InputBaseT, SmallSize>::operator=(const TableImpl& arg)
-> TableImpl& {
-> TableImpl&
requires(BaseT::EntryT::IsCopyable)
{
// Check for completely broken objects. These invariants should be true even
// in a moved-from state.
CARBON_DCHECK(arg.alloc_size() == 0 || !arg.is_small() ||
Expand Down
Loading

0 comments on commit 4a66432

Please sign in to comment.