Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3d35414

Browse files
committedMar 11, 2025·
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 8a75a83 commit 3d35414

5 files changed

+93
-11
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

+67-5
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

@@ -239,14 +239,70 @@ TyTyResolveCompile::visit (const TyTy::FnPtr &type)
239239
type.get_ident ().locus);
240240
}
241241

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

356418
size_t i = 0;
357419
std::vector<Backend::typed_identifier> enum_fields;

‎gcc/rust/rust-diagnostics.cc

+10-3
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

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
3232
#define RUST_ATTRIBUTE_GCC_DIAG(m, n) \
3333
__attribute__ ((__format__ (__gcc_tdiag__, m, n))) \
34-
__attribute__ ((__nonnull__ (m)))
34+
__attribute__ ((__nonnull__ (m)))
3535
#else
3636
#define RUST_ATTRIBUTE_GCC_DIAG(m, n)
3737
#endif
@@ -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)
Please sign in to comment.