Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #ifndef RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
20 : #define RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
21 :
22 : #include "rust-hir-type-check-base.h"
23 : #include "rust-type-util.h"
24 :
25 : namespace Rust {
26 : namespace Resolver {
27 :
28 8260 : class OverlappingImplItemPass : public TypeCheckBase
29 : {
30 : public:
31 4130 : static void go ()
32 : {
33 8260 : OverlappingImplItemPass pass;
34 :
35 : // generate mappings
36 4130 : pass.mappings.iterate_impl_items (
37 4130 : [&] (HirId id, HIR::ImplItem *impl_item, HIR::ImplBlock *impl) -> bool {
38 : // ignoring trait-impls might need thought later on
39 8036 : if (impl->has_trait_ref ())
40 : return true;
41 :
42 2716 : pass.process_impl_item (id, impl_item, impl);
43 2716 : return true;
44 : });
45 :
46 4130 : pass.scan ();
47 4130 : }
48 :
49 2716 : void process_impl_item (HirId id, HIR::ImplItem *impl_item,
50 : HIR::ImplBlock *impl)
51 : {
52 : // lets make a mapping of impl-item Self type to (impl-item,name):
53 : // {
54 : // impl-type -> [ (item, name), ... ]
55 : // }
56 :
57 2716 : HirId impl_type_id = impl->get_type ().get_mappings ().get_hirid ();
58 2716 : TyTy::BaseType *impl_type = nullptr;
59 2716 : bool ok = query_type (impl_type_id, &impl_type);
60 2716 : if (!ok)
61 0 : return;
62 :
63 2716 : std::string impl_item_name = impl_item->get_impl_item_name ();
64 2716 : std::pair<HIR::ImplItem *, std::string> elem (impl_item, impl_item_name);
65 2716 : impl_mappings[impl_type].insert (std::move (elem));
66 2716 : }
67 :
68 4130 : void scan ()
69 : {
70 : // we can now brute force the map looking for can_eq on each of the
71 : // impl_items_types to look for possible colliding impl blocks;
72 5054 : for (auto it = impl_mappings.begin (); it != impl_mappings.end (); it++)
73 : {
74 924 : TyTy::BaseType *query = it->first;
75 :
76 4194 : for (auto iy = impl_mappings.begin (); iy != impl_mappings.end (); iy++)
77 : {
78 3270 : TyTy::BaseType *candidate = iy->first;
79 924 : if (query == candidate)
80 924 : continue;
81 :
82 2346 : if (!types_compatable (TyTy::TyWithLocation (query),
83 2346 : TyTy::TyWithLocation (candidate),
84 : UNKNOWN_LOCATION, false))
85 2302 : continue;
86 :
87 : // we might be in the case that we have:
88 : //
89 : // *const T vs *const [T]
90 : //
91 : // so lets use an equality check when the
92 : // candidates are both generic to be sure we dont emit a false
93 : // positive
94 :
95 44 : bool a = query->is_concrete ();
96 44 : bool b = candidate->is_concrete ();
97 44 : bool both_generic = !a && !b;
98 44 : if (both_generic)
99 : {
100 28 : if (!query->is_equal (*candidate))
101 28 : continue;
102 : }
103 :
104 16 : possible_collision (it->second, iy->second);
105 : }
106 : }
107 4130 : }
108 :
109 16 : void possible_collision (
110 : std::set<std::pair<HIR::ImplItem *, std::string> > query,
111 : std::set<std::pair<HIR::ImplItem *, std::string> > candidate)
112 : {
113 32 : for (auto &q : query)
114 : {
115 16 : HIR::ImplItem *query_impl_item = q.first;
116 16 : std::string query_impl_item_name = q.second;
117 :
118 32 : for (auto &c : candidate)
119 : {
120 16 : HIR::ImplItem *candidate_impl_item = c.first;
121 16 : std::string candidate_impl_item_name = c.second;
122 :
123 16 : if (query_impl_item_name.compare (candidate_impl_item_name) == 0)
124 2 : collision_detected (query_impl_item, candidate_impl_item,
125 : candidate_impl_item_name);
126 16 : }
127 16 : }
128 16 : }
129 :
130 2 : void collision_detected (HIR::ImplItem *query, HIR::ImplItem *dup,
131 : const std::string &name)
132 : {
133 2 : rich_location r (line_table, dup->get_locus ());
134 2 : std::string msg = "duplicate definitions for " + name;
135 2 : r.add_fixit_replace (query->get_locus (), msg.c_str ());
136 2 : r.add_range (query->get_locus ());
137 2 : rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
138 : name.c_str ());
139 2 : }
140 :
141 : private:
142 4130 : OverlappingImplItemPass () : TypeCheckBase () {}
143 :
144 : std::map<TyTy::BaseType *,
145 : std::set<std::pair<HIR::ImplItem *, std::string> > >
146 : impl_mappings;
147 : };
148 :
149 : } // namespace Resolver
150 : } // namespace Rust
151 :
152 : #endif // RUST_HIR_INHERENT_IMPL_ITEM_OVERLAP_H
|