diff options
| author | Deadbeef <ent3rm4n@gmail.com> | 2021-07-04 12:24:20 +0800 |
|---|---|---|
| committer | Deadbeef <ent3rm4n@gmail.com> | 2021-07-10 20:54:44 +0800 |
| commit | 2db927d8d82260759e4aaa183dbebd0adbb00177 (patch) | |
| tree | 04bbc46ca5e71ad46526c929b471e00aeb431321 | |
| parent | a84d1b21aea9863f0fc5f436b4982d145dade646 (diff) | |
| download | rust-2db927d8d82260759e4aaa183dbebd0adbb00177.tar.gz rust-2db927d8d82260759e4aaa183dbebd0adbb00177.zip | |
Add #[default_method_body_is_const]
| -rw-r--r-- | compiler/rustc_feature/src/builtin_attrs.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_const.rs | 49 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs | 20 | ||||
| -rw-r--r-- | src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr | 29 |
5 files changed, 82 insertions, 22 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 259a6328a22..dbdc14dced8 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -470,6 +470,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), + gated!( + default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl, + "the `#[default_method_body_is_const]` attribute marks a default method of a trait \ + as const, so it does not need to be duplicated by a const impl." + ), // ========================================================================== // Internal attributes, Layout related: diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index d783852aaca..eaeec19eb31 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,6 +8,7 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; +use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -85,34 +86,46 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::Constness::Const = imp.constness { let did = imp.of_trait.as_ref()?.trait_def_id()?; - let trait_fn_cnt = self - .tcx - .associated_item_def_ids(did) - .iter() - .filter(|did| { - matches!( - self.tcx.associated_item(**did), - ty::AssocItem { kind: ty::AssocKind::Fn, .. } - ) - }) - .count(); + let mut to_implement = FxHashSet::default(); + + for did in self.tcx.associated_item_def_ids(did) { + if let ty::AssocItem { + kind: ty::AssocKind::Fn, ident, defaultness, .. + } = self.tcx.associated_item(*did) + { + match ( + self.tcx.has_attr(*did, sym::default_method_body_is_const), + defaultness.has_value(), + ) { + (false, true) => { + to_implement.insert(ident); + } + // ignore functions that do not have default bodies + // if those are unimplemented it will be catched by + // typeck. + _ => {} + } + } + } - let impl_fn_cnt = imp + for it in imp .items .iter() .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. })) - .count(); + { + to_implement.remove(&it.ident); + } - // number of trait functions unequal to functions in impl, - // meaning that one or more provided/default functions of the - // trait are used. - if trait_fn_cnt != impl_fn_cnt { + // all nonconst trait functions (not marked with #[default_method_body_is_const]) + // must be implemented + if !to_implement.is_empty() { self.tcx .sess .struct_span_err( item.span, - "const trait implementations may not use default functions", + "const trait implementations may not use non-const default functions", ) + .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `"))) .emit(); } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9051c9d69b5..f7a11876f7d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -462,6 +462,7 @@ symbols! { decode, default_alloc_error_handler, default_lib_allocator, + default_method_body_is_const, default_type_parameter_fallback, default_type_params, delay_span_bug_from_inside_query, diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs index 4ff4fa0d83b..def7c34b4e5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs @@ -8,13 +8,31 @@ trait Tr { println!("lul"); self.req(); } + + #[default_method_body_is_const] + fn default() {} } struct S; impl const Tr for S { fn req(&self) {} +} //~^^ ERROR const trait implementations may not use non-const default functions + +impl const Tr for u8 { + fn req(&self) {} + fn prov(&self) {} } -//~^^^ ERROR const trait implementations may not use default functions + +impl const Tr for u16 { + fn prov(&self) {} + fn default() {} +} //~^^^ ERROR not all trait items implemented + + +impl const Tr for u32 { + fn req(&self) {} + fn default() {} +} //~^^^ ERROR const trait implementations may not use non-const default functions fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr index 51a7b18fa8d..eb7f899b4de 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr @@ -1,10 +1,33 @@ -error: const trait implementations may not use default functions - --> $DIR/impl-with-default-fn.rs:15:1 +error: const trait implementations may not use non-const default functions + --> $DIR/impl-with-default-fn.rs:18:1 | LL | / impl const Tr for S { LL | | fn req(&self) {} LL | | } | |_^ + | + = note: `prov` not implemented + +error: const trait implementations may not use non-const default functions + --> $DIR/impl-with-default-fn.rs:33:1 + | +LL | / impl const Tr for u32 { +LL | | fn req(&self) {} +LL | | fn default() {} +LL | | } + | |_^ + | + = note: `prov` not implemented + +error[E0046]: not all trait items implemented, missing: `req` + --> $DIR/impl-with-default-fn.rs:27:1 + | +LL | fn req(&self); + | -------------- `req` from trait +... +LL | impl const Tr for u16 { + | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation -error: aborting due to previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0046`. |
