Skip to content

Commit c2b0f47

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): Early return if fail enum check * rust-diagnostics.cc (expand_message): non-static now. * rust-diagnostics.h (RUST_ATTRIBUTE_GCC_DIAG): non-static expand msg (expand_message): likewise.
1 parent 76a3c64 commit c2b0f47

File tree

5 files changed

+93
-10
lines changed

5 files changed

+93
-10
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,16 @@ CompileItem::visit (HIR::Function &function)
269269
ctx->pop_const_context ();
270270
}
271271

272+
void
273+
CompileItem::visit (HIR::Enum &e)
274+
{
275+
TyTy::BaseType *resolved_type = nullptr;
276+
bool ok = ctx->get_tyctx ()->lookup_type (e.get_mappings ().get_hirid (),
277+
&resolved_type);
278+
rust_assert (ok);
279+
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
280+
reference = type;
281+
}
272282
void
273283
CompileItem::visit (HIR::ImplBlock &impl_block)
274284
{

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor
4444
void visit (HIR::ImplBlock &impl_block) override;
4545
void visit (HIR::ExternBlock &extern_block) override;
4646
void visit (HIR::Module &module) override;
47-
47+
void visit (HIR::Enum &) override;
4848
// Empty visit for unused Stmt HIR nodes.
4949
void visit (HIR::TupleStruct &) override {}
5050
void visit (HIR::EnumItem &) override {}
@@ -58,7 +58,6 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor
5858
void visit (HIR::UseDeclaration &) override {}
5959
void visit (HIR::TypeAlias &) override {}
6060
void visit (HIR::StructStruct &) override {}
61-
void visit (HIR::Enum &) override {}
6261
void visit (HIR::Union &) override {}
6362
void visit (HIR::Trait &) override {}
6463
void visit (HIR::EmptyStmt &) override {}

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

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
#include "rust-compile-expr.h"
2121
#include "rust-constexpr.h"
2222
#include "rust-gcc.h"
23+
#include "rust-diagnostics.h"
2324

2425
#include "tree.h"
2526
#include "stor-layout.h"
26-
2727
namespace Rust {
2828
namespace Compile {
2929

@@ -248,14 +248,72 @@ TyTyResolveCompile::visit (const TyTy::FnPtr &type)
248248
type.get_ident ().locus);
249249
}
250250

251+
bool
252+
check_variant_record_collision (Context *ctx, const TyTy::ADTType &type,
253+
std::vector<tree> &variant_records)
254+
{
255+
// bdbt: we're checking if shared discriminants crash with each other or
256+
// not. lets make a map from uhwi to hir id. A clash of uhwi in a variant
257+
// record to which said record can be converted uhwi is indicative of
258+
// issue 3351 of gccrs
259+
260+
std::map<HOST_WIDE_INT, std::vector<size_t>> shwi_to_index;
261+
for (size_t i = 0; i < variant_records.size (); i++)
262+
{
263+
TyTy::VariantDef *variant = type.get_variants ().at (i);
264+
if (variant->has_discriminant ())
265+
{
266+
ctx->push_const_context ();
267+
tree discriminant_expr
268+
= CompileExpr::Compile (variant->get_discriminant (), ctx);
269+
ctx->push_const_context ();
270+
tree folded_expr = fold_expr (discriminant_expr);
271+
if (folded_expr == error_mark_node)
272+
{
273+
// if we have discriminant but we fail to fold it, return false
274+
return false;
275+
}
276+
HOST_WIDE_INT discriminant_integer = tree_to_shwi (folded_expr);
277+
shwi_to_index[discriminant_integer].push_back (i);
278+
}
279+
}
280+
281+
bool has_failed = false;
282+
for (const auto &map_item : shwi_to_index)
283+
{
284+
auto discriminant_integer = map_item.first;
285+
const auto &index_vector = map_item.second;
286+
// collision doesn't happen, move to next item
287+
if (index_vector.size () <= 1)
288+
continue;
289+
290+
has_failed = true;
291+
rich_location r (line_table, type.get_locus ());
292+
std::string assigned_here_msg
293+
= expand_message (HOST_WIDE_INT_PRINT_DEC " assigned here",
294+
discriminant_integer);
295+
std::string assigned_more_once_msg
296+
= expand_message ("discriminant value " HOST_WIDE_INT_PRINT_DEC
297+
" assigned more than once",
298+
discriminant_integer);
299+
for (auto index : index_vector)
300+
{
301+
TyTy::VariantDef *variant = type.get_variants ().at (index);
302+
r.add_fixit_replace (variant->get_discriminant ().get_locus (),
303+
assigned_here_msg.c_str ());
304+
}
305+
rust_error_at (r, ErrorCode::E0081, "%s",
306+
assigned_more_once_msg.c_str ());
307+
}
308+
return !has_failed;
309+
}
251310
void
252311
TyTyResolveCompile::visit (const TyTy::ADTType &type)
253312
{
254313
tree type_record = error_mark_node;
255314
if (!type.is_enum ())
256315
{
257316
rust_assert (type.number_of_variants () == 1);
258-
259317
TyTy::VariantDef &variant = *type.get_variants ().at (0);
260318
std::vector<Backend::typed_identifier> fields;
261319
for (size_t i = 0; i < variant.num_fields (); i++)
@@ -358,9 +416,15 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
358416
// add them to the list
359417
variant_records.push_back (named_variant_record);
360418
}
361-
362-
// now we need to make the actual union, but first we need to make
363-
// named_type TYPE_DECL's out of the variants
419+
// TODO: bdbt set up defid and a map (or set?) to check if we have
420+
// checked for collision already.
421+
if (!check_variant_record_collision (ctx, type, variant_records))
422+
{
423+
translated = error_mark_node;
424+
return;
425+
}
426+
// the actual union, but first we need to make named_type TYPE_DECL's out
427+
// of the variants
364428

365429
size_t i = 0;
366430
std::vector<Backend::typed_identifier> enum_fields;

gcc/rust/rust-diagnostics.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ expand_format (const char *fmt)
104104
// calling function must need to have attribute gnu_printf as well, even
105105
// though there is already an attribute declaration for it.
106106

107-
static std::string
108-
expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0);
109-
110107
#pragma GCC diagnostic push
111108
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
112109

@@ -127,6 +124,16 @@ expand_message (const char *fmt, va_list ap)
127124
free (mbuf);
128125
return rval;
129126
}
127+
std::string
128+
expand_message (const char *fmt, ...)
129+
{
130+
va_list ap;
131+
132+
va_start (ap, fmt);
133+
std::string str = expand_message (fmt, ap);
134+
va_end (ap);
135+
return str;
136+
}
130137

131138
#pragma GCC diagnostic pop
132139

gcc/rust/rust-diagnostics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ enum class ErrorCode : unsigned int
8080
#undef ERROR
8181

8282
// clang-format off
83+
std::string
84+
expand_message (const char *fmt, ...) RUST_ATTRIBUTE_GCC_DIAG (1, 2);
85+
8386
extern void
8487
rust_internal_error_at (const location_t, const char *fmt, ...)
8588
RUST_ATTRIBUTE_GCC_DIAG (2, 3)

0 commit comments

Comments
 (0)