// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H #define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H #include "rust-hir-type-check-base.h" #include "rust-hir-full.h" namespace Rust { namespace Resolver { class ImplItemToName : private TypeCheckBase, private HIR::HIRImplVisitor { public: static bool resolve (HIR::ImplItem *item, std::string &name_result) { ImplItemToName resolver (name_result); item->accept_vis (resolver); return resolver.ok; } void visit (HIR::TypeAlias &alias) override { ok = true; result.assign (alias.get_new_type_name ()); } void visit (HIR::Function &function) override { ok = true; result.assign (function.get_function_name ()); } void visit (HIR::ConstantItem &constant) override { ok = true; result.assign (constant.get_identifier ()); } private: ImplItemToName (std::string &result) : TypeCheckBase (), ok (false), result (result) {} bool ok; std::string &result; }; class OverlappingImplItemPass : public TypeCheckBase { public: static void go () { OverlappingImplItemPass pass; // generate mappings pass.mappings->iterate_impl_items ( [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool { // ignoring trait-impls might need thought later on if (impl->has_trait_ref ()) return true; pass.process_impl_item (id, impl_item, impl); return true; }); pass.scan (); } void process_impl_item (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) { // lets make a mapping of impl-item Self type to (impl-item,name): // { // impl-type -> [ (item, name), ... ] // } HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid (); TyTy::BaseType *impl_type = nullptr; bool ok = query_type (impl_type_id, &impl_type); if (!ok) return; std::string impl_item_name; ok = ImplItemToName::resolve (impl_item, impl_item_name); rust_assert (ok); std::pair elem (impl_item, impl_item_name); impl_mappings[impl_type].insert (std::move (elem)); } void scan () { // we can now brute force the map looking for can_eq on each of the // impl_items_types to look for possible colliding impl blocks; for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++) { TyTy::BaseType *query = it->first; for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++) { TyTy::BaseType *candidate = iy->first; if (query == candidate) continue; if (query->can_eq (candidate, false)) { // we might be in the case that we have: // // *const T vs *const [T] // // so lets use an equality check when the // candidates are both generic to be sure we dont emit a false // positive bool a = query->is_concrete (); bool b = candidate->is_concrete (); bool both_generic = !a && !b; if (both_generic) { if (!query->is_equal (*candidate)) continue; } possible_collision (it->second, iy->second); } } } } void possible_collision ( std::set > query, std::set > candidate) { for (auto &q : query) { HIR::ImplItem *query_impl_item = q.first; std::string query_impl_item_name = q.second; for (auto &c : candidate) { HIR::ImplItem *candidate_impl_item = c.first; std::string candidate_impl_item_name = c.second; if (query_impl_item_name.compare (candidate_impl_item_name) == 0) collision_detected (query_impl_item, candidate_impl_item, candidate_impl_item_name); } } } void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup, const std::string &name) { RichLocation r (dup->get_locus ()); r.add_range (query->get_locus ()); rust_error_at (r, "duplicate definitions with name %s", name.c_str ()); } private: OverlappingImplItemPass () : TypeCheckBase () {} std::map > > impl_mappings; }; } // namespace Resolver } // namespace Rust #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H