diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 947f2cc93b2ab..444b22887eabf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -446,6 +446,8 @@ pub enum GenericParamKind { span: Span, /// Optional default value for the const generic param. default: Option, + #[visitable(ignore)] + arg_pos: Option, }, } @@ -4483,7 +4485,7 @@ mod size_asserts { static_assert_size!(GenericArg, 24); static_assert_size!(GenericArgs, 40); static_assert_size!(GenericBound, 80); - static_assert_size!(GenericParam, 80); + static_assert_size!(GenericParam, 88); static_assert_size!(Generics, 40); static_assert_size!(Impl, 80); static_assert_size!(Item, 144); diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 7cb904ab5c353..81b8459a21ece 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -641,6 +641,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::GenericParamKind::Const { ty: self.arena.alloc(hir::Ty { kind, hir_id, span }), default: None, + arg_pos: None, } } }; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index aa58ac4a62eca..bc8c2e2d4737a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2355,7 +2355,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } - GenericParamKind::Const { ty, span: _, default } => { + GenericParamKind::Const { ty, default, arg_pos, .. } => { let ty = self.lower_ty_alloc( ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), @@ -2388,7 +2388,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default }, + hir::GenericParamKind::Const { ty, default, arg_pos: *arg_pos }, ) } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index fe5c604544448..c1eea80662d5f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1380,11 +1380,11 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara } GenericParamKind::Type { default: None } => (), GenericParamKind::Lifetime => (), - GenericParamKind::Const { ty: _, span: _, default: Some(default) } => { + GenericParamKind::Const { default: Some(default), .. } => { ordered_params += " = "; ordered_params += &pprust::expr_to_string(&default.value); } - GenericParamKind::Const { ty: _, span: _, default: None } => (), + GenericParamKind::Const { default: None, .. } => (), } first = false; } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index c1134e1dd7300..c48c2cfabe84b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -442,6 +442,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(final_associated_functions, "`final` on trait functions is experimental"); gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(frontmatter, "frontmatters are experimental"); + gate_all!(function_arg_const_generics, "function arg const generics are experimental"); gate_all!(gen_blocks, "gen blocks are experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(global_registration, "global registration is experimental"); diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index ab9037331050e..8f0481f90872a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -117,14 +117,13 @@ pub(crate) fn expand_deriving_coerce_pointee( GenericParamKind::Type { default: _ } => { cx.typaram(p.span(), p.ident, p.bounds.clone(), None) } - GenericParamKind::Const { ty, span: _, default: _ } => cx - .const_param( - p.span(), - p.ident, - p.bounds.clone(), - ty.clone(), - None, - ), + GenericParamKind::Const { ty, .. } => cx.const_param( + p.span(), + p.ident, + p.bounds.clone(), + ty.clone(), + None, + ), }) .collect(), where_clause: generics.where_clause.clone(), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d69f9ab7f0641..4be687254a4f5 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -649,6 +649,7 @@ impl<'a> TraitDef<'a> { // We can't have default values inside impl block default: None, + arg_pos: None, }; let mut param_clone = param.clone(); param_clone.kind = const_nodefault_kind; diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs index dc45b1a896bc9..420221f1152ee 100644 --- a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -172,7 +172,7 @@ fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics { GenericParamKind::Type { default: _ } => { cx.typaram(param.span(), param.ident, param.bounds.clone(), None) } - GenericParamKind::Const { ty, span: _, default: _ } => cx.const_param( + GenericParamKind::Const { ty, .. } => cx.const_param( param.span(), param.ident, param.bounds.clone(), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 0e9d9ec5e8b7e..fcb427e400441 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -174,7 +174,7 @@ impl<'a> ExtCtxt<'a> { attrs: AttrVec::new(), bounds, is_placeholder: false, - kind: ast::GenericParamKind::Const { ty, span: DUMMY_SP, default }, + kind: ast::GenericParamKind::Const { ty, span: DUMMY_SP, default, arg_pos: None }, colon_span: None, } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8d2184dcc1b0c..13844831b2641 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -542,6 +542,8 @@ declare_features! ( (internal, freeze_impls, "1.78.0", Some(121675)), /// Frontmatter `---` blocks for use by external tools. (unstable, frontmatter, "1.88.0", Some(136889)), + /// Should I open an issue for this? ask Boxy + (incomplete, function_arg_const_generics, "CURRENT_RUSTC_VERSION", Some(162540)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Allows using generics in more complex const expressions, based on definitional equality. @@ -855,6 +857,7 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[ /// Some features require one or more other features to be enabled. pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[ + (sym::function_arg_const_generics, &[sym::min_generic_const_args]), (sym::generic_const_args, &[sym::min_generic_const_args]), (sym::macroless_generic_const_args, &[sym::min_generic_const_args]), (sym::macroless_const_item_generic_const_args, &[sym::min_generic_const_args]), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ee79680d7d1e9..38e68d1bd88ed 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -848,6 +848,7 @@ pub enum GenericParamKind<'hir> { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param default: Option<&'hir ConstArg<'hir>>, + arg_pos: Option, }, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9cd4b5d7d001f..66a1fb31bad12 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1165,7 +1165,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( GenericParamKind::Type { ref default, .. } => { visit_opt!(visitor, visit_ty_unambig, default) } - GenericParamKind::Const { ref ty, ref default } => { + GenericParamKind::Const { ref ty, ref default, arg_pos: _ } => { try_visit!(visitor.visit_ty_unambig(ty)); if let Some(default) = default { try_visit!(visitor.visit_const_param_default(*hir_id, default)); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 1c52d5f5fa954..bef3481031d64 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -311,7 +311,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic } } - GenericParamKind::Const { ty: _, default } => { + GenericParamKind::Const { ty: _, default, arg_pos } => { if default.is_some() { match param_default_policy.expect("no policy for generic param default") { ParamDefaultPolicy::Allowed => {} @@ -322,7 +322,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } - ty::GenericParamDefKind::Const { has_default: default.is_some() } + ty::GenericParamDefKind::Const { has_default: default.is_some(), arg_pos } } }; Some(ty::GenericParamDef { @@ -525,7 +525,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector { type Result = ControlFlow<()>; fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { - if let GenericParamKind::Const { ty, default: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _, arg_pos: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; let res = self.visit_ty_unambig(ty); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 4a35bcb5ef28f..40971317bf14d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -439,8 +439,9 @@ pub(crate) fn check_generic_arg_count( .iter() .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })) .count(); + let arg_const_param_count = gen_params.own_arg_pos_consts().count(); let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; - let named_const_param_count = param_counts.consts; + let named_const_param_count = param_counts.consts - arg_const_param_count; let infer_lifetimes = (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_args(); @@ -616,7 +617,7 @@ pub(crate) fn check_generic_arg_count( let expected_min = if seg.infer_args { 0 } else { - param_counts.consts + named_type_param_count + named_const_param_count + named_type_param_count - default_counts.types - default_counts.consts }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5e081753cc821..2dc0d19166cc9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2387,6 +2387,57 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.check_param_uses_if_mcg(ct, tcx.hir_span(path_hir_id), false) } + pub fn lower_const_arg_expr(&self, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> Const<'tcx> { + let tcx = self.tcx(); + match expr.kind { + hir::ExprKind::Lit(lit) => { + self.lower_const_arg_literal(&lit.node, false, ty, expr.span) + } + hir::ExprKind::Unary( + hir::UnOp::Neg, + hir::Expr { kind: hir::ExprKind::Lit(lit), .. }, + ) => self.lower_const_arg_literal(&lit.node, true, ty, expr.span), + hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { res: Res::Local(_), .. })) => { + Const::new_error(tcx, self.dcx().span_err(expr.span, "Path error")) + } + hir::ExprKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_resolved_const_path(opt_self_ty, path, expr.hir_id) + } + hir::ExprKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { + let self_ty = self.lower_ty(hir_self_ty); + self.lower_type_relative_const_path( + self_ty, + hir_self_ty, + segment, + expr.hir_id, + expr.span, + ) + .unwrap_or_else(|guard| Const::new_error(tcx, guard)) + } + hir::ExprKind::ConstBlock(block) => { + let root = tcx.typeck_root_def_id_local(block.def_id); + let parent_args = ty::GenericArgs::identity_for_item(tcx, root); + let args = + ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }) + .args; + Const::new_alias( + tcx, + ty::IsRigid::No, + ty::AliasConst::new( + tcx, + ty::AliasConstKind::Anon { def_id: block.def_id.to_def_id() }, + args, + ), + ) + } + _ => Const::new_error( + tcx, + self.dcx().span_err(expr.span, "Some other variant we dont support"), + ), + } + } + /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`]. #[instrument(skip(self), level = "debug")] pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'_>, ty: Ty<'tcx>) -> Const<'tcx> { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 6d1ae563a9fa2..eec76111a6e38 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2476,7 +2476,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default } => { + GenericParamKind::Const { ty, ref default, arg_pos: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 47ba64a591aeb..6e3959d1c344f 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::iter; use rustc_abi::{CanonAbi, ExternAbi}; @@ -666,11 +667,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_id: SplatLoweringInfo<'tcx>, callee_generic_args: Option>, ) { + let mut formal_inputs = Cow::Borrowed(fn_sig.inputs()); + if let (SplatLoweringInfo::FnDef(def_id), Some(args)) = (fn_id, callee_generic_args) { + for (param, pos) in self.tcx.generics_of(def_id).own_arg_pos_consts() { + let ty = self.tcx.type_of(param.def_id).instantiate(self.tcx, args).skip_norm_wip(); + let ty = self.normalize(call_expr.span, Unnormalized::new_wip(ty)); + formal_inputs.to_mut().insert(pos as usize, ty); + } + } + let do_check = || { self.check_argument_types( call_expr.span, call_expr, - fn_sig.inputs(), + &formal_inputs, fn_sig.output(), expected, arg_exprs, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 06dbd06eb191b..d393b83c2c033 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -5,6 +5,8 @@ //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. +use std::borrow::Cow; + use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; @@ -618,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_and_args.map_or(expr.span, |(e, _)| e.span), expr.span, expr.hir_id, + call_expr_and_args.map(|(_, args)| args), ) .0 } @@ -1488,14 +1491,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Handle splatted method arguments // self is already handled as `rcvr`, so it's never splatted here - let method_inputs = &method.sig.inputs()[1..]; + let mut method_inputs = Cow::Borrowed(&method.sig.inputs()[1..]); + for (param, pos) in self.tcx.generics_of(method.def_id).own_arg_pos_consts() { + let ty = self + .tcx + .type_of(param.def_id) + .instantiate(self.tcx, method.args) + .skip_norm_wip(); + method_inputs.to_mut().insert(pos as usize - 1, ty); + } + let method_tuple_args_flag = TupleArgumentsFlag::with_fn_sig_kind(method.sig.fn_sig_kind, true); self.check_argument_types( segment.ident.span, expr, - method_inputs, + &method_inputs, method.sig.output(), expected, args, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index bf771ad81a819..cba88002ce1d8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -614,6 +614,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ct } + pub(crate) fn lower_const_arg_expr( + &self, + expr: &hir::Expr<'_>, + ty: Ty<'tcx>, + ) -> ty::Const<'tcx> { + let ct = self.lowerer().lower_const_arg_expr(expr, ty); + self.register_wf_obligation(ct.into(), expr.span, ObligationCauseCode::WellFormed(None)); + ct + } + // If the type given by the user has free regions, save it for later, since // NLL would like to enforce those. Also pass in types that involve // projections, since those can resolve to `'static` bounds (modulo #54940, @@ -1007,6 +1017,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, path_span: Span, hir_id: HirId, + call_args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> (Ty<'tcx>, Res) { let tcx = self.tcx; @@ -1292,6 +1303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { generic_segments: &'a [GenericPathSegment], infer_args_for_err: &'a FxHashSet, segments: &'tcx [hir::PathSegment<'tcx>], + call_args: Option<&'tcx [hir::Expr<'tcx>]>, } impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> { fn args_for_def_id( @@ -1360,6 +1372,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer_args: bool, ) -> ty::GenericArg<'tcx> { let tcx = self.fcx.tcx(); + if let Some(pos) = param.kind.arg_pos() { + let Some(args) = self.call_args else { + let guard = + self.fcx.dcx().span_err(self.span, "argument should be provided"); + return ty::Const::new_error(tcx, guard).into(); + }; + + let Some(arg) = args.get(pos as usize) else { + let guard = self + .fcx + .dcx() + .span_delayed_bug(self.span, "missing argument for const param"); + return ty::Const::new_error(tcx, guard).into(); + }; + let ty = + tcx.type_of(param.def_id).instantiate(tcx, preceding_args).skip_norm_wip(); + return self.fcx.lower_const_arg_expr(arg, ty).into(); + } if !infer_args && let Some(default) = param.default_value(tcx) { // If we have a default, then it doesn't matter that we're not inferring // the type/const arguments: We provide the default where any is missing. @@ -1387,6 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { generic_segments: &generic_segments, infer_args_for_err: &infer_args_for_err, segments, + call_args, }, ) }); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d9ed4bb4dd16f..86f03544b3ed3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2108,25 +2108,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }); - match (body_id, params) { + let mut params_with_generics: IndexVec = match (body_id, params) { (Some(_), Some(_)) | (None, None) => unreachable!(), (Some(body), None) => { let params = self.tcx.hir_body(body).params; let params = params .get(is_method as usize..params.len() - sig.decl.c_variadic() as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); - Some((fn_inputs.zip(params.iter().map(FnParam::Param)).collect(), generics)) + fn_inputs.zip(params.iter().map(FnParam::Param)).collect() } (None, Some(params)) => { let params = params .get(is_method as usize..params.len() - sig.decl.c_variadic() as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); - Some(( - fn_inputs.zip(params.iter().map(|&ident| FnParam::Ident(ident))).collect(), - generics, - )) + fn_inputs.zip(params.iter().map(|&ident| FnParam::Ident(ident))).collect() + } + }; + for param in generics.params { + if let hir::GenericParamKind::Const { arg_pos: Some(pos), .. } = param.kind + && let Some(idx) = (pos as usize).checked_sub(is_method as usize) + { + params_with_generics + .raw + .insert(idx, (None, FnParam::Ident(Some(param.name.ident())))); } } + Some((params_with_generics, generics)) } } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 02e7991b15743..18f45b834e618 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -41,6 +41,7 @@ pub(crate) struct ConfirmContext<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, skip_record_for_diagnostics: bool, + call_args: Option<&'tcx [hir::Expr<'tcx>]>, } impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { @@ -65,6 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, + args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> ConfirmResult<'tcx> { debug!( "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", @@ -72,6 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); + confirm_cx.call_args = args; confirm_cx.confirm(unadjusted_self_ty, pick, segment) } @@ -97,7 +100,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, ) -> ConfirmContext<'a, 'tcx> { - ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false } + ConfirmContext { + fcx, + span, + self_expr, + call_expr, + skip_record_for_diagnostics: false, + call_args: None, + } } fn confirm( @@ -490,10 +500,19 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn inferred_kind( &mut self, - _preceding_args: &[ty::GenericArg<'tcx>], + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, _infer_args: bool, ) -> ty::GenericArg<'tcx> { + if let Some(pos) = param.kind.arg_pos() + && let Some(args) = self.cfcx.call_args + && let Some(arg) = pos.checked_sub(1).and_then(|index| args.get(index as usize)) + { + let tcx = self.cfcx.tcx; + let ty = + tcx.type_of(param.def_id).instantiate(tcx, preceding_args).skip_norm_wip(); + return self.cfcx.lower_const_arg_expr(arg, ty).into(); + } self.cfcx.var_for_def(self.cfcx.span, param) } } diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 3425ba5d747d6..2aeb047cba52b 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -203,7 +203,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None); - let result = self.confirm_method(span, self_expr, call_expr, self_ty, &pick, segment); + let result = + self.confirm_method(span, self_expr, call_expr, self_ty, &pick, segment, Some(args)); debug!("result = {:?}", result); if let Some(span) = result.illegal_sized_bound { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 01be2de606b51..76adae6cc6b8d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -912,7 +912,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rustc_hir::PatExprKind::Path(qpath) => { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span); - self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0 + self.instantiate_value_path( + segments, opt_ty, res, lt.span, lt.span, lt.hir_id, None, + ) + .0 } }; self.write_ty(lt.hir_id, ty); @@ -1625,7 +1628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find the type of the path pattern, for later checking. let (pat_ty, pat_res) = - self.instantiate_value_path(segments, opt_ty, res, span, span, path_id); + self.instantiate_value_path(segments, opt_ty, res, span, span, path_id, None); Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } }) } @@ -1785,8 +1788,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Type-check the path. - let (pat_ty, res) = - self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); + let (pat_ty, res) = self + .instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id, None); if !pat_ty.is_fn() { return report_unexpected_res(res); } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index f5e983ab48f92..905d30d1240f8 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -15,7 +15,7 @@ use crate::ty::{self, ClauseKind, EarlyBinder, GenericArgsRef, Region, RegionKin pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool }, + Const { has_default: bool, arg_pos: Option }, } impl GenericParamDefKind { @@ -48,6 +48,13 @@ impl GenericParamDefKind { _ => false, } } + + pub fn arg_pos(&self) -> Option { + match self { + GenericParamDefKind::Const { arg_pos, .. } => *arg_pos, + _ => None, + } + } } #[derive(Clone, Debug, TyEncodable, TyDecodable, StableHash)] @@ -300,6 +307,10 @@ impl<'tcx> Generics { self.own_params.iter().filter(|p| p.kind.is_synthetic()).count() } + pub fn own_arg_pos_consts(&'tcx self) -> impl Iterator { + self.own_params.iter().filter_map(|param| Some((param, param.kind.arg_pos()?))) + } + /// Returns the args corresponding to the generic parameters /// of this item, excluding `Self`. /// diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 070ce5a3d6e24..42964bcaf679e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -411,10 +411,22 @@ impl<'tcx> ThirBuildCx<'tcx> { let expr = self.method_callee(expr, segment.ident.span, None); info!("Using method span: {:?}", expr.span); + let generics = match *expr.ty.kind() { + ty::FnDef(def_id, _) => Some(tcx.generics_of(def_id)), + _ => None, + }; + let is_const_arg = |idx: usize| { + generics.is_some_and(|g| { + g.own_arg_pos_consts().any(|(_, pos)| pos as usize == idx) + }) + }; let args = std::iter::once(receiver) .chain(args.iter()) - .map(|expr| self.mirror_expr(expr)) + .enumerate() + .filter(|&(idx, _)| !is_const_arg(idx)) + .map(|(_, arg)| self.mirror_expr(arg)) .collect(); + ExprKind::Call { ty: expr.ty, fun: self.thir.exprs.push(expr), @@ -516,10 +528,26 @@ impl<'tcx> ThirBuildCx<'tcx> { base: AdtExprBase::None, })) } else { + let fn_ty = self.typeck_results.node_type(fun.hir_id); + let generics = match *fn_ty.kind() { + ty::FnDef(def_id, _) => Some(tcx.generics_of(def_id)), + _ => None, + }; + let is_const_arg = |idx: usize| { + generics.is_some_and(|g| { + g.own_arg_pos_consts().any(|(_, pos)| pos as usize == idx) + }) + }; + let args = args + .iter() + .enumerate() + .filter(|&(idx, _)| !is_const_arg(idx)) + .map(|(_, arg)| self.mirror_expr(arg)) + .collect(); ExprKind::Call { - ty: self.typeck_results.node_type(fun.hir_id), + ty: fn_ty, fun: self.mirror_expr(fun), - args: self.mirror_exprs(args), + args, from_hir_call: true, fn_span: expr.span, } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6d4a0215eb7b3..cde52520c9c21 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -42,6 +42,7 @@ use crate::diagnostics::{ }; use crate::exp; use crate::parser::attr::InnerAttrPolicy; +use crate::parser::function::FuncParam; use crate::parser::{FnContext, IsDotDotDot}; /// Creates a placeholder argument. @@ -2473,9 +2474,10 @@ impl<'a> Parser<'a> { /// the parameters are *names* (so we don't emit errors about not being able to find `b` in /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, /// we deduplicate them to not complain about duplicated parameter names. - pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec) { + pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { + let FuncParam::GeneralParam(input) = input else { continue }; let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) = (&input.pat.kind, &input.ty.kind) { diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 57fe19226066c..baad87bb0ea34 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -109,6 +109,64 @@ pub(crate) enum FnContext { Impl, } +#[derive(Debug, Clone)] +pub(crate) enum FuncParam { + GeneralParam(Param), + ConstGenericParam(GenericParam), +} + +pub(crate) struct FnDeclWithConstGenerics { + pub(crate) inputs: ThinVec, + pub(crate) output: FnRetTy, +} + +impl FnDeclWithConstGenerics { + pub(crate) fn into_fn_decl(self) -> (FnDecl, ThinVec) { + let mut const_params = ThinVec::new(); + let inputs = self + .inputs + .into_iter() + .filter_map(|param| match param { + FuncParam::GeneralParam(param) => Some(param), + FuncParam::ConstGenericParam(param) => { + const_params.push(param); + None + } + }) + .collect(); + (FnDecl { inputs, output: self.output }, const_params) + } +} + +impl ast::HasAttrs for FuncParam { + // Follows `ast::Expr`. + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false; + + fn attrs(&self) -> &[rustc_ast::Attribute] { + match self { + FuncParam::GeneralParam(p) => &p.attrs, + FuncParam::ConstGenericParam(p) => &p.attrs, + } + } + + fn visit_attrs(&mut self, f: impl FnOnce(&mut rustc_ast::AttrVec)) { + match self { + FuncParam::GeneralParam(p) => p.visit_attrs(f), + FuncParam::ConstGenericParam(p) => p.visit_attrs(f), + } + } +} + +impl ast::HasTokens for FuncParam { + fn tokens(&self) -> Option<&rustc_ast::tokenstream::LazyAttrTokenStream> { + None + } + + fn tokens_mut(&mut self) -> Option<&mut Option> { + None + } +} + /// Parsing of functions and methods. impl<'a> Parser<'a> { /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`. @@ -138,6 +196,10 @@ impl<'a> Parser<'a> { } }; + let (decl, const_params) = decl.into_fn_decl(); + let decl = Box::new(decl); + generics.params.extend(const_params); + // Store the end of function parameters to give better diagnostics // inside `parse_fn_body()`. let fn_params_end = self.prev_token.span.shrink_to_hi(); @@ -663,18 +725,18 @@ impl<'a> Parser<'a> { fn_parse_mode: &FnParseMode, ret_allow_plus: AllowPlus, recover_return_sign: RecoverReturnSign, - ) -> PResult<'a, Box> { - Ok(Box::new(FnDecl { + ) -> PResult<'a, FnDeclWithConstGenerics> { + Ok(FnDeclWithConstGenerics { inputs: self.parse_fn_params(fn_parse_mode)?, output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, - })) + }) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. pub(super) fn parse_fn_params( &mut self, fn_parse_mode: &FnParseMode, - ) -> PResult<'a, ThinVec> { + ) -> PResult<'a, ThinVec> { let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... if self.token != TokenKind::OpenParen @@ -688,27 +750,34 @@ impl<'a> Parser<'a> { return Ok(ThinVec::new()); } + let mut param_index = 0; let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(fn_parse_mode, first_param, true).or_else(|e| { - let guar = e.emit(); - // When parsing a param failed, we should check to make the span of the param - // not contain '(' before it. - // For example when parsing `*mut Self` in function `fn oof(*mut Self)`. - let lo = if let TokenKind::OpenParen = p.prev_token.kind { - p.prev_token.span.shrink_to_hi() - } else { - p.prev_token.span - }; - p.restore_snapshot(snapshot); - // Skip every token until next possible arg or end. - p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]); - // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(sym::dummy, lo.to(p.prev_token.span)), guar)) - }); + let param = p + .parse_param_general(fn_parse_mode, first_param, true, Some(param_index)) + .or_else(|e| { + let guar = e.emit(); + // When parsing a param failed, we should check to make the span of the param + // not contain '(' before it. + // For example when parsing `*mut Self` in function `fn oof(*mut Self)`. + let lo = if let TokenKind::OpenParen = p.prev_token.kind { + p.prev_token.span.shrink_to_hi() + } else { + p.prev_token.span + }; + p.restore_snapshot(snapshot); + // Skip every token until next possible arg or end. + p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]); + // Create a placeholder argument for proper arg count (issue #34264). + Ok(FuncParam::GeneralParam(dummy_arg( + Ident::new(sym::dummy, lo.to(p.prev_token.span)), + guar, + ))) + }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; + param_index += 1; param })?; // Replace duplicated recovered params with `_` pattern to avoid unnecessary errors. @@ -725,7 +794,8 @@ impl<'a> Parser<'a> { fn_parse_mode: &FnParseMode, first_param: bool, recover_arg_parse: bool, - ) -> PResult<'a, Param> { + param_index: Option, + ) -> PResult<'a, FuncParam> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { @@ -733,7 +803,7 @@ impl<'a> Parser<'a> { if let Some(mut param) = this.parse_self_param()? { param.attrs = attrs; let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) }; - return Ok((res?, Trailing::No, UsePreAttrPos::No)); + return Ok((FuncParam::GeneralParam(res?), Trailing::No, UsePreAttrPos::No)); } let is_dot_dot_dot = if this.token.kind == token::DotDotDot { @@ -756,6 +826,37 @@ impl<'a> Parser<'a> { } else { is_name_required }; + + if let Some(arg_pos) = param_index + && this.eat_keyword(exp!(Const)) + { + let const_span = this.prev_token.span; + let ident = this.parse_ident()?; + let colon_span = Some(this.token.span); + this.expect(exp!(Colon))?; + let ty = this.parse_ty()?; + this.psess.gated_spans.gate(sym::function_arg_const_generics, const_span); + let generic_param = GenericParam { + id: ast::DUMMY_NODE_ID, + ident, + attrs, + bounds: ThinVec::new(), + is_placeholder: false, + kind: GenericParamKind::Const { + ty, + span: const_span.to(this.prev_token.span), + default: None, + arg_pos: Some(arg_pos), + }, + colon_span, + }; + return Ok(( + FuncParam::ConstGenericParam(generic_param), + Trailing::No, + UsePreAttrPos::No, + )); + } + let (pat, ty) = if is_name_required || this.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let (pat, colon) = this.parse_fn_param_pat_colon()?; @@ -772,7 +873,7 @@ impl<'a> Parser<'a> { let guar = err.emit(); let mut arg = dummy_arg(ident, guar); arg.span = pat_span; - Ok((arg, Trailing::No, UsePreAttrPos::No)) + Ok((FuncParam::GeneralParam(arg), Trailing::No, UsePreAttrPos::No)) } else { Err(err) }; @@ -792,7 +893,7 @@ impl<'a> Parser<'a> { this.check_trailing_angle_brackets(segment, &[exp!(CloseParen)]) { return Ok(( - dummy_arg(segment.ident, guar), + FuncParam::GeneralParam(dummy_arg(segment.ident, guar)), Trailing::No, UsePreAttrPos::No, )); @@ -825,7 +926,14 @@ impl<'a> Parser<'a> { let span = lo.to(this.prev_token.span); Ok(( - Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty }, + FuncParam::GeneralParam(Param { + attrs, + id: ast::DUMMY_NODE_ID, + is_placeholder: false, + pat, + span, + ty, + }), Trailing::No, UsePreAttrPos::No, )) diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index d47f8c4c264dd..b4c3ba683d2a8 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, bounds: ThinVec::new(), - kind: GenericParamKind::Const { ty, span, default: None }, + kind: GenericParamKind::Const { ty, span, default: None, arg_pos: None }, is_placeholder: false, colon_span: None, }) @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, bounds: ThinVec::new(), - kind: GenericParamKind::Const { ty, span, default }, + kind: GenericParamKind::Const { ty, span, default, arg_pos: None }, is_placeholder: false, colon_span: None, }) @@ -190,7 +190,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, bounds: ThinVec::new(), - kind: GenericParamKind::Const { ty, span, default }, + kind: GenericParamKind::Const { ty, span, default, arg_pos: None }, is_placeholder: false, colon_span: None, }) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index cbd0891c7fe9a..189899a776ff3 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -20,6 +20,7 @@ use crate::diagnostics::{ PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; +use crate::parser::function::FuncParam; use crate::parser::{CommaRecoveryMode, Expr, FnContext, FnParseMode, RecoverColon, RecoverComma}; /// Specifies how to parse a path. @@ -404,7 +405,12 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, false, false)?; + let param = match p.parse_param_general(&mode, false, false, None)? { + FuncParam::GeneralParam(param) => param, + FuncParam::ConstGenericParam(param) => { + unreachable!("const param parsed without a position: {param:?}") + } + }; if !matches!(param.pat.kind, PatKind::Missing) { self.psess .gated_spans diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f62f8f1765652..428ff32e5f304 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -17,6 +17,7 @@ use crate::diagnostics::{ InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; +use crate::parser::function::FuncParam; use crate::parser::{FnContext, FnParseMode, FrontMatterParsingMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; @@ -859,7 +860,10 @@ impl<'a> Parser<'a> { context: FnContext::FunctionPtrType, req_body: false, }; - let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?; + let (decl, const_params) = + self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?.into_fn_decl(); + params.extend(const_params); + let decl = Box::new(decl); let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::FnPtr(Box::new(FnPtrTy { @@ -1430,6 +1434,7 @@ impl<'a> Parser<'a> { FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false }; match self.parse_fn_decl(&mode, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) { Ok(decl) => { + let (decl, _) = decl.into_fn_decl(); self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span }); Some(ast::Path { span: fn_token_span.to(self.prev_token.span), @@ -1527,7 +1532,13 @@ impl<'a> Parser<'a> { let mode = FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false }; let inputs = match self.parse_fn_params(&mode) { - Ok(params) => params, + Ok(params) => params + .into_iter() + .filter_map(|param| match param { + FuncParam::GeneralParam(param) => Some(param), + FuncParam::ConstGenericParam(_) => None, + }) + .collect(), Err(err) => { if let Some(snapshot) = snapshot { self.restore_snapshot(snapshot); diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 17ce015d4ce10..a66fae23dd097 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -700,7 +700,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { ty::GenericParamDefKind::Type { has_default, synthetic } => { GenericParamDefKind::Type { has_default, synthetic } } - ty::GenericParamDefKind::Const { has_default } => { + ty::GenericParamDefKind::Const { has_default, arg_pos: _ } => { GenericParamDefKind::Const { has_default } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 095d5131c0b60..6938270a16c26 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1745,7 +1745,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { forward_ty_ban_rib.bindings.swap_remove(i); forward_ty_ban_rib_const_param_ty.bindings.swap_remove(i); } - GenericParamKind::Const { ref ty, span: _, ref default } => { + GenericParamKind::Const { ref ty, ref default, .. } => { // Const parameters can't have param bounds. assert!(param.bounds.is_empty()); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9bbfcbc60c42c..22ca0294abb76 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3584,7 +3584,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() } else if let GenericParam { - kind: GenericParamKind::Const { ty, span: _, default }, + kind: GenericParamKind::Const { ty, default, .. }, .. } = param { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5f18a4036af33..1dac00472829b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1732,7 +1732,7 @@ impl<'tcx> Resolver<'_, 'tcx> { .filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => Some("'_"), ty::GenericParamDefKind::Type { has_default, .. } - | ty::GenericParamDefKind::Const { has_default } => { + | ty::GenericParamDefKind::Const { has_default, arg_pos: _ } => { if has_default { None } else { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4c1b9c78b7963..ed650d0b94b75 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1058,6 +1058,7 @@ symbols! { fsub_algebraic, fsub_fast, full, + function_arg_const_generics, fundamental, fused_iterator, future_output, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7f6392fce691a..4bec8fea3a23c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -617,7 +617,7 @@ fn clean_generic_param_def( }, ) } - ty::GenericParamDefKind::Const { has_default } => ( + ty::GenericParamDefKind::Const { has_default, arg_pos: _ } => ( def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( @@ -696,7 +696,7 @@ fn clean_generic_param<'tcx>( }, ) } - hir::GenericParamKind::Const { ty, default } => ( + hir::GenericParamKind::Const { ty, default, arg_pos: _ } => ( param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index c340c56781082..ef7376d3959a3 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -923,11 +923,13 @@ fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool { ty: lt, default: ld, span: _, + arg_pos: _ }, Const { ty: rt, default: rd, span: _, + arg_pos: _ }, ) => eq_ty(lt, rt) && both(ld.as_ref(), rd.as_ref(), eq_anon_const), _ => false, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index cf7777d037d9b..ecac61a758895 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -373,10 +373,12 @@ impl HirEqInterExpr<'_, '_, '_> { GenericParamKind::Const { ty: l_ty, default: l_default, + arg_pos: _ }, GenericParamKind::Const { ty: r_ty, default: r_default, + arg_pos: _ }, ) => self.eq_ty(l_ty, r_ty) && both(*l_default, *r_default, |l, r| self.eq_const_arg(l, r)), _ => false, diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index b8e072c7c6956..ac8e0ccf1f56f 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -665,6 +665,7 @@ impl Rewrite for ast::GenericParam { ref ty, span, default, + .. } = &self.kind { param.push_str("const "); diff --git a/tests/ui/attributes/doc_examples/rustc_dump_generics.stderr b/tests/ui/attributes/doc_examples/rustc_dump_generics.stderr index b6b2eacb2c137..d40115642ce25 100644 --- a/tests/ui/attributes/doc_examples/rustc_dump_generics.stderr +++ b/tests/ui/attributes/doc_examples/rustc_dump_generics.stderr @@ -22,6 +22,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { diff --git a/tests/ui/attributes/dump_generics.stderr b/tests/ui/attributes/dump_generics.stderr index 5a212e01e8cbc..f966957055f81 100644 --- a/tests/ui/attributes/dump_generics.stderr +++ b/tests/ui/attributes/dump_generics.stderr @@ -39,6 +39,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -137,6 +138,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -225,6 +227,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -309,6 +312,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -393,6 +397,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -470,6 +475,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -562,6 +568,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -650,6 +657,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, GenericParamDef { @@ -803,6 +811,7 @@ note: Generics { pure_wrt_drop: false, kind: Const { has_default: false, + arg_pos: None, }, }, ], diff --git a/tests/ui/const-generics/function_arg_const_generics/basic_test.rs b/tests/ui/const-generics/function_arg_const_generics/basic_test.rs new file mode 100644 index 0000000000000..86bf37b599805 --- /dev/null +++ b/tests/ui/const-generics/function_arg_const_generics/basic_test.rs @@ -0,0 +1,18 @@ +//@ check-pass +#![feature(function_arg_const_generics, min_generic_const_args)] + +fn foo(const N: usize) -> [u8; N] { [0; N] } + +fn forward() -> [u8; K] { foo(K) } + +struct S; + +impl S { + fn m(&self, x: u8, const N: usize) -> [u8; N] { [x; N] } +} + +fn main() { + let _: [u8; 3] = foo(3); + let _: [u8; 5] = forward::<5>(); + let _: [u8; 4] = S::m(&S, 1, 4); +} diff --git a/tests/ui/feature-gates/feature-gate-function-arg-const-generics.rs b/tests/ui/feature-gates/feature-gate-function-arg-const-generics.rs new file mode 100644 index 0000000000000..582af74750d24 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-function-arg-const-generics.rs @@ -0,0 +1,4 @@ +fn foo(const N: usize) {} +//~^ ERROR function arg const generics are experimental + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-function-arg-const-generics.stderr b/tests/ui/feature-gates/feature-gate-function-arg-const-generics.stderr new file mode 100644 index 0000000000000..d5190ac6d86b8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-function-arg-const-generics.stderr @@ -0,0 +1,13 @@ +error[E0658]: function arg const generics are experimental + --> $DIR/feature-gate-function-arg-const-generics.rs:1:8 + | +LL | fn foo(const N: usize) {} + | ^^^^^ + | + = note: see issue #162540 for more information + = help: add `#![feature(function_arg_const_generics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 420b01102e41e..c7ee591200fc2 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -27,7 +27,7 @@ ast-stats Pat 448 (NN.N%) 7 64 ast-stats - Struct 64 (NN.N%) 1 ast-stats - Wild 64 (NN.N%) 1 ast-stats - Ident 320 (NN.N%) 5 -ast-stats GenericParam 400 (NN.N%) 5 80 +ast-stats GenericParam 440 (NN.N%) 5 88 ast-stats GenericBound 320 (NN.N%) 4 80 ast-stats - Trait 320 (NN.N%) 4 ast-stats AssocItem 288 (NN.N%) 4 72 @@ -58,7 +58,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 6_872 126 +ast-stats Total 6_912 126 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats