Skip to content

Commit b092c7c

Browse files
committed
Fix clash of enum shared discriminant
gcc/rust/ChangeLog: * backend/rust-compile-item.cc (CompileItem::visit): Use HIR::Enum visit * backend/rust-compile-item.h: Fix clash of enum shared discriminant * backend/rust-compile-type.cc (check_variant_record_collision): Likewise (TyTyResolveCompile::visit): Likewise.
1 parent 540708e commit b092c7c

File tree

3 files changed

+77
-7
lines changed

3 files changed

+77
-7
lines changed

gcc/rust/backend/rust-compile-item.cc

+11
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@ CompileItem::visit (HIR::Function &function)
265265
ctx->pop_const_context ();
266266
}
267267

268+
void
269+
CompileItem::visit (HIR::Enum &e)
270+
{
271+
TyTy::BaseType *resolved_type = nullptr;
272+
bool ok = ctx->get_tyctx ()->lookup_type (e.get_mappings ().get_hirid (),
273+
&resolved_type);
274+
rust_assert (ok);
275+
276+
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
277+
reference = type;
278+
}
268279
void
269280
CompileItem::visit (HIR::ImplBlock &impl_block)
270281
{

gcc/rust/backend/rust-compile-item.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor
4848
void visit (HIR::ImplBlock &impl_block) override;
4949
void visit (HIR::ExternBlock &extern_block) override;
5050
void visit (HIR::Module &module) override;
51-
51+
void visit (HIR::Enum &) override;
5252
// Empty visit for unused Stmt HIR nodes.
5353
void visit (HIR::TupleStruct &) override {}
5454
void visit (HIR::EnumItem &) override {}
@@ -62,7 +62,6 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor
6262
void visit (HIR::UseDeclaration &) override {}
6363
void visit (HIR::TypeAlias &) override {}
6464
void visit (HIR::StructStruct &) override {}
65-
void visit (HIR::Enum &) override {}
6665
void visit (HIR::Union &) override {}
6766
void visit (HIR::Trait &) override {}
6867
void visit (HIR::EmptyStmt &) override {}

gcc/rust/backend/rust-compile-type.cc

+65-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
#include "tree.h"
2525
#include "stor-layout.h"
26-
2726
namespace Rust {
2827
namespace Compile {
2928

@@ -239,14 +238,69 @@ TyTyResolveCompile::visit (const TyTy::FnPtr &type)
239238
type.get_ident ().locus);
240239
}
241240

241+
bool
242+
check_variant_record_collision (Context *ctx, const TyTy::ADTType &type,
243+
std::vector<tree> &variant_records)
244+
{
245+
// bdbt: we're checking if shared discriminants crash with each other or
246+
// not. lets make a map from uhwi to hir id. A clash of uhwi in a variant
247+
// record to which said record can be converted uhwi is indicative of
248+
// issue 3351 of gccrs
249+
250+
std::map<HOST_WIDE_INT, std::vector<size_t>> shwi_to_index;
251+
for (size_t i = 0; i < variant_records.size (); i++)
252+
{
253+
TyTy::VariantDef *variant = type.get_variants ().at (i);
254+
if (variant->has_discriminant ())
255+
{
256+
tree discriminant_expr
257+
= CompileExpr::Compile (variant->get_discriminant (), ctx);
258+
tree folded_expr = fold_expr (discriminant_expr);
259+
if (folded_expr == error_mark_node)
260+
{
261+
// if we have discriminant but we fail to fold it, return false
262+
return false;
263+
}
264+
HOST_WIDE_INT discriminant_integer = tree_to_shwi (folded_expr);
265+
shwi_to_index[discriminant_integer].push_back (i);
266+
}
267+
}
268+
269+
bool has_failed = false;
270+
for (const auto &map_item : shwi_to_index)
271+
{
272+
auto discriminant_integer = map_item.first;
273+
const auto &index_vector = map_item.second;
274+
// collision doesn't happen, move to next item
275+
if (index_vector.size () <= 1)
276+
continue;
277+
278+
has_failed = true;
279+
rich_location r (line_table, type.get_locus ());
280+
std::string assigned_here_msg = "\""
281+
+ std::to_string (discriminant_integer)
282+
+ "\"" + " assigned here";
283+
std::string assigned_more_once_msg
284+
= "discriminant value \"" + std::to_string (discriminant_integer) + "\""
285+
+ " assigned more than once";
286+
for (auto index : index_vector)
287+
{
288+
TyTy::VariantDef *variant = type.get_variants ().at (index);
289+
r.add_fixit_replace (variant->get_discriminant ().get_locus (),
290+
assigned_here_msg.c_str ());
291+
}
292+
rust_error_at (r, ErrorCode::E0081, "%s",
293+
assigned_more_once_msg.c_str ());
294+
}
295+
return !has_failed;
296+
}
242297
void
243298
TyTyResolveCompile::visit (const TyTy::ADTType &type)
244299
{
245300
tree type_record = error_mark_node;
246301
if (!type.is_enum ())
247302
{
248303
rust_assert (type.number_of_variants () == 1);
249-
250304
TyTy::VariantDef &variant = *type.get_variants ().at (0);
251305
std::vector<Backend::typed_identifier> fields;
252306
for (size_t i = 0; i < variant.num_fields (); i++)
@@ -349,9 +403,15 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
349403
// add them to the list
350404
variant_records.push_back (named_variant_record);
351405
}
352-
353-
// now we need to make the actual union, but first we need to make
354-
// named_type TYPE_DECL's out of the variants
406+
// TODO: bdbt set up defid and a map (or set?) to check if we have
407+
// checked for collision already.
408+
if (!check_variant_record_collision (ctx, type, variant_records))
409+
{
410+
translated = error_mark_node;
411+
return;
412+
}
413+
// the actual union, but first we need to make named_type TYPE_DECL's out
414+
// of the variants
355415

356416
size_t i = 0;
357417
std::vector<Backend::typed_identifier> enum_fields;

0 commit comments

Comments
 (0)