about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/visit.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs5
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs6
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs3
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs7
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs18
-rw-r--r--compiler/rustc_parse/src/parser/path.rs29
-rw-r--r--compiler/rustc_passes/src/stability.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs3
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs5
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs8
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.rs2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.stderr8
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_trait_param.rs2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_trait_param.stderr8
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr21
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/ast_utils.rs7
37 files changed, 160 insertions, 53 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index cf31e566c38..8167bde0322 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -368,6 +368,8 @@ pub enum GenericParamKind {
         ty: P<Ty>,
         /// Span of the `const` keyword.
         kw_span: Span,
+        /// Optional default value for the const generic param
+        default: Option<AnonConst>,
     },
 }
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 3889ede7f4c..97966cc3260 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -790,8 +790,9 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
         GenericParamKind::Type { default } => {
             visit_opt(default, |default| vis.visit_ty(default));
         }
-        GenericParamKind::Const { ty, kw_span: _ } => {
+        GenericParamKind::Const { ty, kw_span: _, default } => {
             vis.visit_ty(ty);
+            visit_opt(default, |default| vis.visit_anon_const(default));
         }
     }
     smallvec![param]
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index a420bb56350..a696626f8c4 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -578,7 +578,12 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Generi
     match param.kind {
         GenericParamKind::Lifetime => (),
         GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
-        GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
+        GenericParamKind::Const { ref ty, ref default, .. } => {
+            visitor.visit_ty(ty);
+            if let Some(default) = default {
+                visitor.visit_anon_const(default);
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d17b29089d6..f81dc39842c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2242,13 +2242,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 (hir::ParamName::Plain(param.ident), kind)
             }
-            GenericParamKind::Const { ref ty, kw_span: _ } => {
+            GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
                 let ty = self
                     .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
                         this.lower_ty(&ty, ImplTraitContext::disallowed())
                     });
+                let default = default.as_ref().map(|def| self.lower_anon_const(def));
 
-                (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty })
+                (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty, default })
             }
         };
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index c40f00bc9e9..e172f9d71ff 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -733,7 +733,7 @@ fn validate_generic_param_order(
         let (ord_kind, ident) = match &param.kind {
             GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
             GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
-            GenericParamKind::Const { ref ty, kw_span: _ } => {
+            GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
                 let ty = pprust::ty_to_string(ty);
                 let unordered = sess.features_untracked().const_generics;
                 (ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
@@ -774,8 +774,8 @@ fn validate_generic_param_order(
                 }
                 GenericParamKind::Type { default: None } => (),
                 GenericParamKind::Lifetime => (),
-                // FIXME(const_generics:defaults)
-                GenericParamKind::Const { ty: _, kw_span: _ } => (),
+                // FIXME(const_generics_defaults)
+                GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
             }
             first = false;
         }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 6a9d6d2ed12..435f32535b6 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -619,6 +619,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
         extended_key_value_attributes,
         "arbitrary expressions in key-value attributes are unstable"
     );
+    gate_all!(
+        const_generics_defaults,
+        "default values for const generic parameters are experimental"
+    );
     if sess.parse_sess.span_diagnostic.err_count() == 0 {
         // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
         // involved, so we only emit errors where there are no other parsing errors.
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 333a396a0b4..bdd378b34e1 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -2668,13 +2668,17 @@ impl<'a> State<'a> {
                         s.print_type(default)
                     }
                 }
-                ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
+                ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
                     s.word_space("const");
                     s.print_ident(param.ident);
                     s.s.space();
                     s.word_space(":");
                     s.print_type(ty);
-                    s.print_type_bounds(":", &param.bounds)
+                    s.print_type_bounds(":", &param.bounds);
+                    if let Some(ref _default) = default {
+                        // FIXME(const_generics_defaults): print the `default` value here
+                        todo!();
+                    }
                 }
             }
         });
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 1651180817b..3c8bf12b3d4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -145,7 +145,8 @@ fn inject_impl_of_structural_trait(
                 *default = None;
                 ast::GenericArg::Type(cx.ty_ident(span, param.ident))
             }
