|
10 | 10 | use rustc_attr as attr;
|
11 | 11 | use rustc_errors::struct_span_err;
|
12 | 12 | use rustc_hir as hir;
|
| 13 | +use rustc_hir::def::DefKind; |
13 | 14 | use rustc_hir::def_id::LocalDefId;
|
14 | 15 | use rustc_hir::intravisit::{self, Visitor};
|
15 | 16 | use rustc_middle::hir::nested_filter;
|
@@ -58,88 +59,73 @@ impl NonConstExpr {
|
58 | 59 | fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
59 | 60 | let mut vis = CheckConstVisitor::new(tcx);
|
60 | 61 | tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
|
61 |
| - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx)); |
| 62 | + for id in tcx.hir_module_items(module_def_id).items() { |
| 63 | + check_item(tcx, id); |
| 64 | + } |
62 | 65 | }
|
63 | 66 |
|
64 | 67 | pub(crate) fn provide(providers: &mut Providers) {
|
65 | 68 | *providers = Providers { check_mod_const_bodies, ..*providers };
|
66 | 69 | }
|
67 | 70 |
|
68 |
| -struct CheckConstTraitVisitor<'tcx> { |
69 |
| - tcx: TyCtxt<'tcx>, |
70 |
| -} |
| 71 | +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { |
| 72 | + let _: Option<_> = try { |
| 73 | + if !matches!(tcx.hir().def_kind(id.def_id), DefKind::Impl) { |
| 74 | + None? |
| 75 | + } |
71 | 76 |
|
72 |
| -impl<'tcx> CheckConstTraitVisitor<'tcx> { |
73 |
| - fn new(tcx: TyCtxt<'tcx>) -> Self { |
74 |
| - CheckConstTraitVisitor { tcx } |
75 |
| - } |
76 |
| -} |
| 77 | + let item = tcx.hir().item(id); |
| 78 | + if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness { |
| 79 | + let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; |
| 80 | + let ancestors = tcx |
| 81 | + .trait_def(trait_def_id) |
| 82 | + .ancestors(tcx, item.def_id.to_def_id()) |
| 83 | + .ok()?; |
| 84 | + let mut to_implement = Vec::new(); |
77 | 85 |
|
78 |
| -impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> { |
79 |
| - /// check for const trait impls, and errors if the impl uses provided/default functions |
80 |
| - /// of the trait being implemented; as those provided functions can be non-const. |
81 |
| - fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) { |
82 |
| - let _: Option<_> = try { |
83 |
| - if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness { |
84 |
| - let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; |
85 |
| - let ancestors = self |
86 |
| - .tcx |
87 |
| - .trait_def(trait_def_id) |
88 |
| - .ancestors(self.tcx, item.def_id.to_def_id()) |
89 |
| - .ok()?; |
90 |
| - let mut to_implement = Vec::new(); |
91 |
| - |
92 |
| - for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() |
| 86 | + for trait_item in tcx.associated_items(trait_def_id).in_definition_order() |
| 87 | + { |
| 88 | + if let ty::AssocItem { |
| 89 | + kind: ty::AssocKind::Fn, |
| 90 | + defaultness, |
| 91 | + def_id: trait_item_id, |
| 92 | + .. |
| 93 | + } = *trait_item |
| 94 | + { |
| 95 | + // we can ignore functions that do not have default bodies: |
| 96 | + // if those are unimplemented it will be caught by typeck. |
| 97 | + if !defaultness.has_value() |
| 98 | + || tcx |
| 99 | + .has_attr(trait_item_id, sym::default_method_body_is_const) |
93 | 100 | {
|
94 |
| - if let ty::AssocItem { |
95 |
| - kind: ty::AssocKind::Fn, |
96 |
| - defaultness, |
97 |
| - def_id: trait_item_id, |
98 |
| - .. |
99 |
| - } = *trait_item |
100 |
| - { |
101 |
| - // we can ignore functions that do not have default bodies: |
102 |
| - // if those are unimplemented it will be caught by typeck. |
103 |
| - if !defaultness.has_value() |
104 |
| - || self |
105 |
| - .tcx |
106 |
| - .has_attr(trait_item_id, sym::default_method_body_is_const) |
107 |
| - { |
108 |
| - continue; |
109 |
| - } |
110 |
| - |
111 |
| - let is_implemented = ancestors |
112 |
| - .leaf_def(self.tcx, trait_item_id) |
113 |
| - .map(|node_item| !node_item.defining_node.is_from_trait()) |
114 |
| - .unwrap_or(false); |
115 |
| - |
116 |
| - if !is_implemented { |
117 |
| - to_implement.push(self.tcx.item_name(trait_item_id).to_string()); |
118 |
| - } |
119 |
| - } |
| 101 | + continue; |
120 | 102 | }
|
121 | 103 |
|
122 |
| - // all nonconst trait functions (not marked with #[default_method_body_is_const]) |
123 |
| - // must be implemented |
124 |
| - if !to_implement.is_empty() { |
125 |
| - self.tcx |
126 |
| - .sess |
127 |
| - .struct_span_err( |
128 |
| - item.span, |
129 |
| - "const trait implementations may not use non-const default functions", |
130 |
| - ) |
131 |
| - .note(&format!("`{}` not implemented", to_implement.join("`, `"))) |
132 |
| - .emit(); |
| 104 | + let is_implemented = ancestors |
| 105 | + .leaf_def(tcx, trait_item_id) |
| 106 | + .map(|node_item| !node_item.defining_node.is_from_trait()) |
| 107 | + .unwrap_or(false); |
| 108 | + |
| 109 | + if !is_implemented { |
| 110 | + to_implement.push(tcx.item_name(trait_item_id).to_string()); |
133 | 111 | }
|
| 112 | + } |
134 | 113 | }
|
135 |
| - }; |
136 |
| - } |
137 | 114 |
|
138 |
| - fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {} |
139 |
| - |
140 |
| - fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {} |
141 |
| - |
142 |
| - fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {} |
| 115 | + // all nonconst trait functions (not marked with #[default_method_body_is_const]) |
| 116 | + // must be implemented |
| 117 | + if !to_implement.is_empty() { |
| 118 | + tcx |
| 119 | + .sess |
| 120 | + .struct_span_err( |
| 121 | + item.span, |
| 122 | + "const trait implementations may not use non-const default functions", |
| 123 | + ) |
| 124 | + .note(&format!("`{}` not implemented", to_implement.join("`, `"))) |
| 125 | + .emit(); |
| 126 | + } |
| 127 | + } |
| 128 | + }; |
143 | 129 | }
|
144 | 130 |
|
145 | 131 | #[derive(Copy, Clone)]
|
|
0 commit comments