about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2021-07-04 12:24:20 +0800
committerDeadbeef <ent3rm4n@gmail.com>2021-07-10 20:54:44 +0800
commit2db927d8d82260759e4aaa183dbebd0adbb00177 (patch)
tree04bbc46ca5e71ad46526c929b471e00aeb431321 /compiler
parenta84d1b21aea9863f0fc5f436b4982d145dade646 (diff)
downloadrust-2db927d8d82260759e4aaa183dbebd0adbb00177.tar.gz
rust-2db927d8d82260759e4aaa183dbebd0adbb00177.zip
Add #[default_method_body_is_const]
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_passes/src/check_const.rs49
-rw-r--r--compiler/rustc_span/src/symbol.rs1
3 files changed, 37 insertions, 18 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,