-            ast::GenericParamKind::Const { ty: _, kw_span: _ } => {
+            ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
+                *default = None;
                 ast::GenericArg::Const(cx.const_ident(span, param.ident))
             }
         })
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index c61857a1cd0..252e96b47c6 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -581,7 +581,7 @@ declare_features! (
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
 
-    /// Allows non-trivial generic constants which have to be manually propageted upwards.
+    /// Allows non-trivial generic constants which have to be manually propagated upwards.
     (active, const_evaluatable_checked, "1.48.0", Some(76560), None),
 
     /// Allows basic arithmetic on floating point types in a `const fn`.
@@ -623,6 +623,9 @@ declare_features! (
     /// `:pat2018` and `:pat2021` macro matchers.
     (active, edition_macro_pats, "1.51.0", Some(54883), None),
 
+    /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
+    (active, const_generics_defaults, "1.51.0", Some(44580), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -647,6 +650,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::repr128,
     sym::unsized_locals,
     sym::capture_disjoint_fields,
+    sym::const_generics_defaults,
 ];
 
 /// Some features are not allowed to be used together at the same time, if
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 47a7651e1d4..ebeb1bae2a3 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -418,6 +418,8 @@ pub enum GenericParamKind<'hir> {
     },
     Const {
         ty: &'hir Ty<'hir>,
+        /// Optional default value for the const generic param
+        default: Option<AnonConst>,
     },
 }
 
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 03c8b173885..87a2434152f 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -877,7 +877,12 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
         GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
-        GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
+        GenericParamKind::Const { ref ty, ref default } => {
+            visitor.visit_ty(ty);
+            if let Some(ref default) = default {
+                visitor.visit_anon_const(default);
+            }
+        }
     }
     walk_list!(visitor, visit_param_bound, param.bounds);
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 0b5eb1d8266..85bc38daa3d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2205,9 +2205,13 @@ impl<'a> State<'a> {
                     self.print_type(&default)
                 }
             }
-            GenericParamKind::Const { ref ty } => {
+            GenericParamKind::Const { ref ty, ref default } => {
                 self.word_space(":");
-                self.print_type(ty)
+                self.print_type(ty);
+                if let Some(ref _default) = default {
+                    // FIXME(const_generics_defaults): print the `default` value here
+                    todo!();
+                }
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 777107ed863..14a56119f21 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -958,7 +958,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 ty::GenericParamDefKind::Type { has_default, .. } => {
                     Some((param.def_id, has_default))
                 }
-                ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
+                ty::GenericParamDefKind::Const => None, // FIXME(const_generics_defaults)
             })
             .peekable();
         let has_default = {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 4dfe3e84877..ac6ceafaba8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1834,7 +1834,7 @@ impl EncodeContext<'a, 'tcx> {
                         EntryKind::ConstParam,
                         true,
                     );
-                    // FIXME(const_generics:defaults)
+                    // FIXME(const_generics_defaults)
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index c79e06b7fdd..77f16688937 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -203,7 +203,7 @@ pub trait Printer<'tcx>: Sized {
                                     self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
                                 )
                     }
-                    ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
+                    ty::GenericParamDefKind::Const => false, // FIXME(const_generics_defaults)
                 }
             })
             .count();
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 860e63020bb..42a13376863 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -5,7 +5,7 @@ use rustc_ast::{
     self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
 };
 use rustc_errors::PResult;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, sym};
 
 impl<'a> Parser<'a> {
     /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -56,12 +56,26 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
+        // Parse optional const generics default value, taking care of feature gating the spans
+        // with the unstable syntax mechanism.
+        let default = if self.eat(&token::Eq) {
+            // The gated span goes from the `=` to the end of the const argument that follows (and
+            // which could be a block expression).
+            let start = self.prev_token.span;
+            let const_arg = self.parse_const_arg()?;
+            let span = start.to(const_arg.value.span);
+            self.sess.gated_spans.gate(sym::const_generics_defaults, span);
+            Some(const_arg)
+        } else {
+            None
+        };
+
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
             attrs: preceding_attrs.into(),
             bounds: Vec::new(),
-            kind: GenericParamKind::Const { ty, kw_span: const_span },
+            kind: GenericParamKind::Const { ty, kw_span: const_span, default },
             is_placeholder: false,
         })
     }
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 60a47ca12b8..43dee391c17 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -515,6 +515,23 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by
+    /// the caller.
+    pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
+        // Parse const argument.
+        let value = if let token::OpenDelim(token::Brace) = self.token.kind {
+            self.parse_block_expr(
+                None,
+                self.token.span,
+                BlockCheckMode::Default,
+                ast::AttrVec::new(),
+            )?
+        } else {
+            self.handle_unambiguous_unbraced_const_arg()?
+        };
+        Ok(AnonConst { id: ast::DUMMY_NODE_ID, value })
+    }
+
     /// Parse a generic argument in a path segment.
     /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
     fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
