about summary refs log tree commit diff
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
parenta84d1b21aea9863f0fc5f436b4982d145dade646 (diff)
downloadrust-2db927d8d82260759e4aaa183dbebd0adbb00177.tar.gz
rust-2db927d8d82260759e4aaa183dbebd0adbb00177.zip
Add #[default_method_body_is_const]
-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
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs20
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr29
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`.