|
8 | 8 | //! through, but errors for structured control flow in a `const` should be emitted here.
|
9 | 9 |
|
10 | 10 | use rustc_attr as attr;
|
| 11 | +use rustc_data_structures::stable_set::FxHashSet; |
11 | 12 | use rustc_errors::struct_span_err;
|
12 | 13 | use rustc_hir as hir;
|
13 | 14 | use rustc_hir::def_id::LocalDefId;
|
@@ -85,34 +86,41 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
85 | 86 | if let hir::ItemKind::Impl(ref imp) = item.kind {
|
86 | 87 | if let hir::Constness::Const = imp.constness {
|
87 | 88 | let did = imp.of_trait.as_ref()?.trait_def_id()?;
|
88 |
| - let trait_fn_cnt = self |
89 |
| - .tcx |
90 |
| - .associated_item_def_ids(did) |
91 |
| - .iter() |
92 |
| - .filter(|did| { |
93 |
| - matches!( |
94 |
| - self.tcx.associated_item(**did), |
95 |
| - ty::AssocItem { kind: ty::AssocKind::Fn, .. } |
96 |
| - ) |
97 |
| - }) |
98 |
| - .count(); |
| 89 | + let mut to_implement = FxHashSet::default(); |
| 90 | + |
| 91 | + for did in self.tcx.associated_item_def_ids(did) { |
| 92 | + if let ty::AssocItem { |
| 93 | + kind: ty::AssocKind::Fn, ident, defaultness, .. |
| 94 | + } = self.tcx.associated_item(*did) |
| 95 | + { |
| 96 | + // we can ignore functions that do not have default bodies: |
| 97 | + // if those are unimplemented it will be catched by typeck. |
| 98 | + if defaultness.has_value() |
| 99 | + && !self.tcx.has_attr(*did, sym::default_method_body_is_const) |
| 100 | + { |
| 101 | + to_implement.insert(ident); |
| 102 | + } |
| 103 | + } |
| 104 | + } |
99 | 105 |
|
100 |
| - let impl_fn_cnt = imp |
| 106 | + for it in imp |
101 | 107 | .items
|
102 | 108 | .iter()
|
103 | 109 | .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
104 |
| - .count(); |
| 110 | + { |
| 111 | + to_implement.remove(&it.ident); |
| 112 | + } |
105 | 113 |
|
106 |
| - // number of trait functions unequal to functions in impl, |
107 |
| - // meaning that one or more provided/default functions of the |
108 |
| - // trait are used. |
109 |
| - if trait_fn_cnt != impl_fn_cnt { |
| 114 | + // all nonconst trait functions (not marked with #[default_method_body_is_const]) |
| 115 | + // must be implemented |
| 116 | + if !to_implement.is_empty() { |
110 | 117 | self.tcx
|
111 | 118 | .sess
|
112 | 119 | .struct_span_err(
|
113 | 120 | item.span,
|
114 |
| - "const trait implementations may not use default functions", |
| 121 | + "const trait implementations may not use non-const default functions", |
115 | 122 | )
|
| 123 | + .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `"))) |
116 | 124 | .emit();
|
117 | 125 | }
|
118 | 126 | }
|
|
0 commit comments