From 7cf18543bb7ea61c0e518a0c6085b8fc0a04b7e0 Mon Sep 17 00:00:00 2001 From: badumbatish Date: Wed, 26 Feb 2025 00:57:03 -0800 Subject: [PATCH 1/2] Establish new test for shared discriminant gcc/testsuite/ChangeLog: * rust/compile/shared_discriminator_enum.rs: New test. --- gcc/testsuite/rust/compile/shared_discriminator_enum.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 gcc/testsuite/rust/compile/shared_discriminator_enum.rs diff --git a/gcc/testsuite/rust/compile/shared_discriminator_enum.rs b/gcc/testsuite/rust/compile/shared_discriminator_enum.rs new file mode 100644 index 000000000000..85627a8f5379 --- /dev/null +++ b/gcc/testsuite/rust/compile/shared_discriminator_enum.rs @@ -0,0 +1,7 @@ +// from issue 3351: https://github.com/Rust-GCC/gccrs/issues/3351 +enum Foo { // { dg-error "discriminant value 1 assigned more than once" } + Bar = 1, + Qaz = 1, +} + +fn main() {} From 074a58a9bc58bd42c0ace42f7c4a9c9843f978ea Mon Sep 17 00:00:00 2001 From: badumbatish Date: Wed, 26 Feb 2025 01:51:26 -0800 Subject: [PATCH 2/2] 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. --- gcc/rust/backend/rust-compile-item.cc | 11 ++++ gcc/rust/backend/rust-compile-item.h | 3 +- gcc/rust/backend/rust-compile-type.cc | 72 +++++++++++++++++++++++++-- gcc/rust/rust-diagnostics.cc | 13 +++-- gcc/rust/rust-diagnostics.h | 3 ++ 5 files changed, 92 insertions(+), 10 deletions(-) diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 6ed5b3980c0a..8ef4255378bc 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -269,6 +269,17 @@ CompileItem::visit (HIR::Function &function) ctx->pop_const_context (); } +void +CompileItem::visit (HIR::Enum &e) +{ + TyTy::BaseType *resolved_type = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type (e.get_mappings ().get_hirid (), + &resolved_type); + rust_assert (ok); + + tree type = TyTyResolveCompile::compile (ctx, resolved_type); + reference = type; +} void CompileItem::visit (HIR::ImplBlock &impl_block) { diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index 59f5d629234b..4a3a6bd1dd4a 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -44,7 +44,7 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Module &module) override; - + void visit (HIR::Enum &) override; // Empty visit for unused Stmt HIR nodes. void visit (HIR::TupleStruct &) override {} void visit (HIR::EnumItem &) override {} @@ -58,7 +58,6 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor void visit (HIR::UseDeclaration &) override {} void visit (HIR::TypeAlias &) override {} void visit (HIR::StructStruct &) override {} - void visit (HIR::Enum &) override {} void visit (HIR::Union &) override {} void visit (HIR::Trait &) override {} void visit (HIR::EmptyStmt &) override {} diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 5be2b9e317e4..1fcb5d14a6de 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -20,10 +20,10 @@ #include "rust-compile-expr.h" #include "rust-constexpr.h" #include "rust-gcc.h" +#include "rust-diagnostics.h" #include "tree.h" #include "stor-layout.h" - namespace Rust { namespace Compile { @@ -248,6 +248,63 @@ TyTyResolveCompile::visit (const TyTy::FnPtr &type) type.get_ident ().locus); } +bool +check_variant_record_collision (Context *ctx, const TyTy::ADTType &type, + std::vector &variant_records) +{ + // bdbt: we're checking if shared discriminants crash with each other or + // not. lets make a map from uhwi to hir id. A clash of uhwi in a variant + // record to which said record can be converted uhwi is indicative of + // issue 3351 of gccrs + + std::map> shwi_to_index; + for (size_t i = 0; i < variant_records.size (); i++) + { + TyTy::VariantDef *variant = type.get_variants ().at (i); + if (variant->has_discriminant ()) + { + tree discriminant_expr + = CompileExpr::Compile (variant->get_discriminant (), ctx); + tree folded_expr = fold_expr (discriminant_expr); + if (folded_expr == error_mark_node) + { + // if we have discriminant but we fail to fold it, return false + return false; + } + HOST_WIDE_INT discriminant_integer = tree_to_shwi (folded_expr); + shwi_to_index[discriminant_integer].push_back (i); + } + } + + bool has_failed = false; + for (const auto &map_item : shwi_to_index) + { + auto discriminant_integer = map_item.first; + const auto &index_vector = map_item.second; + // collision doesn't happen, move to next item + if (index_vector.size () <= 1) + continue; + + has_failed = true; + rich_location r (line_table, type.get_locus ()); + std::string assigned_here_msg + = expand_message (HOST_WIDE_INT_PRINT_DEC " assigned here", + discriminant_integer); + std::string assigned_more_once_msg + = expand_message ("discriminant value " HOST_WIDE_INT_PRINT_DEC + " assigned more than once", + discriminant_integer); + for (auto index : index_vector) + { + TyTy::VariantDef *variant = type.get_variants ().at (index); + r.add_fixit_replace (variant->get_discriminant ().get_locus (), + assigned_here_msg.c_str ()); + } + rust_error_at (r, ErrorCode::E0081, "%s", + assigned_more_once_msg.c_str ()); + } + return !has_failed; +} void TyTyResolveCompile::visit (const TyTy::ADTType &type) { @@ -255,7 +312,6 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) if (!type.is_enum ()) { rust_assert (type.number_of_variants () == 1); - TyTy::VariantDef &variant = *type.get_variants ().at (0); std::vector fields; for (size_t i = 0; i < variant.num_fields (); i++) @@ -358,9 +414,15 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) // add them to the list variant_records.push_back (named_variant_record); } - - // now we need to make the actual union, but first we need to make - // named_type TYPE_DECL's out of the variants + // TODO: bdbt set up defid and a map (or set?) to check if we have + // checked for collision already. + if (!check_variant_record_collision (ctx, type, variant_records)) + { + translated = error_mark_node; + return; + } + // the actual union, but first we need to make named_type TYPE_DECL's out + // of the variants size_t i = 0; std::vector enum_fields; diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc index 0bb891bfe4c8..42ee988e1093 100644 --- a/gcc/rust/rust-diagnostics.cc +++ b/gcc/rust/rust-diagnostics.cc @@ -104,9 +104,6 @@ expand_format (const char *fmt) // calling function must need to have attribute gnu_printf as well, even // though there is already an attribute declaration for it. -static std::string -expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0); - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-attribute=format" @@ -127,6 +124,16 @@ expand_message (const char *fmt, va_list ap) free (mbuf); return rval; } +std::string +expand_message (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + std::string str = expand_message (fmt, ap); + va_end (ap); + return str; +} #pragma GCC diagnostic pop diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index 3da1881bb6ca..edb3545e9fa8 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -80,6 +80,9 @@ enum class ErrorCode : unsigned int #undef ERROR // clang-format off +std::string +expand_message (const char *fmt, ...) RUST_ATTRIBUTE_GCC_DIAG (1, 2); + extern void rust_internal_error_at (const location_t, const char *fmt, ...) RUST_ATTRIBUTE_GCC_DIAG (2, 3)