@@ -524,17 +541,7 @@ impl<'a> Parser<'a> {
             GenericArg::Lifetime(self.expect_lifetime())
         } else if self.check_const_arg() {
             // Parse const argument.
-            let value = if let token::OpenDelim(token::Brace) = self.token.kind {
-                self.parse_block_expr(
-                    None,
-                    self.token.span,
-                    BlockCheckMode::Default,
-                    ast::AttrVec::new(),
-                )?
-            } else {
-                self.handle_unambiguous_unbraced_const_arg()?
-            };
-            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
+            GenericArg::Const(self.parse_const_arg()?)
         } else if self.check_type() {
             // Parse type argument.
             match self.parse_ty() {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 3c2462aab26..def2a501cf4 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -443,7 +443,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
         let kind = match &p.kind {
-            // FIXME(const_generics:defaults)
+            // FIXME(const_generics_defaults)
             hir::GenericParamKind::Type { default, .. } if default.is_some() => {
                 AnnotationKind::Container
             }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index dd1874debbd..fbe99a31150 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -586,7 +586,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     // Allow all following defaults to refer to this type parameter.
                     default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
                 }
-                GenericParamKind::Const { ref ty, kw_span: _ } => {
+                GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
+                    // FIXME(const_generics_defaults): handle `default` value here
                     for bound in &param.bounds {
                         self.visit_param_bound(bound);
                     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index ca30d90e6ad..0de732b2cf9 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -214,7 +214,7 @@ enum ResolutionError<'a> {
     /// Error E0530: `X` bindings cannot shadow `Y`s.
     BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
     /// Error E0128: type parameters with a default cannot use forward-declared identifiers.
-    ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
+    ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
     /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
     ParamInTyOfConstParam(Symbol),
     /// constant values inside of type parameter defaults must not depend on generic parameters.
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 40d60a8394b..987badcedde 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1343,9 +1343,12 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                         self.visit_ty(ty);
                     }
                 }
-                hir::GenericParamKind::Const { ref ty } => {
+                hir::GenericParamKind::Const { ref ty, ref default } => {
                     self.process_bounds(param.bounds);
                     self.visit_ty(ty);
+                    if let Some(default) = default {
+                        self.visit_anon_const(default);
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index ff445d727fa..e7d1c9d3bbe 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -614,9 +614,13 @@ impl<'hir> Sig for hir::Generics<'hir> {
                 start: offset + text.len(),
                 end: offset + text.len() + param_text.as_str().len(),
             });
-            if let hir::GenericParamKind::Const { ref ty } = param.kind {
+            if let hir::GenericParamKind::Const { ref ty, ref default } = param.kind {
                 param_text.push_str(": ");
                 param_text.push_str(&ty_to_string(&ty));
+                if let Some(ref _default) = default {
+                    // FIXME(const_generics_defaults): push the `default` value here
+                    todo!();
+                }
             }
             if !param.bounds.is_empty() {
                 param_text.push_str(": ");
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b040a70437d..64b50a9b70a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -368,6 +368,7 @@ symbols! {
         const_fn_transmute,
         const_fn_union,
         const_generics,
+        const_generics_defaults,
         const_if_match,
         const_impl_trait,
         const_in_array_repeat_expressions,
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 0feac036f00..a3a2b8967c6 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -387,7 +387,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     defaults.types += has_default as usize
                 }
                 GenericParamDefKind::Const => {
-                    // FIXME(const_generics:defaults)
+                    // FIXME(const_generics_defaults)
                 }
             };
         }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 38d33e55866..9a2210e4f0e 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -486,7 +486,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                     GenericParamDefKind::Const => {
                         let ty = tcx.at(self.span).type_of(param.def_id);
-                        // FIXME(const_generics:defaults)
+                        // FIXME(const_generics_defaults)
                         if infer_args {
                             // No const parameters were provided, we can infer all.
                             self.astconv.ct_infer(ty, Some(param), self.span).into()
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 2a8b77da44f..7126b624059 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1376,7 +1376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                     GenericParamDefKind::Const => {
-                        // FIXME(const_generics:defaults)
+                        // FIXME(const_generics_defaults)
                         // No const parameters were provided, we have to infer them.
                         self.fcx.var_for_def(self.span, param)
                     }
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 2ae9ded3fa0..ab41ff372e2 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -286,9 +286,9 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
         // We currently only check wf of const params here.
         hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
 
-        // Const parameters are well formed if their
-        // type is structural match.
-        hir::GenericParamKind::Const { ty: hir_ty } => {
+        // Const parameters are well formed if their type is structural match.
+        // FIXME(const_generics_defaults): we also need to check that the `default` is wf.
+        hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
             let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
 
             let err_ty_str;
@@ -785,7 +785,7 @@ fn check_where_clauses<'tcx, 'fcx>(
             }
 
             GenericParamDefKind::Const => {
-                // FIXME(const_generics:defaults)
+                // FIXME(const_generics_defaults)
                 fcx.tcx.mk_param_from_def(param)
             }
         }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 3e40f5ba28a..2ebb1a3be4e 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -228,7 +228,7 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
                 hir::GenericParamKind::Const { .. } => {
                     let def_id = self.tcx.hir().local_def_id(param.hir_id);
                     self.tcx.ensure().type_of(def_id);
-                    // FIXME(const_generics:defaults)
+                    // FIXME(const_generics_defaults)
                 }
             }
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f4eb1924e6f..2f430842f9d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -607,11 +607,12 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
                     synthetic,
                 },
             ),
-            hir::GenericParamKind::Const { ref ty } => (
+            hir::GenericParamKind::Const { ref ty, default: _ } => (
                 self.name.ident().name,
                 GenericParamDefKind::Const {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
                     ty: ty.clean(cx),
+                    // FIXME(const_generics_defaults): add `default` field here for docs
                 },
             ),
         };
@@ -1385,7 +1386,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &DocContext<'_>) -> Type {
                                 if let Some(ct) = const_ {
                                     ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx));
                                 }
-                                // FIXME(const_generics:defaults)
+                                // FIXME(const_generics_defaults)
                                 indices.consts += 1;
                             }
                         }
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.rs b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
index d7918a73ab8..5b0a42a4556 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.rs
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
@@ -1,4 +1,4 @@
 fn foo<const SIZE: usize = 5>() {}
