CloneContext: Assert objects are owned by the program

Check that pre-clone objects are owned by the source program.
Check that post-clone object are owned by the target builder.

Fixed: tint:469
Change-Id: Idd0eeb8dfb386e295b66b4b6621cc13dc1a30786
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48260
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
Ben Clayton 2021-04-19 16:50:23 +00:00 committed by Commit Bot service account
parent b895ba1cea
commit 917b14b626
6 changed files with 88 additions and 3 deletions

View File

@ -81,7 +81,7 @@ class Node : public Castable<Node, Cloneable> {
/// @param node a pointer to an AST node
/// @returns the ProgramID of the given AST node.
inline ProgramID ProgramIDOf(ast::Node* node) {
inline ProgramID ProgramIDOf(const ast::Node* node) {
return node ? node->program_id() : ProgramID();
}

View File

@ -32,11 +32,14 @@ namespace tint {
class CloneContext;
class Program;
class ProgramBuilder;
namespace ast {
class FunctionList;
class Node;
} // namespace ast
ProgramID ProgramIDOf(const Program*);
ProgramID ProgramIDOf(const ast::Node*);
/// Cloneable is the base class for all objects that can be cloned
class Cloneable : public Castable<Cloneable> {
public:
@ -46,6 +49,11 @@ class Cloneable : public Castable<Cloneable> {
virtual Cloneable* Clone(CloneContext* ctx) const = 0;
};
/// @returns an invalid ProgramID
inline ProgramID ProgramIDOf(const Cloneable*) {
return ProgramID();
}
/// ShareableCloneable is the base class for Cloneable objects which will only
/// be cloned once when CloneContext::Clone() is called with the same object
/// pointer.
@ -95,6 +103,8 @@ class CloneContext {
return nullptr;
}
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
// Have we cloned this object already, or was Replace() called for this
// object?
auto it = cloned_.find(a);
@ -127,7 +137,11 @@ class CloneContext {
cloned_.emplace(a, cloned);
}
return CheckedCast<T>(cloned);
auto* out = CheckedCast<T>(cloned);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, out);
return out;
}
/// Clones the Node or type::Type `a` into the ProgramBuilder #dst if `a` is
@ -149,6 +163,8 @@ class CloneContext {
return nullptr;
}
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
// Have we seen this object before? If so, return the previously cloned
// version instead of making yet another copy.
auto it = cloned_.find(a);

View File

@ -97,6 +97,23 @@ struct NotANode : public Castable<NotANode, Cloneable> {
}
};
struct ProgramNode : public Castable<ProgramNode, Cloneable> {
ProgramNode(Allocator* alloc, ProgramID id, ProgramID cloned_id)
: allocator(alloc), program_id(id), cloned_program_id(cloned_id) {}
Allocator* const allocator;
ProgramID const program_id;
ProgramID const cloned_program_id;
ProgramNode* Clone(CloneContext*) const override {
return allocator->Create<ProgramNode>(cloned_program_id, cloned_program_id);
}
};
ProgramID ProgramIDOf(const ProgramNode* node) {
return node->program_id;
}
struct UniqueTypes {
using Node = UniqueNode;
using Replaceable = UniqueReplaceable;
@ -642,6 +659,38 @@ TYPED_TEST(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
}
TYPED_TEST(CloneContextTest, ProgramIDs) {
ProgramBuilder dst;
Program src(ProgramBuilder{});
CloneContext ctx(&dst, &src);
Allocator allocator;
ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
}
TYPED_TEST(CloneContextTest, ProgramIDs_ObjectNotOwnedBySrc) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder dst;
Program src(ProgramBuilder{});
CloneContext ctx(&dst, &src);
Allocator allocator;
ctx.Clone(allocator.Create<ProgramNode>(ProgramID::New(), dst.ID()));
},
R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a))");
}
TYPED_TEST(CloneContextTest, ProgramIDs_ObjectNotOwnedByDst) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder dst;
Program src(ProgramBuilder{});
CloneContext ctx(&dst, &src);
Allocator allocator;
ctx.Clone(allocator.Create<ProgramNode>(src.ID(), ProgramID::New()));
},
R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, out))");
}
} // namespace
TINT_INSTANTIATE_TYPEINFO(UniqueNode);
@ -651,5 +700,6 @@ TINT_INSTANTIATE_TYPEINFO(ShareableNode);
TINT_INSTANTIATE_TYPEINFO(ShareableReplaceable);
TINT_INSTANTIATE_TYPEINFO(ShareableReplacement);
TINT_INSTANTIATE_TYPEINFO(NotANode);
TINT_INSTANTIATE_TYPEINFO(ProgramNode);
} // namespace tint

View File

@ -171,6 +171,12 @@ class Program {
bool moved_ = false;
};
/// @param program the Program
/// @returns the ProgramID of the Program
inline ProgramID ProgramIDOf(const Program* program) {
return program->ID();
}
} // namespace tint
#endif // SRC_PROGRAM_H_

View File

@ -1505,6 +1505,12 @@ struct ProgramBuilder::TypesBuilder::CToAST<void> {
};
//! @endcond
/// @param builder the ProgramBuilder
/// @returns the ProgramID of the ProgramBuilder
inline ProgramID ProgramIDOf(const ProgramBuilder* builder) {
return builder->ID();
}
} // namespace tint
#endif // SRC_PROGRAM_BUILDER_H_

View File

@ -102,6 +102,13 @@ class Type : public Castable<Type, ShareableCloneable> {
Type();
};
/// @returns the ProgramID of the given type.
inline ProgramID ProgramIDOf(const Type*) {
/// TODO(crbug.com/tint/724): Actually implement this once we split the `type`
/// namespace into ast::Type and sem::Type.
return ProgramID();
}
} // namespace type
} // namespace tint