about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2022-09-20 11:55:07 +0000
committerDeadbeef <ent3rm4n@gmail.com>2022-09-20 11:57:58 +0000
commita052f2cce1df8ac5ac9fcd104c948545f8b5f2f4 (patch)
tree291a1724a5276b99ec3eeee18d7231724757f6ea
parent4af79ccd5e23c7cbaabcd7aefdda3b715abde606 (diff)
downloadrust-a052f2cce1df8ac5ac9fcd104c948545f8b5f2f4.tar.gz
rust-a052f2cce1df8ac5ac9fcd104c948545f8b5f2f4.zip
Add the `#[derive_const]` attribute
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs35
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs3
-rw-r--r--compiler/rustc_expand/src/base.rs4
-rw-r--r--compiler/rustc_expand/src/expand.rs13
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs1
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/macros/mod.rs13
-rw-r--r--library/core/src/prelude/v1.rs4
-rw-r--r--library/std/src/prelude/v1.rs4
-rw-r--r--src/test/ui/issues/issue-32655.stderr14
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr11
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs13
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr14
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs19
30 files changed, 163 insertions, 30 deletions
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index cb5359dd1e2..86df3c44eb3 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -34,6 +34,7 @@ impl MultiItemModifier for Expander {
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let template = AttributeTemplate { list: Some("path"), ..Default::default() };
         let attr = &ecx.attribute(meta_item.clone());
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index e0fb7affb34..01f237e6ab5 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -10,7 +10,7 @@ use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
-pub(crate) struct Expander;
+pub(crate) struct Expander(pub bool);
 
 impl MultiItemModifier for Expander {
     fn expand(
@@ -19,6 +19,7 @@ impl MultiItemModifier for Expander {
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let sess = ecx.sess;
         if report_bad_target(sess, &item, span) {
@@ -58,20 +59,20 @@ impl MultiItemModifier for Expander {
                         report_path_args(sess, &meta);
                         meta.path
                     })
-                    .map(|path| (path, dummy_annotatable(), None))
+                    .map(|path| (path, dummy_annotatable(), None, self.0))
                     .collect();
 
                 // Do not configure or clone items unless necessary.
                 match &mut resolutions[..] {
                     [] => {}
-                    [(_, first_item, _), others @ ..] => {
+                    [(_, first_item, ..), others @ ..] => {
                         *first_item = cfg_eval(
                             sess,
                             features,
                             item.clone(),
                             ecx.current_expansion.lint_node_id,
                         );
-                        for (_, item, _) in others {
+                        for (_, item, _, _) in others {
                             *item = first_item.clone();
                         }
                     }
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 77e0b6c55a8..3a5b7ecde8a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -12,6 +12,7 @@ pub fn expand_deriving_copy(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let trait_def = TraitDef {
         span,
@@ -21,6 +22,7 @@ pub fn expand_deriving_copy(
         supports_unions: true,
         methods: Vec::new(),
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push);
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index c7f2d95e72f..6d9be879cd1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -14,6 +14,7 @@ pub fn expand_deriving_clone(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     // The simple form is `fn clone(&self) -> Self { *self }`, possibly with
     // some additional `AssertParamIsClone` assertions.
@@ -86,6 +87,7 @@ pub fn expand_deriving_clone(
             combine_substructure: substructure,
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand_ext(cx, mitem, item, push, is_simple)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 5b556c5c9b9..9c01314112a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -15,6 +15,7 @@ pub fn expand_deriving_eq(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let span = cx.with_def_site_ctxt(span);
     let inline = cx.meta_word(span, sym::inline);
@@ -41,6 +42,7 @@ pub fn expand_deriving_eq(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 72625869558..d5c81c38783 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -13,6 +13,7 @@ pub fn expand_deriving_ord(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let inline = cx.meta_word(span, sym::inline);
     let attrs = thin_vec![cx.attribute(inline)];
@@ -33,6 +34,7 @@ pub fn expand_deriving_ord(
             combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 42ee65b570a..11b838a076c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -14,6 +14,7 @@ pub fn expand_deriving_partial_eq(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         let base = true;
@@ -88,6 +89,7 @@ pub fn expand_deriving_partial_eq(
         supports_unions: false,
         methods,
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 516892aeda9..107a01190bb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -13,6 +13,7 @@ pub fn expand_deriving_partial_ord(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let ordering_ty = Path(path_std!(cmp::Ordering));
     let ret_ty =
@@ -42,6 +43,7 @@ pub fn expand_deriving_partial_ord(
         supports_unions: false,
         methods: vec![partial_cmp_def],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 4af7fd81653..cf977c0824d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -13,6 +13,7 @@ pub fn expand_deriving_debug(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     // &mut ::std::fmt::Formatter
     let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
@@ -36,6 +37,7 @@ pub fn expand_deriving_debug(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 7174dbbe7ea..a27a068f31a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -16,6 +16,7 @@ pub fn expand_deriving_rustc_decodable(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let krate = sym::rustc_serialize;
     let typaram = sym::__D;
@@ -54,6 +55,7 @@ pub fn expand_deriving_rustc_decodable(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index a94c8a996e6..35b23f2f8f3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -16,6 +16,7 @@ pub fn expand_deriving_default(
     mitem: &ast::MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
 
@@ -46,6 +47,7 @@ pub fn expand_deriving_default(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
     trait_def.expand(cx, mitem, item, push)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index b220e54238f..f06cf0c56bc 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -100,6 +100,7 @@ pub fn expand_deriving_rustc_encodable(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let krate = sym::rustc_serialize;
     let typaram = sym::__S;
@@ -138,6 +139,7 @@ pub fn expand_deriving_rustc_encodable(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     trait_def.expand(cx, mitem, item, push)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3cc160adb53..78dbe8e5979 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -171,7 +171,7 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData};
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use std::cell::RefCell;
 use std::iter;
 use std::vec;
@@ -200,6 +200,8 @@ pub struct TraitDef<'a> {
     pub methods: Vec<MethodDef<'a>>,
 
     pub associated_types: Vec<(Ident, Ty)>,
+
+    pub is_const: bool,
 }
 
 pub struct MethodDef<'a> {
@@ -726,7 +728,7 @@ impl<'a> TraitDef<'a> {
                 unsafety: ast::Unsafe::No,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
-                constness: ast::Const::No,
+                constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
                 generics: trait_generics,
                 of_trait: opt_trait_ref,
                 self_ty: self_type,
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index f1f02e7ce77..ef3da94f9e3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -13,6 +13,7 @@ pub fn expand_deriving_hash(
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
+    is_const: bool,
 ) {
     let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std);
 
@@ -38,6 +39,7 @@ pub fn expand_deriving_hash(
             })),
         }],
         associated_types: Vec::new(),
+        is_const,
     };
 
     hash_trait_def.expand(cx, mitem, item, push);
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a65d0bad6de..5b89da91d42 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -38,9 +38,10 @@ pub mod partial_ord;
 
 pub mod generic;
 
-pub(crate) struct BuiltinDerive(
-    pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
-);
+pub(crate) type BuiltinDeriveFn =
+    fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
+
+pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
 
 impl MultiItemModifier for BuiltinDerive {
     fn expand(
@@ -49,6 +50,7 @@ impl MultiItemModifier for BuiltinDerive {
         span: Span,
         meta_item: &MetaItem,
         item: Annotatable,
+        is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         // FIXME: Built-in derives often forget to give spans contexts,
         // so we are doing it here in a centralized way.
@@ -57,21 +59,28 @@ impl MultiItemModifier for BuiltinDerive {
         match item {
             Annotatable::Stmt(stmt) => {
                 if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
-                    (self.0)(ecx, span, meta_item, &Annotatable::Item(item), &mut |a| {
-                        // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
-                        // to the function
-                        items.push(Annotatable::Stmt(P(ast::Stmt {
-                            id: ast::DUMMY_NODE_ID,
-                            kind: ast::StmtKind::Item(a.expect_item()),
-                            span,
-                        })));
-                    });
+                    (self.0)(
+                        ecx,
+                        span,
+                        meta_item,
+                        &Annotatable::Item(item),
+                        &mut |a| {
+                            // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
+                            // to the function
+                            items.push(Annotatable::Stmt(P(ast::Stmt {
+                                id: ast::DUMMY_NODE_ID,
+                                kind: ast::StmtKind::Item(a.expect_item()),
+                                span,
+                            })));
+                        },
+                        is_derive_const,
+                    );
                 } else {
                     unreachable!("should have already errored on non-item statement")
                 }
             }
             _ => {
-                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
+                (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
             }
         }
         ExpandResult::Ready(items)
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 8aeb3b82a9c..ab1fcde1686 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -97,7 +97,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
-        derive: derive::Expander,
+        derive: derive::Expander(false),
+        derive_const: derive::Expander(true),
         global_allocator: global_allocator::expand,
         test: test::expand_test,
         test_case: test::expand_test_case,
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index e1da3ecdec7..b3d187848be 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -248,6 +248,7 @@ pub trait MultiItemModifier {
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable>;
 }
 
@@ -261,6 +262,7 @@ where
         span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         ExpandResult::Ready(self(ecx, span, meta_item, item))
     }
@@ -871,7 +873,7 @@ impl SyntaxExtension {
 /// Error type that denotes indeterminacy.
 pub struct Indeterminate;
 
-pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>)>;
+pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>, bool)>;
 
 pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c2add852a06..a63b59d31cf 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -319,6 +319,7 @@ pub enum InvocationKind {
     },
     Derive {
         path: ast::Path,
+        is_const: bool,
         item: Annotatable,
     },
 }
@@ -460,13 +461,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             derive_invocations.reserve(derives.len());
                             derives
                                 .into_iter()
-                                .map(|(path, item, _exts)| {
+                                .map(|(path, item, _exts, is_const)| {
                                     // FIXME: Consider using the derive resolutions (`_exts`)
                                     // instead of enqueuing the derives to be resolved again later.
                                     let expn_id = LocalExpnId::fresh_empty();
                                     derive_invocations.push((
                                         Invocation {
-                                            kind: InvocationKind::Derive { path, item },
+                                            kind: InvocationKind::Derive { path, item, is_const },
                                             fragment_kind,
                                             expansion_data: ExpansionData {
                                                 id: expn_id,
@@ -699,7 +700,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 SyntaxExtensionKind::LegacyAttr(expander) => {
                     match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) {
                         Ok(meta) => {
-                            let items = match expander.expand(self.cx, span, &meta, item) {
+                            let items = match expander.expand(self.cx, span, &meta, item, false) {
                                 ExpandResult::Ready(items) => items,
                                 ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
@@ -731,19 +732,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::Derive { path, item } => match ext {
+            InvocationKind::Derive { path, item, is_const } => match ext {
                 SyntaxExtensionKind::Derive(expander)
                 | SyntaxExtensionKind::LegacyDerive(expander) => {
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
                     let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
-                    let items = match expander.expand(self.cx, span, &meta, item) {
+                    let items = match expander.expand(self.cx, span, &meta, item, is_const) {
                         ExpandResult::Ready(items) => items,
                         ExpandResult::Retry(item) => {
                             // Reassemble the original invocation for retrying.
                             return ExpandResult::Retry(Invocation {
-                                kind: InvocationKind::Derive { path: meta.path, item },
+                                kind: InvocationKind::Derive { path: meta.path, item, is_const },
                                 ..invoc
                             });
                         }
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 1a2ab9d190e..e9a69192068 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -112,6 +112,7 @@ impl MultiItemModifier for DeriveProcMacro {
         span: Span,
         _meta_item: &ast::MetaItem,
         item: Annotatable,
+        _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         // We need special handling for statement items
         // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index dafa10e9e00..8ef99e5ef96 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -356,7 +356,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
             has_derive_copy: false,
         });
         let parent_scope = self.invocation_parent_scopes[&expn_id];
-        for (i, (path, _, opt_ext)) in entry.resolutions.iter_mut().enumerate() {
+        for (i, (path, _, opt_ext, _)) in entry.resolutions.iter_mut().enumerate() {
             if opt_ext.is_none() {
                 *opt_ext = Some(
                     match self.resolve_macro_path(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 562360130e9..0a9570979d5 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -614,6 +614,7 @@ symbols! {
         deref_mut,
         deref_target,
         derive,
+        derive_const,
         derive_default_enum,
         destruct,
         destructuring_assignment,
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index fd96e1ff77d..e504db81434 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1464,6 +1464,19 @@ pub(crate) mod builtin {
         /* compiler built-in */
     }
 
+    /// Attribute macro used to apply derive macros for implementing traits
+    /// in a const context.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/derive.html
+    #[unstable(feature = "derive_const", issue = "none")]
+    #[rustc_builtin_macro]
+    #[cfg(not(bootstrap))]
+    pub macro derive_const($item:item) {
+        /* compiler built-in */
+    }
+
     /// Attribute macro applied to a function to turn it into a unit test.
     ///
     /// See [the reference] for more info.
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index b566e211cd8..f52c06d7ead 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -78,6 +78,10 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
 
+#[unstable(feature = "derive_const", issue = "none")]
+#[cfg(not(bootstrap))]
+pub use crate::macros::builtin::derive_const;
+
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 0226c4d7a25..93f4a17bbfc 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -62,6 +62,10 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
 
+#[unstable(feature = "derive_const", issue = "none")]
+#[cfg(not(bootstrap))]
+pub use core::prelude::v1::derive_const;
+
 // Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_accessible",
diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr
index 2d9ce430a46..5a758c7002b 100644
--- a/src/test/ui/issues/issue-32655.stderr
+++ b/src/test/ui/issues/issue-32655.stderr
@@ -2,18 +2,28 @@ error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:3:11
    |
 LL |         #[derive_Clone]
-   |           ^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const`
 ...
 LL | foo!();
    | ------ in this macro invocation
    |
+  ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+LL |     pub macro derive_const($item:item) {
+   |     ---------------------- similarly named attribute macro `derive_const` defined here
+   |
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot find attribute `derive_Clone` in this scope
   --> $DIR/issue-32655.rs:15:7
    |
 LL |     #[derive_Clone]
-   |       ^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `derive_const`
+   |
+  ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+LL |     pub macro derive_const($item:item) {
+   |     ---------------------- similarly named attribute macro `derive_const` defined here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs
new file mode 100644
index 00000000000..348ca0ab190
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.rs
@@ -0,0 +1,4 @@
+#[derive_const(Default)] //~ ERROR use of unstable library feature
+pub struct S;
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr
new file mode 100644
index 00000000000..cc9bdd2715f
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-gate.stderr
@@ -0,0 +1,11 @@
+error[E0658]: use of unstable library feature 'derive_const'
+  --> $DIR/derive-const-gate.rs:1:3
+   |
+LL | #[derive_const(Default)]
+   |   ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(derive_const)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs
new file mode 100644
index 00000000000..92843a8a2da
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.rs
@@ -0,0 +1,13 @@
+#![feature(derive_const)]
+
+pub struct A;
+
+impl Default for A {
+    fn default() -> A { A }
+}
+
+#[derive_const(Default)]
+pub struct S(A);
+//~^ cannot call non-const fn
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
new file mode 100644
index 00000000000..d463c774e28
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr
@@ -0,0 +1,14 @@
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-non-const-type.rs:10:14
+   |
+LL | #[derive_const(Default)]
+   |                ------- in this derive macro expansion
+LL | pub struct S(A);
+   |              ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs
new file mode 100644
index 00000000000..d1fbeac8598
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const_derives/derive-const-use.rs
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)]
+
+pub struct A;
+
+impl const Default for A {
+    fn default() -> A { A }
+}
+
+impl const PartialEq for A {
+    fn eq(&self, _: &A) -> bool { true }
+}
+
+#[derive_const(Default, PartialEq)]
+pub struct S((), A);
+
+const _: () = assert!(S((), A) == S::default());
+
+fn main() {}