-                      //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+//~^ ERROR default values for const generic parameters are experimental
 
 fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
index 8eb796d9bb7..31b5ad5123e 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
@@ -1,8 +1,12 @@
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+error[E0658]: default values for const generic parameters are experimental
   --> $DIR/default_function_param.rs:1:26
    |
 LL | fn foo<const SIZE: usize = 5>() {}
-   |                          ^ expected one of 7 possible tokens
+   |                          ^^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics_defaults)]` 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/const-generics/min_const_generics/default_trait_param.rs b/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
index c8003ad5d44..14bac473ed9 100644
--- a/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
+++ b/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
@@ -1,4 +1,4 @@
 trait Foo<const KIND: bool = true> {}
-                        //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+//~^ ERROR default values for const generic parameters are experimental
 
 fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr b/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
index 6d112ef1de0..5617b35ad01 100644
--- a/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
+++ b/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
@@ -1,8 +1,12 @@
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+error[E0658]: default values for const generic parameters are experimental
   --> $DIR/default_trait_param.rs:1:28
    |
 LL | trait Foo<const KIND: bool = true> {}
-   |                            ^ expected one of 7 possible tokens
+   |                            ^^^^^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics_defaults)]` 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/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
index 845c6111b59..a85e2a2f2c4 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
@@ -7,7 +7,7 @@ struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
 //[full]~^ ERROR constant values inside of type parameter defaults
 //[min]~^^ ERROR generic parameters may not be used in const operations
 
-// FIXME(const_generics:defaults): We still don't know how to we deal with type defaults.
+// FIXME(const_generics_defaults): We still don't know how to deal with type defaults.
 struct Bar<T = [u8; N], const N: usize>(T);
 //~^ ERROR constant values inside of type parameter defaults
 //~| ERROR type parameters with a default
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs
new file mode 100644
index 00000000000..5b5ccc88873
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs
@@ -0,0 +1,9 @@
+#[cfg(FALSE)]
+struct A<const N: usize = 3>;
+//~^ ERROR default values for const generic parameters are experimental
+
+#[cfg(FALSE)]
+fn foo<const B: bool = false>() {}
+//~^ ERROR default values for const generic parameters are experimental
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr
new file mode 100644
index 00000000000..e2b48d793fd
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr
@@ -0,0 +1,21 @@
+error[E0658]: default values for const generic parameters are experimental
+  --> $DIR/feature-gate-const_generics_defaults.rs:2:25
+   |
+LL | struct A<const N: usize = 3>;
+   |                         ^^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics_defaults)]` to the crate attributes to enable
+
+error[E0658]: default values for const generic parameters are experimental
+  --> $DIR/feature-gate-const_generics_defaults.rs:6:22
+   |
+LL | fn foo<const B: bool = false>() {}
+   |                      ^^^^^^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics_defaults)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
index f0267e4c792..940573e4caa 100644
--- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
@@ -407,6 +407,10 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
     }
 }
 
+pub fn eq_anon_const(l: &AnonConst, r: &AnonConst) -> bool {
+    eq_expr(&l.value, &r.value)
+}
+
 pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
     matches!(
         (l, r),
@@ -497,7 +501,8 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
         && match (&l.kind, &r.kind) {
             (Lifetime, Lifetime) => true,
             (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
-            (Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r),
+            (Const { ty: lt, kw_span: _ , default: ld}, Const { ty: rt, kw_span: _, default: rd }) =>
+                eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
             _ => false,
         }
         && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))