diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 0adf4f898ab6d..f9095084672c9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3753,10 +3753,29 @@ pub struct ConstItem { pub ident: Ident, pub generics: Generics, pub ty: Box, - pub expr: Option>, + pub body: Option, pub define_opaque: Option>, } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum ConstItemRhs { + TypeConst(AnonConst), + Body(Box), +} + +impl ConstItemRhs { + pub fn span(&self) -> Span { + self.expr().span + } + + pub fn expr(&self) -> &Expr { + match self { + ConstItemRhs::TypeConst(anon_const) => &anon_const.value, + ConstItemRhs::Body(expr) => expr, + } + } +} + // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ebd5aa6e93d83..80f4a59db1526 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -422,6 +422,7 @@ macro_rules! common_visitor_and_walkers { Closure, Const, ConstItem, + ConstItemRhs, Defaultness, Delegation, DelegationMac, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 53351f91c46bc..838edb1d8f95f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -172,15 +172,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::Static(box ast::StaticItem { ident, - ty: t, + ty, safety: _, mutability: m, expr: e, define_opaque, }) => { let ident = self.lower_ident(*ident); - let (ty, body_id) = - self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let body_id = self.lower_const_body(span, e.as_deref()); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(*m, ident, ty, body_id) } @@ -188,21 +189,24 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - expr, + body, define_opaque, .. }) => { let ident = self.lower_ident(*ident); - let (generics, (ty, body_id)) = self.lower_generics( + let (generics, (ty, body)) = self.lower_generics( generics, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_item_rhs(attrs, body.as_ref(), span); + (ty, body) }, ); self.lower_define_opaque(hir_id, &define_opaque); - hir::ItemKind::Const(ident, generics, ty, body_id) + hir::ItemKind::Const(ident, generics, ty, body) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, @@ -463,17 +467,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item( - &mut self, - ty: &Ty, - span: Span, - body: Option<&Expr>, - impl_trait_position: ImplTraitPosition, - ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position)); - (ty, self.lower_const_body(span, body)) - } - #[instrument(level = "debug", skip(self))] fn lower_use_tree( &mut self, @@ -808,7 +801,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - expr, + body, define_opaque, .. }) => { @@ -819,14 +812,15 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); - + let body = body + .as_ref() + .map(|body| this.lower_const_item_rhs(attrs, Some(body), i.span)); hir::TraitItemKind::Const(ty, body) }, ); if define_opaque.is_some() { - if expr.is_some() { + if body.is_some() { self.lower_define_opaque(hir_id, &define_opaque); } else { self.dcx().span_err( @@ -836,7 +830,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - (*ident, generics, kind, expr.is_some()) + (*ident, generics, kind, body.is_some()) } AssocItemKind::Fn(box Fn { sig, ident, generics, body: None, define_opaque, .. @@ -1021,7 +1015,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - expr, + body, define_opaque, .. }) => ( @@ -1033,8 +1027,8 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); this.lower_define_opaque(hir_id, &define_opaque); + let body = this.lower_const_item_rhs(attrs, body.as_ref(), i.span); hir::ImplItemKind::Const(ty, body) }, ), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4e2243e87873c..fb75edca4d133 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2303,6 +2303,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind }) } + fn lower_const_item_rhs( + &mut self, + attrs: &[hir::Attribute], + rhs: Option<&ConstItemRhs>, + span: Span, + ) -> hir::ConstItemRhs<'hir> { + match rhs { + Some(ConstItemRhs::TypeConst(anon)) => { + hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon)) + } + None if attr::contains_name(attrs, sym::type_const) => { + let const_arg = ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Error( + DUMMY_SP, + self.dcx().span_delayed_bug(DUMMY_SP, "no block"), + ), + }; + hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg)) + } + Some(ConstItemRhs::Body(body)) => { + hir::ConstItemRhs::Body(self.lower_const_body(span, Some(body))) + } + None => hir::ConstItemRhs::Body(self.lower_const_body(span, None)), + } + } + /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_anon_const`]. fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f773b02058ef1..8cb75cca32c38 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1236,9 +1236,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } }); } - ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { + ItemKind::Const(box ConstItem { defaultness, body, .. }) => { self.check_defaultness(item.span, *defaultness); - if expr.is_none() { + if body.is_none() { self.dcx().emit_err(errors::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1578,7 +1578,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { - AssocItemKind::Const(box ConstItem { expr: None, .. }) => { + AssocItemKind::Const(box ConstItem { body: None, .. }) => { self.dcx().emit_err(errors::AssocConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index ab402cbb8dc12..be50d71769806 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -213,7 +213,7 @@ impl<'a> State<'a> { ident, generics, ty, - expr, + body, define_opaque, }) => { self.print_item_const( @@ -221,7 +221,7 @@ impl<'a> State<'a> { None, generics, ty, - expr.as_deref(), + body.as_ref().map(|ct| ct.expr()), &item.vis, ast::Safety::Default, *defaultness, @@ -566,7 +566,7 @@ impl<'a> State<'a> { ident, generics, ty, - expr, + body, define_opaque, }) => { self.print_item_const( @@ -574,7 +574,7 @@ impl<'a> State<'a> { None, generics, ty, - expr.as_deref(), + body.as_ref().map(|ct| ct.expr()), vis, ast::Safety::Default, *defaultness, diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 40946f3b2791a..e5d9d2080c08e 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -43,7 +43,7 @@ pub(crate) fn expand( // Generate anonymous constant serving as container for the allocator methods. let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index c968353504e15..e69f0838f22e9 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -47,7 +47,7 @@ pub(crate) fn expand( // Generate anonymous constant serving as container for the allocator methods. let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 6ac3e17503d09..e30d506a31b9e 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -385,9 +385,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box { cx.attr_nested_word(sym::allow, sym::deprecated, span), ]); - let block = cx.expr_block( + let block = ast::ConstItemRhs::Body(cx.expr_block( cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), - ); + )); let anon_constant = cx.item_const( span, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 7a189ee1f4d05..21fd4689b9aa2 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -289,7 +289,7 @@ pub(crate) fn expand_test_or_bench( ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), define_opaque: None, // test::TestDescAndFn { - expr: Some( + body: Some(ast::ConstItemRhs::Body( cx.expr_struct( sp, test_path("TestDescAndFn"), @@ -371,7 +371,7 @@ pub(crate) fn expand_test_or_bench( field("testfn", test_fn), // } ], ), // } - ), + )), } .into(), ), diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index b63e929387e61..0a1d52a1b2237 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -6,7 +6,9 @@ // having basically only two use-cases that act in different ways. use rustc_errors::ErrorGuaranteed; -use rustc_hir::LangItem; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::DefKind; +use rustc_hir::{LangItem, find_attr}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, AdtDef, Ty}; @@ -365,8 +367,14 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Don't peek inside trait associated constants. - if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() { + // Avoid looking at attrs of anon consts as that will ICE + let is_type_const_item = + matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst) + && find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_)); + + // Don't peak inside trait associated consatnts, also `#[type_const] const` items + // don't have bodies so there's nothing to look at + if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 55541cdf4d7e1..f8497dea9f4b3 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -104,6 +104,10 @@ impl<'a> ExtCtxt<'a> { } } + pub fn anon_const_block(&self, b: Box) -> Box { + Box::new(self.anon_const(b.span, ast::ExprKind::Block(b, None))) + } + pub fn const_ident(&self, span: Span, ident: Ident) -> ast::AnonConst { self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident))) } @@ -722,7 +726,7 @@ impl<'a> ExtCtxt<'a> { span: Span, ident: Ident, ty: Box, - expr: Box, + body: ast::ConstItemRhs, ) -> Box { let defaultness = ast::Defaultness::Final; self.item( @@ -735,7 +739,7 @@ impl<'a> ExtCtxt<'a> { // FIXME(generic_const_items): Pass the generics as a parameter. generics: ast::Generics::default(), ty, - expr: Some(expr), + body: Some(body), define_opaque: None, } .into(), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 394747f81581e..e076ceaabf991 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -402,6 +402,28 @@ impl<'hir> PathSegment<'hir> { } } +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub enum ConstItemRhs<'hir> { + Body(BodyId), + TypeConst(&'hir ConstArg<'hir>), +} + +impl<'hir> ConstItemRhs<'hir> { + pub fn hir_id(&self) -> HirId { + match self { + ConstItemRhs::Body(body_id) => body_id.hir_id, + ConstItemRhs::TypeConst(ct_arg) => ct_arg.hir_id, + } + } + + pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span { + match self { + ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span, + ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(), + } + } +} + /// A constant that enters the type system, used for arguments to const generics (e.g. array lengths). /// /// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed @@ -473,6 +495,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { match self.kind { ConstArgKind::Path(path) => path.span(), ConstArgKind::Anon(anon) => anon.span, + ConstArgKind::Error(span, _) => span, ConstArgKind::Infer(span, _) => span, } } @@ -489,6 +512,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// However, in the future, we'll be using it for all of those. Path(QPath<'hir>), Anon(&'hir AnonConst), + /// Error const + Error(Span, ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes /// [`GenericArg::Infer`] is used instead. Infer(Span, Unambig), @@ -3161,7 +3186,7 @@ impl<'hir> TraitItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, Option), + expect_const, (&'hir Ty<'hir>, Option>), TraitItemKind::Const(ty, body), (ty, *body); expect_fn, (&FnSig<'hir>, &TraitFn<'hir>), @@ -3186,7 +3211,7 @@ pub enum TraitFn<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TraitItemKind<'hir> { /// An associated constant with an optional value (otherwise `impl`s must contain a value). - Const(&'hir Ty<'hir>, Option), + Const(&'hir Ty<'hir>, Option>), /// An associated function with an optional body. Fn(FnSig<'hir>, TraitFn<'hir>), /// An associated type with (possibly empty) bounds and optional concrete @@ -3255,9 +3280,9 @@ impl<'hir> ImplItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body); - expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); - expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty; + expect_const, (&'hir Ty<'hir>, ConstItemRhs<'hir>), ImplItemKind::Const(ty, body), (ty, *body); + expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); + expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty; } } @@ -3266,7 +3291,7 @@ impl<'hir> ImplItem<'hir> { pub enum ImplItemKind<'hir> { /// An associated constant of the given type, set to the constant result /// of the expression. - Const(&'hir Ty<'hir>, BodyId), + Const(&'hir Ty<'hir>, ConstItemRhs<'hir>), /// An associated function implementation with the given signature and body. Fn(FnSig<'hir>, BodyId), /// An associated type. @@ -4195,8 +4220,8 @@ impl<'hir> Item<'hir> { expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId), ItemKind::Static(mutbl, ident, ty, body), (*mutbl, *ident, ty, *body); - expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), - ItemKind::Const(ident, generics, ty, body), (*ident, generics, ty, *body); + expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, ConstItemRhs<'hir>), + ItemKind::Const(ident, generics, ty, ct_arg), (*ident, generics, ty, *ct_arg); expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); @@ -4367,7 +4392,7 @@ pub enum ItemKind<'hir> { /// A `static` item. Static(Mutability, Ident, &'hir Ty<'hir>, BodyId), /// A `const` item. - Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), + Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, ConstItemRhs<'hir>), /// A function declaration. Fn { sig: FnSig<'hir>, @@ -4605,17 +4630,18 @@ impl<'hir> OwnerNode<'hir> { OwnerNode::Item(Item { kind: ItemKind::Static(_, _, _, body) - | ItemKind::Const(_, _, _, body) + | ItemKind::Const(.., ConstItemRhs::Body(body)) | ItemKind::Fn { body, .. }, .. }) | OwnerNode::TraitItem(TraitItem { kind: - TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + TraitItemKind::Fn(_, TraitFn::Provided(body)) + | TraitItemKind::Const(_, Some(ConstItemRhs::Body(body))), .. }) | OwnerNode::ImplItem(ImplItem { - kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, ConstItemRhs::Body(body)), .. }) => Some(*body), _ => None, @@ -4866,7 +4892,7 @@ impl<'hir> Node<'hir> { Node::Item(Item { owner_id, kind: - ItemKind::Const(_, _, _, body) + ItemKind::Const(.., ConstItemRhs::Body(body)) | ItemKind::Static(.., body) | ItemKind::Fn { body, .. }, .. @@ -4874,12 +4900,13 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { owner_id, kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), + TraitItemKind::Const(.., Some(ConstItemRhs::Body(body))) + | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { owner_id, - kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), + kind: ImplItemKind::Const(.., ConstItemRhs::Body(body)) | ImplItemKind::Fn(_, body), .. }) => Some((owner_id.def_id, *body)), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index eb682f32111a5..72ca3d72aeb36 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -369,6 +369,10 @@ pub trait Visitor<'v>: Sized { walk_ty(self, t) } + fn visit_const_item_rhs(&mut self, c: ConstItemRhs<'v>) -> Self::Result { + walk_const_item_rhs(self, c) + } + /// All consts are treated as ambiguous consts for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// @@ -551,7 +555,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty_unambig(typ)); - try_visit!(visitor.visit_nested_body(body)); + try_visit!(visitor.visit_const_item_rhs(body)); } ItemKind::Fn { ident, sig, generics, body: body_id, .. } => { try_visit!(visitor.visit_ident(ident)); @@ -1036,6 +1040,16 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - V::Result::output() } +pub fn walk_const_item_rhs<'v, V: Visitor<'v>>( + visitor: &mut V, + ct_rhs: ConstItemRhs<'v>, +) -> V::Result { + match ct_rhs { + ConstItemRhs::Body(body_id) => visitor.visit_nested_body(body_id), + ConstItemRhs::TypeConst(const_arg) => visitor.visit_const_arg_unambig(const_arg), + } +} + pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v>, @@ -1058,6 +1072,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( match kind { ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), + ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important } } @@ -1220,7 +1235,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( match *kind { TraitItemKind::Const(ref ty, default) => { try_visit!(visitor.visit_ty_unambig(ty)); - visit_opt!(visitor, visit_nested_body, default); + visit_opt!(visitor, visit_const_item_rhs, default); } TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => { try_visit!(visitor.visit_fn_decl(sig.decl)); @@ -1275,7 +1290,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( match *kind { ImplItemKind::Const(ref ty, body) => { try_visit!(visitor.visit_ty_unambig(ty)); - visitor.visit_nested_body(body) + visitor.visit_const_item_rhs(body) } ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn( FnKind::Method(impl_item.ident, sig), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b6a662f425602..f72cd8c52e9f4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -96,6 +96,7 @@ pub(crate) fn provide(providers: &mut Providers) { rendered_precise_capturing_args, const_param_default, anon_const_kind, + const_of_item, ..*providers }; } @@ -1526,6 +1527,7 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin let const_arg_id = tcx.parent_hir_id(hir_id); match tcx.hir_node(const_arg_id) { hir::Node::ConstArg(_) => { + let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id)); if tcx.features().generic_const_exprs() { ty::AnonConstKind::GCE } else if tcx.features().min_generic_const_args() { @@ -1533,7 +1535,7 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Repeat(_, repeat_count), .. - }) = tcx.hir_node(tcx.parent_hir_id(const_arg_id)) + }) = parent_hir_node && repeat_count.hir_id == const_arg_id { ty::AnonConstKind::RepeatExprCount @@ -1544,3 +1546,32 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin _ => ty::AnonConstKind::NonTypeSystem, } } + +#[instrument(level = "debug", skip(tcx), ret)] +fn const_of_item<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let ct_rhs = match tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => *ct, + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(.., ct), .. + }) => ct.expect("no default value for trait assoc const"), + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct, + _ => { + span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item") + } + }; + let ct_arg = match ct_rhs { + hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg, + hir::ConstItemRhs::Body(body_id) => { + bug!("cannot call const_of_item on a non-type_const {body_id:?}") + } + }; + let icx = ItemCtxt::new(tcx, def_id); + let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); + let ct = icx + .lowerer() + .lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + ty::EarlyBinder::bind(ct) +} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 333cea23c4148..3d2f0466cad08 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -77,20 +77,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // stable enough and does not need a feature gate anymore. Node::AnonConst(_) => { let parent_did = tcx.parent(def_id.to_def_id()); - - // We don't do this unconditionally because the `DefId` parent of an anon const - // might be an implicitly created closure during `async fn` desugaring. This would - // have the wrong generics. - // - // i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }` - // would implicitly have a closure in its body that would be the parent of - // the `{ 1 + 2 }` anon const. This closure's generics is simply a witness - // instead of `['a]`. - let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) { - parent_did - } else { - tcx.hir_get_parent_item(hir_id).to_def_id() - }; debug!(?parent_did); let mut in_param_ty = false; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8cbf17162e321..f9aae54bbcdb1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -158,14 +158,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - TraitItemKind::Const(ty, body_id) => body_id - .and_then(|body_id| { + TraitItemKind::Const(ty, body) => body + .and_then(|ct_arg| { ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + ct_arg.hir_id(), ty.span, + ct_arg.span(tcx), item.ident, "associated constant", ) @@ -183,13 +184,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ImplItemKind::Const(ty, body_id) => { + ImplItemKind::Const(ty, ct_arg) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + ct_arg.hir_id(), ty.span, + ct_arg.span(tcx), item.ident, "associated constant", ) @@ -212,8 +214,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ infer_placeholder_type( icx.lowerer(), def_id, - body_id, + body_id.hir_id, ty.span, + tcx.hir_body(body_id).value.span, ident, "static variable", ) @@ -229,13 +232,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } } } - ItemKind::Const(ident, _, ty, body_id) => { + ItemKind::Const(ident, _, ty, body) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + body.hir_id(), ty.span, + body.span(tcx), ident, "constant", ) @@ -425,13 +429,14 @@ pub(super) fn type_of_opaque_hir_typeck( fn infer_placeholder_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, - body_id: hir::BodyId, - span: Span, + hir_id: HirId, + ty_span: Span, + body_span: Span, item_ident: Ident, kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - let ty = tcx.typeck(def_id).node_type(body_id.hir_id); + let ty = tcx.typeck(def_id).node_type(hir_id); // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. @@ -439,10 +444,10 @@ fn infer_placeholder_type<'tcx>( // us to improve in typeck so we do that now. let guar = cx .dcx() - .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| { + .try_steal_modify_and_emit_err(ty_span, StashKey::ItemNoType, |err| { if !ty.references_error() { // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic). - let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" }; + let colon = if ty_span == item_ident.span.shrink_to_hi() { ":" } else { "" }; // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. @@ -452,14 +457,14 @@ fn infer_placeholder_type<'tcx>( if let Some(ty) = ty.make_suggestable(tcx, false, None) { err.span_suggestion( - span, + ty_span, format!("provide a type for the {kind}"), format!("{colon} {ty}"), Applicability::MachineApplicable, ); } else { with_forced_trimmed_paths!(err.span_note( - tcx.hir_body(body_id).value.span, + body_span, format!("however, the inferred type `{ty}` cannot be named"), )); } @@ -473,7 +478,7 @@ fn infer_placeholder_type<'tcx>( } // If we didn't find any infer tys, then just fallback to `span`. if visitor.spans.is_empty() { - visitor.spans.push(span); + visitor.spans.push(ty_span); } let mut diag = bad_placeholder(cx, visitor.spans, kind); @@ -482,20 +487,20 @@ fn infer_placeholder_type<'tcx>( // same span. If this happens, we will fall through to this arm, so // we need to suppress the suggestion since it's invalid. Ideally we // would suppress the duplicated error too, but that's really hard. - if span.is_empty() && span.from_expansion() { + if ty_span.is_empty() && ty_span.from_expansion() { // An approximately better primary message + no suggestion... diag.primary_message("missing type for item"); } else if !ty.references_error() { if let Some(ty) = ty.make_suggestable(tcx, false, None) { diag.span_suggestion_verbose( - span, + ty_span, "replace this with a fully-specified type", ty, Applicability::MachineApplicable, ); } else { with_forced_trimmed_paths!(diag.span_note( - tcx.hir_body(body_id).value.span, + body_span, format!("however, the inferred type `{ty}` cannot be named"), )); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 7accab8df87c7..5930df67479fb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -5,9 +5,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; -use rustc_hir::PolyTraitRef; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_hir::{PolyTraitRef, find_attr}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -578,7 +579,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { term, }) }); - bounds.push((bound.upcast(tcx), constraint.span)); + + if let ty::AssocTag::Const = assoc_tag + && !find_attr!( + self.tcx().get_all_attrs(assoc_item.def_id), + AttributeKind::TypeConst(_) + ) + { + if tcx.features().min_generic_const_args() + || tcx.features().associated_const_equality() + { + let mut err = self.dcx().struct_span_err( + constraint.span, + "use of trait associated const without `#[type_const]`", + ); + err.note("the declaration in the trait must be marked with `#[type_const]`"); + return Err(err.emit()); + } else { + let err = self.dcx().span_delayed_bug( + constraint.span, + "use of trait associated const without `#[type_const]`", + ); + return Err(err); + } + } else { + bounds.push((bound.upcast(tcx), constraint.span)); + } } // SelfTraitThatDefines is only interested in trait predicates. PredicateFilter::SelfTraitThatDefines(_) => {} 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 eb660804c2b52..cef08097f3045 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -27,9 +27,10 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; +use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, find_attr}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::DynCompatibilityViolation; use rustc_macros::{TypeFoldable, TypeVisitable}; @@ -1244,7 +1245,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { LowerTypeRelativePathMode::Const, )? { TypeRelativePath::AssocItem(def_id, args) => { - if !tcx.associated_item(def_id).is_type_const_capable(tcx) { + if !find_attr!(self.tcx().get_all_attrs(def_id), AttributeKind::TypeConst(_)) { let mut err = self.dcx().struct_span_err( span, "use of trait associated const without `#[type_const]`", @@ -1685,6 +1686,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::AssocTag::Const, ) { Ok((item_def_id, item_args)) => { + if !find_attr!(self.tcx().get_all_attrs(item_def_id), AttributeKind::TypeConst(_)) { + let mut err = self.dcx().struct_span_err( + span, + "use of `const` in the type system without `#[type_const]`", + ); + err.note("the declaration must be marked with `#[type_const]`"); + return Const::new_error(self.tcx(), err.emit()); + } + let uv = ty::UnevaluatedConst::new(item_def_id, item_args); Const::new_unevaluated(self.tcx(), uv) } @@ -2217,6 +2227,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), + hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 6659aff711107..1206004921385 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -91,13 +91,16 @@ mod variance; pub use errors::NoVariantNamed; use rustc_abi::{CVariadicStatus, ExternAbi}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::lints::DelayedLint; -use rustc_hir::{self as hir}; -use rustc_middle::middle; +use rustc_hir::{ + find_attr, {self as hir}, +}; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{Const, Ty, TyCtxt}; +use rustc_middle::{middle, ty}; use rustc_session::parse::feature_err; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; @@ -227,7 +230,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.ensure_ok().eval_static_initializer(item_def_id); check::maybe_check_static_with_link_section(tcx, item_def_id); } - DefKind::Const if !tcx.generics_of(item_def_id).own_requires_monomorphization() => { + DefKind::Const + if !tcx.generics_of(item_def_id).own_requires_monomorphization() + && !find_attr!(tcx.get_all_attrs(item_def_id), AttributeKind::TypeConst(_)) => + { // FIXME(generic_const_items): Passing empty instead of identity args is fishy but // seems to be fine for now. Revisit this! let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty()); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b9d8eed54a9e3..bb79c16e24013 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -523,17 +523,17 @@ impl<'a> State<'a> { ident: Ident, generics: &hir::Generics<'_>, ty: &hir::Ty<'_>, - default: Option, + default: Option>, ) { self.word_space("const"); self.print_ident(ident); self.print_generic_params(generics.params); self.word_space(":"); self.print_type(ty); - if let Some(expr) = default { + if let Some(ct_rhs) = default { self.space(); self.word_space("="); - self.ann.nested(self, Nested::Body(expr)); + self.print_const_item_rhs(ct_rhs); } self.print_where_clause(generics); self.word(";") @@ -616,7 +616,7 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } - hir::ItemKind::Const(ident, generics, ty, expr) => { + hir::ItemKind::Const(ident, generics, ty, rhs) => { let (cb, ib) = self.head("const"); self.print_ident(ident); self.print_generic_params(generics.params); @@ -626,7 +626,7 @@ impl<'a> State<'a> { self.end(ib); self.word_space("="); - self.ann.nested(self, Nested::Body(expr)); + self.print_const_item_rhs(rhs); self.print_where_clause(generics); self.word(";"); self.end(cb); @@ -1125,10 +1125,18 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(constant.body)) } + fn print_const_item_rhs(&mut self, ct_rhs: hir::ConstItemRhs<'_>) { + match ct_rhs { + hir::ConstItemRhs::Body(body_id) => self.ann.nested(self, Nested::Body(body_id)), + hir::ConstItemRhs::TypeConst(const_arg) => self.print_const_arg(const_arg), + } + } + fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), + ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), ConstArgKind::Infer(..) => self.word("_"), } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index d14463e44a03f..d204a3c731ae3 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1490,13 +1490,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { if let Some(def_id) = opt_def_id && let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, _, _, body_id), + kind: hir::ItemKind::Const(_, _, _, ct_rhs), .. })) = self.tcx.hir_get_if_local(def_id) - && let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id) + && let hir::Node::Expr(expr) = self.tcx.hir_node(ct_rhs.hir_id()) && hir::is_range_literal(expr) { - let span = self.tcx.hir_span(body_id.hir_id); + let span = self.tcx.hir_span(ct_rhs.hir_id()); if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { e.span_suggestion_verbose( ident.span, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0669da1a025b1..6d07f6f90619f 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -978,9 +978,9 @@ impl<'tcx> LateContext<'tcx> { .. }) => *init, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { - Some(self.tcx.hir_body(body_id).value) - } + // FIXME(mgca): figure out how to handle ConstArgKind::Path (or don't but add warning in docs here) + hir::ItemKind::Const(.., hir::ConstItemRhs::Body(body_id)) + | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value), _ => None, }, _ => None, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1594a0361a62c..73c0736fa53b6 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1016,19 +1016,22 @@ trait UnusedDelimLint { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(box ast::ConstItem { expr: Some(expr), .. }) - | Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind - { - self.check_unused_delims_expr( - cx, - expr, - UnusedDelimsCtx::AssignedValue, - false, - None, - None, - false, - ); - } + let expr = if let Const(box ast::ConstItem { body: Some(body), .. }) = &item.kind { + body.expr() + } else if let Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind { + expr + } else { + return; + }; + self.check_unused_delims_expr( + cx, + expr, + UnusedDelimsCtx::AssignedValue, + false, + None, + None, + false, + ); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index df3add316ec23..7f4d603ba062d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -402,6 +402,7 @@ provide! { tcx, def_id, other, cdata, tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) } anon_const_kind => { table } + const_of_item => { table } } pub(in crate::rmeta) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index db66938457f09..46f5f01f8368b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1350,6 +1350,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool { fn should_encode_const(def_kind: DefKind) -> bool { match def_kind { + // FIXME(mgca): should we remove Const and AssocConst here? DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true, DefKind::Struct @@ -1428,7 +1429,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { && match tcx.hir_node_by_def_id(local_id) { hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind { // Skip encoding defs for these as they should not have had a `DefId` created - hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, + hir::ConstArgKind::Error(..) + | hir::ConstArgKind::Path(..) + | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, }, _ => false, @@ -1601,6 +1604,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::AnonConst = def_kind { record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); } + if let DefKind::Const = def_kind + && find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + { + record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id)); + } + if let DefKind::AssocConst = def_kind + && find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + { + let assoc_item = tcx.associated_item(def_id); + let should_encode = match assoc_item.container { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, + ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), + }; + if should_encode { + record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id)); + } + } if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 720970bbaf93f..cfdd5f970f3d9 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -468,6 +468,7 @@ define_tables! { assumed_wf_types_for_rpitit: Table, Span)>>, opaque_ty_origin: Table>>, anon_const_kind: Table>, + const_of_item: Table>>>, associated_types_for_impl_traits_in_trait_or_impl: Table>>>, } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index feaad5bb96eb9..cdf85b82ae727 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -44,7 +44,7 @@ macro_rules! arena_types { rustc_middle::traits::query::DropckOutlivesResult<'tcx> > >, - [] normalize_canonicalized_projection_ty: + [] normalize_canonicalized_projection: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::NormalizationResult<'tcx> diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 448c26ef31813..c6728e2b47a8a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -292,6 +292,13 @@ rustc_queries! { separate_provide_extern } + /// Returns the const of the RHS of a const item. + query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + desc { |tcx| "computing the value for `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Returns the *type* of the definition given by `DefId`. /// /// For type aliases (whether eager or lazy) and associated types, this returns @@ -2411,7 +2418,7 @@ rustc_queries! { /// Do not call this query directly: Invoke `normalize` instead. /// /// - query normalize_canonicalized_projection_ty( + query normalize_canonicalized_projection( goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, @@ -2439,7 +2446,7 @@ rustc_queries! { /// Do not call this query directly: Invoke `normalize` instead. /// /// - query normalize_canonicalized_inherent_projection_ty( + query normalize_canonicalized_inherent_projection( goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index c5cd7c54e4e86..9f3bc0ec43e6a 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -66,7 +66,7 @@ pub mod type_op { } pub type CanonicalAliasGoal<'tcx> = - CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTerm<'tcx>>>; pub type CanonicalMethodAutoderefStepsGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>; @@ -192,11 +192,11 @@ pub struct MethodAutoderefBadTy<'tcx> { pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, } -/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}_ty` queries. +/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}` queries. #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct NormalizationResult<'tcx> { /// Result of the normalization. - pub normalized_ty: Ty<'tcx>, + pub normalized_term: ty::Term<'tcx>, } /// Outlives bounds are relationships between generic parameters, diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 768646c763029..5e20bc142ffe6 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -1,9 +1,7 @@ use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_hir as hir; -use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; -use rustc_hir::find_attr; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, Ident, Symbol}; @@ -173,24 +171,6 @@ impl AssocItem { pub fn is_impl_trait_in_trait(&self) -> bool { matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) } - - /// Returns true if: - /// - This trait associated item has the `#[type_const]` attribute, - /// - If it is in a trait impl, the item from the original trait has this attribute, or - /// - It is an inherent assoc const. - pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool { - if !matches!(self.kind, ty::AssocKind::Const { .. }) { - return false; - } - - let def_id = match self.container { - AssocContainer::Trait => self.def_id, - AssocContainer::TraitImpl(Ok(trait_item_did)) => trait_item_did, - AssocContainer::TraitImpl(Err(_)) => return false, - AssocContainer::InherentImpl => return true, - }; - find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) - } } #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index de2b2e6c64f25..4b5a08919768a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -242,6 +242,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } + fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + self.const_of_item(def_id) + } type AdtDef = ty::AdtDef<'tcx>; fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 52e6f2d3e1a59..6e071fb344c44 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -58,8 +58,12 @@ pub(crate) fn lit_to_const<'tcx>( (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ty::ValTree::from_scalar_int(tcx, n.into()) } - (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { - ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) + (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => + { + // A CStr is a newtype around a byte slice, so we create the inner slice here. + // We need a branch for each "level" of the data structure. + let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); + ty::ValTree::from_branches(tcx, [bytes]) } (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index 8aa6e4a3d7118..8777f84957a79 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -30,14 +30,12 @@ where ); let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - panic!("normalizing free const aliases in the type system is unsupported"); + cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into() }; - self.instantiate_normalizes_to_term(goal, actual.into()); + self.instantiate_normalizes_to_term(goal, actual); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 2bb1ac8f7426e..42aa237762d9e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -54,8 +54,7 @@ where let normalized = if inherent.kind(cx).is_type() { cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() } else { - // FIXME(mgca): Properly handle IACs in the type system - panic!("normalizing inherent associated consts in the type system is unsupported"); + cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into() }; self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 0674b3d42ab4d..110cc30e740bb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -366,19 +366,7 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - if cx.features().associated_const_equality() { - panic!("associated const projection is not supported yet") - } else { - ty::EarlyBinder::bind( - Const::new_error_with_message( - cx, - "associated const projection is not supported yet", - ) - .into(), - ) - } + cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) } kind => panic!("expected projection, found {kind:?}"), }; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index aa03d5956cd23..db1712e7b6074 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -6,7 +6,9 @@ use rustc_ast::ast::*; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; -use rustc_ast::{self as ast}; +use rustc_ast::{ + attr, {self as ast}, +}; use rustc_ast_pretty::pprust; use rustc_errors::codes::*; use rustc_errors::{Applicability, PResult, StashKey, struct_span_code_err}; @@ -255,13 +257,13 @@ impl<'a> Parser<'a> { } else { self.recover_const_mut(const_span); self.recover_missing_kw_before_item()?; - let (ident, generics, ty, expr) = self.parse_const_item()?; + let (ident, generics, ty, body) = self.parse_const_item(attrs)?; ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ident, generics, ty, - expr, + body, define_opaque: None, })) } @@ -1013,12 +1015,13 @@ impl<'a> Parser<'a> { define_opaque, }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); + let body = expr.map(ConstItemRhs::Body); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, ident, generics: Generics::default(), ty, - expr, + body, define_opaque, })) } @@ -1273,7 +1276,7 @@ impl<'a> Parser<'a> { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Const(box ConstItem { ident, ty, expr, .. }) => { + ItemKind::Const(box ConstItem { ident, ty, body, .. }) => { let const_span = Some(span.with_hi(ident.span.lo())) .filter(|span| span.can_be_used_for_suggestions()); self.dcx().emit_err(errors::ExternItemCannotBeConst { @@ -1284,7 +1287,10 @@ impl<'a> Parser<'a> { ident, ty, mutability: Mutability::Not, - expr, + expr: body.map(|b| match b { + ConstItemRhs::TypeConst(anon_const) => anon_const.value, + ConstItemRhs::Body(expr) => expr, + }), safety: Safety::Default, define_opaque: None, })) @@ -1455,7 +1461,8 @@ impl<'a> Parser<'a> { /// ``` fn parse_const_item( &mut self, - ) -> PResult<'a, (Ident, Generics, Box, Option>)> { + attrs: &[Attribute], + ) -> PResult<'a, (Ident, Generics, Box, Option)> { let ident = self.parse_ident_or_underscore()?; let mut generics = self.parse_generics()?; @@ -1482,7 +1489,15 @@ impl<'a> Parser<'a> { let before_where_clause = if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() }; - let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None }; + let body = if self.eat(exp!(Eq)) { + if attr::contains_name(attrs, sym::type_const) { + Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?)) + } else { + Some(ConstItemRhs::Body(self.parse_expr()?)) + } + } else { + None + }; let after_where_clause = self.parse_where_clause()?; @@ -1490,18 +1505,18 @@ impl<'a> Parser<'a> { // Users may be tempted to write such code if they are still used to the deprecated // where-clause location on type aliases and associated types. See also #89122. if before_where_clause.has_where_token - && let Some(expr) = &expr + && let Some(body) = &body { self.dcx().emit_err(errors::WhereClauseBeforeConstBody { span: before_where_clause.span, name: ident.span, - body: expr.span, + body: body.span(), sugg: if !after_where_clause.has_where_token { - self.psess.source_map().span_to_snippet(expr.span).ok().map(|body| { + self.psess.source_map().span_to_snippet(body.span()).ok().map(|body_s| { errors::WhereClauseBeforeConstBodySugg { left: before_where_clause.span.shrink_to_lo(), - snippet: body, - right: before_where_clause.span.shrink_to_hi().to(expr.span), + snippet: body_s, + right: before_where_clause.span.shrink_to_hi().to(body.span()), } }) } else { @@ -1539,7 +1554,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, generics, ty, expr)) + Ok((ident, generics, ty, body)) } /// We were supposed to parse `":" $ty` but the `:` or the type was missing. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ef42c42f68b37..91453e0c1d42b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2102,19 +2102,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_type_const(&self, hir_id: HirId, attr_span: Span, target: Target) { - let tcx = self.tcx; - if target == Target::AssocConst - && let parent = tcx.parent(hir_id.expect_owner().to_def_id()) - && self.tcx.def_kind(parent) == DefKind::Trait - { + fn check_type_const(&self, _hir_id: HirId, attr_span: Span, target: Target) { + if matches!(target, Target::AssocConst | Target::Const) { return; } else { self.dcx() - .struct_span_err( - attr_span, - "`#[type_const]` must only be applied to trait associated constants", - ) + .struct_span_err(attr_span, "`#[type_const]` must only be applied to const items") .emit(); } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index d1a703fc5d841..0570d2d004862 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -217,7 +217,7 @@ impl<'tcx> ReachableContext<'tcx> { // We can't figure out which value the constant will evaluate to. In // lieu of that, we have to consider everything mentioned in the const // initializer reachable, since it *may* end up in the final value. - Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init), + Err(ErrorHandled::TooGeneric(_)) => self.visit_const_item_rhs(init), // If there was an error evaluating the const, nothing can be reachable // via it, and anyway compilation will fail. Err(ErrorHandled::Reported(..)) => {} @@ -253,8 +253,8 @@ impl<'tcx> ReachableContext<'tcx> { | hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { // Keep going, nothing to get exported } - hir::TraitItemKind::Const(_, Some(body_id)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { + hir::TraitItemKind::Const(_, Some(body)) => self.visit_const_item_rhs(body), + hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { self.visit_nested_body(body_id); } hir::TraitItemKind::Type(..) => {} @@ -262,7 +262,7 @@ impl<'tcx> ReachableContext<'tcx> { } Node::ImplItem(impl_item) => match impl_item.kind { hir::ImplItemKind::Const(_, body) => { - self.visit_nested_body(body); + self.visit_const_item_rhs(body); } hir::ImplItemKind::Fn(_, body) => { if recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 8c6e9f6fb3a40..eed45937ca3a6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2699,7 +2699,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(expr) = expr { // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. - this.resolve_const_body(expr, Some((ident, ConstantItemKind::Static))); + this.resolve_static_body(expr, Some((ident, ConstantItemKind::Static))); } }); self.resolve_define_opaques(define_opaque); @@ -2709,7 +2709,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident, ref generics, ref ty, - ref expr, + ref body, ref define_opaque, .. }) => { @@ -2734,8 +2734,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| this.visit_ty(ty), ); - if let Some(expr) = expr { - this.resolve_const_body(expr, Some((ident, ConstantItemKind::Const))); + if let Some(body) = body { + this.resolve_const_item_rhs( + body, + Some((ident, ConstantItemKind::Const)), + ); } }, ); @@ -3053,7 +3056,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { AssocItemKind::Const(box ast::ConstItem { generics, ty, - expr, + body, define_opaque, .. }) => { @@ -3075,13 +3078,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. - if let Some(expr) = expr { + if let Some(body) = body { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); + this.resolve_const_item_rhs(body, None); } }, ) @@ -3258,7 +3261,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident, generics, ty, - expr, + body, define_opaque, .. }) => { @@ -3300,13 +3303,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_generics(generics); this.visit_ty(ty); - if let Some(expr) = expr { + if let Some(body) = body { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); + this.resolve_const_item_rhs(body, None); } }, ) @@ -3516,7 +3519,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { + fn resolve_static_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) { self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| { this.visit_expr(expr) @@ -3524,6 +3527,23 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }) } + fn resolve_const_item_rhs( + &mut self, + rhs: &'ast ConstItemRhs, + item: Option<(Ident, ConstantItemKind)>, + ) { + self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| match rhs { + ConstItemRhs::TypeConst(anon_const) => { + this.resolve_anon_const(anon_const, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + ConstItemRhs::Body(expr) => { + this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| { + this.visit_expr(expr) + }); + } + }) + } + fn resolve_delegation(&mut self, delegation: &'ast Delegation) { self.smart_resolve_path( delegation.id, diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 800a599be789a..0ff9c05fa90b5 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -333,10 +333,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { let res = if free.kind(infcx.tcx).is_type() { infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead use that rather than evaluating. - super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) - .super_fold_with(self) + infcx + .tcx + .const_of_item(free.def_id) + .instantiate(infcx.tcx, free.args) + .fold_with(self) .into() }; self.depth -= 1; @@ -436,51 +437,40 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx return ct; } - // Doing "proper" normalization of const aliases is inherently cyclic until const items - // are real aliases instead of having bodies. We gate proper const alias handling behind - // mgca to avoid breaking stable code, though this should become the "main" codepath long - // before mgca is stabilized. - // - // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items - // are represented. - if tcx.features().min_generic_const_args() { - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => uv, - _ => return ct.super_fold_with(self), - }; - - let ct = match tcx.def_kind(uv.def) { - DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { - DefKind::Trait => self.normalize_trait_projection(uv.into()), - DefKind::Impl { of_trait: false } => { - self.normalize_inherent_projection(uv.into()) - } - kind => unreachable!( - "unexpected `DefKind` for const alias' resolution's parent def: {:?}", - kind - ), - }, - DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), - kind => { - unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; + + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()).expect_const() } - }; + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(), + DefKind::AnonConst => { + let ct = ct.super_fold_with(self); + super::with_replaced_escaping_bound_vars( + self.selcx.infcx, + &mut self.universes, + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), + ) + } + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - ct.expect_const().super_fold_with(self) - } else { - let ct = ct.super_fold_with(self); - return super::with_replaced_escaping_bound_vars( - self.selcx.infcx, - &mut self.universes, - ct, - |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), - ) - .super_fold_with(self); - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - } + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.super_fold_with(self) } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fab5102427c70..6ac5e6b5c69f6 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -546,7 +546,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() } else { - get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into() }; let mut term = selcx.infcx.resolve_vars_if_possible(term); @@ -2034,14 +2034,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term = if obligation.predicate.kind(tcx).is_type() { tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - ty::EarlyBinder::bind( - get_associated_const_value( - selcx, - obligation.predicate.to_term(tcx).expect_const(), - param_env, - ) - .into(), - ) + tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) }; let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { @@ -2133,15 +2126,3 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } - -fn get_associated_const_value<'tcx>( - selcx: &mut SelectionContext<'_, 'tcx>, - alias_ct: ty::Const<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> ty::Const<'tcx> { - // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type - // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the - // constant is "close enough" to getting the actual rhs of the const item for now even if it might - // lead to some cycles - super::evaluate_const(selcx.infcx, alias_ct, param_env) -} diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6eb0caee1a6f..02438b24ca7f4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -1,9 +1,10 @@ //! Code for the 'normalization' query. This consists of a wrapper //! which folds deeply, invoking the underlying -//! `normalize_canonicalized_projection_ty` query when it encounters projections. +//! `normalize_canonicalized_projection` query when it encounters projections. use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def::DefKind; use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; @@ -255,76 +256,9 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } - ty::Projection | ty::Inherent | ty::Free => { - // See note in `rustc_trait_selection::traits::project` - - let infcx = self.infcx; - let tcx = infcx.tcx; - // Just an optimization: When we don't have escaping bound vars, - // we don't need to replace them with placeholders. - let (data, maps) = if data.has_escaping_bound_vars() { - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - (data, Some((mapped_regions, mapped_types, mapped_consts))) - } else { - (data, None) - }; - let data = data.try_fold_with(self)?; - - let mut orig_values = OriginalQueryValues::default(); - let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); - debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - let result = match kind { - ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), - ty::Free => tcx.normalize_canonicalized_free_alias(c_data), - ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), - kind => unreachable!("did not expect {kind:?} due to match arm above"), - }?; - // We don't expect ambiguity. - if !result.value.is_proven() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.dcx() - .delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}")); - } - return Err(NoSolution); - } - let InferOk { value: result, obligations } = infcx - .instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - )?; - debug!("QueryNormalizer: result = {:#?}", result); - debug!("QueryNormalizer: obligations = {:#?}", obligations); - self.obligations.extend(obligations); - let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - result.normalized_ty, - ) - } else { - result.normalized_ty - }; - // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that - // still has unevaluated consts, so keep normalizing here if that's the case. - // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer - // of type and we need to continue folding it to reveal the TAIT behind it. - if res != ty - && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free) - { - res.try_fold_with(self)? - } else { - res - } - } + ty::Projection | ty::Inherent | ty::Free => self + .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), data.def_id, data.args))? + .expect_type(), }; self.cache.insert(ty, res); @@ -339,12 +273,22 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { return Ok(constant); } - let constant = crate::traits::with_replaced_escaping_bound_vars( - self.infcx, - &mut self.universes, - constant, - |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env), - ); + let uv = match constant.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return constant.try_super_fold_with(self), + }; + + let constant = match self.cx().def_kind(uv.def) { + DefKind::AnonConst => crate::traits::with_replaced_escaping_bound_vars( + self.infcx, + &mut self.universes, + constant, + |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env), + ), + _ => self + .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), uv.def, uv.args))? + .expect_const(), + }; debug!(?constant, ?self.param_env); constant.try_super_fold_with(self) } @@ -361,3 +305,85 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } } + +impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { + fn try_fold_free_or_assoc( + &mut self, + term: ty::AliasTerm<'tcx>, + ) -> Result, NoSolution> { + let infcx = self.infcx; + let tcx = infcx.tcx; + // Just an optimization: When we don't have escaping bound vars, + // we don't need to replace them with placeholders. + let (term, maps) = if term.has_escaping_bound_vars() { + let (term, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, term); + (term, Some((mapped_regions, mapped_types, mapped_consts))) + } else { + (term, None) + }; + let term = term.try_fold_with(self)?; + + let mut orig_values = OriginalQueryValues::default(); + let c_term = infcx.canonicalize_query(self.param_env.and(term), &mut orig_values); + debug!("QueryNormalizer: c_term = {:#?}", c_term); + debug!("QueryNormalizer: orig_values = {:#?}", orig_values); + let result = match term.kind(tcx) { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + tcx.normalize_canonicalized_projection(c_term) + } + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + tcx.normalize_canonicalized_free_alias(c_term) + } + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + tcx.normalize_canonicalized_inherent_projection(c_term) + } + kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => { + unreachable!("did not expect {kind:?} due to match arm above") + } + }?; + // We don't expect ambiguity. + if !result.value.is_proven() { + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_term:?} {result:?}")); + } + return Err(NoSolution); + } + let InferOk { value: result, obligations } = infcx + .instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + result, + )?; + debug!("QueryNormalizer: result = {:#?}", result); + debug!("QueryNormalizer: obligations = {:#?}", obligations); + self.obligations.extend(obligations); + let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result.normalized_term, + ) + } else { + result.normalized_term + }; + // `tcx.normalize_canonicalized_projection` may normalize to a type that + // still has unevaluated consts, so keep normalizing here if that's the case. + // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer + // of type and we need to continue folding it to reveal the TAIT behind it. + if res != term.to_term(tcx) + && (res.as_type().map_or(false, |t| t.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)) + || term.kind(tcx) == ty::AliasTermKind::FreeTy) + { + res.try_fold_with(self) + } else { + Ok(res) + } + } +} diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index db871d4b0aaad..1d7ea9fe00a3f 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -12,18 +12,18 @@ use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { - normalize_canonicalized_projection_ty, + normalize_canonicalized_projection, normalize_canonicalized_free_alias, - normalize_canonicalized_inherent_projection_ty, + normalize_canonicalized_inherent_projection, ..*p }; } -fn normalize_canonicalized_projection_ty<'tcx>( +fn normalize_canonicalized_projection<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal); + debug!("normalize_canonicalized_projection(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -32,7 +32,7 @@ fn normalize_canonicalized_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = traits::normalize_projection_term( + let normalized_term = traits::normalize_projection_term( selcx, param_env, goal.into(), @@ -61,10 +61,7 @@ fn normalize_canonicalized_projection_ty<'tcx>( return Err(NoSolution); } - // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty - // expected a type, but there is the possibility it could've been a const now. - // Maybe change it to a Term later? - Ok(NormalizationResult { normalized_ty: answer.expect_type() }) + Ok(NormalizationResult { normalized_term }) }, ) } @@ -89,17 +86,21 @@ fn normalize_canonicalized_free_alias<'tcx>( }, ); ocx.register_obligations(obligations); - let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args); - Ok(NormalizationResult { normalized_ty }) + let normalized_term = if goal.kind(tcx).is_type() { + tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into() + } else { + tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).into() + }; + Ok(NormalizationResult { normalized_term }) }, ) } -fn normalize_canonicalized_inherent_projection_ty<'tcx>( +fn normalize_canonicalized_inherent_projection<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal); + debug!("normalize_canonicalized_inherent_projection(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -107,7 +108,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = traits::normalize_inherent_projection( + let normalized_term = traits::normalize_inherent_projection( selcx, param_env, goal.into(), @@ -117,7 +118,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( ); ocx.register_obligations(obligations); - Ok(NormalizationResult { normalized_ty: answer.expect_type() }) + Ok(NormalizationResult { normalized_term }) }, ) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 023dbd38d9112..c8d50a64e72c2 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -204,6 +204,7 @@ pub trait Interner: fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; + fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; type AdtDef: AdtDef; fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 481395ffb836c..49557f035e293 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -308,13 +308,21 @@ pub(crate) fn clean_precise_capturing_arg( pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'tcx>, + // Used for mgca representation of const item bodies. + parent_if_item_body: Option, _cx: &mut DocContext<'tcx>, ) -> ConstantKind { match &constant.kind { hir::ConstArgKind::Path(qpath) => { ConstantKind::Path { path: qpath_to_string(qpath).into() } } - hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, + hir::ConstArgKind::Anon(anon) => { + if let Some(def_id) = parent_if_item_body { + ConstantKind::Local { def_id, body: anon.body } + } else { + ConstantKind::Anonymous { body: anon.body } + } + } hir::ConstArgKind::Infer(..) => ConstantKind::Infer, } } @@ -1194,7 +1202,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitItemKind::Const(ty, Some(default)) => { ProvidedAssocConstItem(Box::new(Constant { generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), - kind: ConstantKind::Local { def_id: local_did, body: default }, + kind: clean_const(default, Some(local_did), cx), type_: clean_ty(ty, cx), })) } @@ -1244,7 +1252,7 @@ pub(crate) fn clean_impl_item<'tcx>( let inner = match impl_.kind { hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant { generics: clean_generics(impl_.generics, cx), - kind: ConstantKind::Local { def_id: local_did, body: expr }, + kind: clean_const(expr, Some(local_did), cx), type_: clean_ty(ty, cx), })), hir::ImplItemKind::Fn(ref sig, body) => { @@ -2517,7 +2525,7 @@ fn clean_generic_args<'tcx>( hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)), hir::GenericArg::Const(ct) => { - GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx))) + GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), None, cx))) } hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) @@ -2786,10 +2794,10 @@ fn clean_maybe_renamed_item<'tcx>( mutability, expr: Some(body_id), }), - ItemKind::Const(_, generics, ty, body_id) => ConstantItem(Box::new(Constant { + ItemKind::Const(_, generics, ty, body) => ConstantItem(Box::new(Constant { generics: clean_generics(generics, cx), type_: clean_ty(ty, cx), - kind: ConstantKind::Local { body: body_id, def_id }, + kind: clean_const(body, Some(def_id), cx), })), ItemKind::TyAlias(_, generics, ty) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 751e9b0034277..590805c5d00de 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -7,8 +7,7 @@ use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; -use rustc_hir as hir; -use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource}; +use rustc_hir::{self as hir, AnonConst, Block, BlockCheckMode, ConstArg, ConstArgKind, ItemKind, Node, UnsafeSource}; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -202,6 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }; let item_has_safety_comment = item_has_safety_comment(cx, item); +<<<<<<< HEAD match item_has_safety_comment { HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)), HasSafetyComment::No => check_has_no_safety_comment(cx, item), @@ -209,6 +209,163 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } } } +||||||| parent of ed062304ce5 (mgca: Add ConstArg representation for const items) + match (&item.kind, item_has_safety_comment) { + // lint unsafe impl without safety comment + (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => { + if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) + && !is_unsafe_from_proc_macro(cx, item.span) + { + let source_map = cx.tcx.sess.source_map(); + let span = if source_map.is_multiline(item.span) { + source_map.span_until_char(item.span, '\n') + } else { + item.span + }; + + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe impl missing a safety comment", + |diag| { + diag.help("consider adding a safety comment on the preceding line"); + }, + ); + } + }, + // lint safe impl with unnecessary safety comment + (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + let (span, help_span) = mk_spans(pos); + + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + "impl has unnecessary safety comment", + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, + (ItemKind::Impl(_), _) => {}, + // const and static items only need a safety comment if their body is an unsafe block, lint otherwise + (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { + let body = cx.tcx.hir_body(body); + if !matches!( + body.value.kind, hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + ) { + let (span, help_span) = mk_spans(pos); + + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + format!( + "{} has unnecessary safety comment", + cx.tcx.def_descr(item.owner_id.to_def_id()), + ), + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + } + }, + // Aside from unsafe impls and consts/statics with an unsafe block, items in general + // do not have safety invariants that need to be documented, so lint those. + (_, HasSafetyComment::Yes(pos)) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + let (span, help_span) = mk_spans(pos); +======= + match (&item.kind, item_has_safety_comment) { + // lint unsafe impl without safety comment + (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => { + if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) + && !is_unsafe_from_proc_macro(cx, item.span) + { + let source_map = cx.tcx.sess.source_map(); + let span = if source_map.is_multiline(item.span) { + source_map.span_until_char(item.span, '\n') + } else { + item.span + }; + + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe impl missing a safety comment", + |diag| { + diag.help("consider adding a safety comment on the preceding line"); + }, + ); + } + }, + // lint safe impl with unnecessary safety comment + (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + let (span, help_span) = mk_spans(pos); + + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + "impl has unnecessary safety comment", + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, + (ItemKind::Impl(_), _) => {}, + // const and static items only need a safety comment if their body is an unsafe block, lint otherwise + ( + &ItemKind::Const( + .., + &ConstArg { + kind: ConstArgKind::Anon(&AnonConst { body, .. }), + .. + }, + ) + | &ItemKind::Static(.., body), + HasSafetyComment::Yes(pos), + ) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { + let body = cx.tcx.hir_body(body); + if !matches!( + body.value.kind, hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + ) { + let (span, help_span) = mk_spans(pos); + + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + format!( + "{} has unnecessary safety comment", + cx.tcx.def_descr(item.owner_id.to_def_id()), + ), + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + } + }, + // Aside from unsafe impls and consts/statics with an unsafe block, items in general + // do not have safety invariants that need to be documented, so lint those. + (_, HasSafetyComment::Yes(pos)) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + let (span, help_span) = mk_spans(pos); +>>>>>>> ed062304ce5 (mgca: Add ConstArg representation for const items) fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) { match &item.kind { 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 ad69e6eb184e1..9df9588e84ac7 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -358,7 +358,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: li, generics: lg, ty: lt, - expr: le, + body: lb, define_opaque: _, }), Const(box ConstItem { @@ -366,7 +366,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: ri, generics: rg, ty: rt, - expr: re, + body: rb, define_opaque: _, }), ) => { @@ -374,7 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_deref(), re.as_deref()) + && both(lb.as_deref(), rb.as_deref(), |l, r| eq_anon_const(l, r)) }, ( Fn(box ast::Fn { @@ -595,7 +595,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: li, generics: lg, ty: lt, - expr: le, + body: lb, define_opaque: _, }), Const(box ConstItem { @@ -603,7 +603,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: ri, generics: rg, ty: rt, - expr: re, + body: rb, define_opaque: _, }), ) => { @@ -611,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_deref(), re.as_deref()) + && both(lb.as_deref(), rb.as_deref(), |l, r| eq_anon_const(l, r)) }, ( Fn(box ast::Fn { diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 75e468b35256c..526b4bcfbae74 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2022,30 +2022,30 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind - { - ast::ItemKind::Static(s) => ( - None, - "static", - s.safety, - s.ident, - &s.ty, - s.mutability, - &s.expr, - None, - ), - ast::ItemKind::Const(c) => ( - Some(c.defaultness), - "const", - ast::Safety::Default, - c.ident, - &c.ty, - ast::Mutability::Not, - &c.expr, - Some(&c.generics), - ), - _ => unreachable!(), - }; + let (defaultness, prefix, safety, ident, ty, mutability, expr_opt, generics) = + match &item.kind { + ast::ItemKind::Static(s) => ( + None, + "static", + s.safety, + s.ident, + &s.ty, + s.mutability, + s.expr.as_ref(), + None, + ), + ast::ItemKind::Const(c) => ( + Some(c.defaultness), + "const", + ast::Safety::Default, + c.ident, + &c.ty, + ast::Mutability::Not, + c.body.as_ref().map(|ct| &ct.value), + Some(&c.generics), + ), + _ => unreachable!(), + }; StaticParts { prefix, safety, @@ -2054,15 +2054,15 @@ impl<'a> StaticParts<'a> { generics, ty, mutability, - expr_opt: expr.as_ref(), + expr_opt, defaultness, span: item.span, } } pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self { - let (defaultness, ty, expr_opt, generics) = match &ti.kind { - ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), + let (defaultness, ty, body_opt, generics) = match &ti.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.body, Some(&c.generics)), _ => unreachable!(), }; StaticParts { @@ -2073,15 +2073,15 @@ impl<'a> StaticParts<'a> { generics, ty, mutability: ast::Mutability::Not, - expr_opt: expr_opt.as_ref(), + expr_opt: body_opt.as_ref().map(|ct| &ct.value), defaultness: Some(defaultness), span: ti.span, } } pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self { - let (defaultness, ty, expr, generics) = match &ii.kind { - ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), + let (defaultness, ty, body, generics) = match &ii.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.body, Some(&c.generics)), _ => unreachable!(), }; StaticParts { @@ -2092,7 +2092,7 @@ impl<'a> StaticParts<'a> { generics, ty, mutability: ast::Mutability::Not, - expr_opt: expr.as_ref(), + expr_opt: body.as_ref().map(|ct| &ct.value), defaultness: Some(defaultness), span: ii.span, } diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index ac085864ff09f..d433af6bdd57d 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -1,17 +1,27 @@ // We used to say "ambiguous associated type" on ambiguous associated consts. // Ensure that we now use the correct label. -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait0: Parent0 + Parent0 {} -trait Parent0 { const K: (); } +trait Parent0 { + #[type_const] + const K: (); +} fn take0(_: impl Trait0) {} //~^ ERROR ambiguous associated constant `K` in bounds of `Trait0` trait Trait1: Parent1 + Parent2 {} -trait Parent1 { const C: i32; } -trait Parent2 { const C: &'static str; } +trait Parent1 { + #[type_const] + const C: i32; +} +trait Parent2 { + #[type_const] + const C: &'static str; +} fn take1(_: impl Trait1) {} //~^ ERROR ambiguous associated constant `C` in bounds of `Trait1` diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr index aa1db4cb032ef..3541664d1c6a7 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr @@ -1,12 +1,12 @@ error[E0222]: ambiguous associated constant `K` in bounds of `Trait0` - --> $DIR/assoc-const-eq-ambiguity.rs:9:25 + --> $DIR/assoc-const-eq-ambiguity.rs:13:25 | -LL | trait Parent0 { const K: (); } - | ----------- - | | - | ambiguous `K` from `Parent0` - | ambiguous `K` from `Parent0` -LL | +LL | const K: (); + | ----------- + | | + | ambiguous `K` from `Parent0` + | ambiguous `K` from `Parent0` +... LL | fn take0(_: impl Trait0) {} | ^^^^^^^^^^ ambiguous associated constant `K` | @@ -17,13 +17,14 @@ LL | fn take0(_: impl Trait0) {} T: Parent0::K = { () } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` - --> $DIR/assoc-const-eq-ambiguity.rs:16:25 + --> $DIR/assoc-const-eq-ambiguity.rs:26:25 | -LL | trait Parent1 { const C: i32; } - | ------------ ambiguous `C` from `Parent1` -LL | trait Parent2 { const C: &'static str; } - | --------------------- ambiguous `C` from `Parent2` -LL | +LL | const C: i32; + | ------------ ambiguous `C` from `Parent1` +... +LL | const C: &'static str; + | --------------------- ambiguous `C` from `Parent2` +... LL | fn take1(_: impl Trait1) {} | ^^^^^^^ ambiguous associated constant `C` diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index e583b12b1d701..f6240ead0b9bd 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -1,8 +1,10 @@ // Check that we eventually catch types of assoc const bounds // (containing late-bound vars) that are ill-formed. -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait { + #[type_const] const K: T; } diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 42e084f39c01e..b629bb4d3f8c7 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13 | LL | K = { () } | ^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13 | LL | K = { () } | ^^^^^^ @@ -13,7 +13,7 @@ LL | K = { () } = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `Project` is not general enough - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:10:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13 | LL | _: impl Trait< | _____________^ diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index 7fc6d564ca444..36b3d8a648fd8 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -3,9 +3,11 @@ // //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait { + #[type_const] const K: T; } diff --git a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs index 4b6de6f56d558..22a03e47b2f76 100644 --- a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs +++ b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs @@ -4,9 +4,13 @@ // // issue: //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] -pub trait TraitA { const K: u8 = 0; } +pub trait TraitA { + #[type_const] + const K: u8 = 0; +} pub trait TraitB {} impl TraitA for () {} diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 6db1e85ccfa6a..3f48b3bfbb6d1 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -1,8 +1,10 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait<'a> { + #[type_const] const K: &'a (); } diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index 349fddcafe8b7..d6a7eb6cfc7d9 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:9:35 + --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35 | LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index 06fd0a024f006..5b0438e95695c 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -1,8 +1,10 @@ // Regression test for issue #108271. // Detect and reject generic params in the type of assoc consts used in an equality bound. -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait<'a, T: 'a, const N: usize> { + #[type_const] const K: &'a [T; N]; } @@ -21,6 +23,7 @@ fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} //~| NOTE `K` has type `&'r [A; Q]` trait Project { + #[type_const] const SELF: Self; } diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index 6b7b714fff10a..7ba1d638baa88 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:9:61 + --> $DIR/assoc-const-eq-param-in-ty.rs:11:61 | LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} | -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r` @@ -7,7 +7,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} } = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:9:61 + --> $DIR/assoc-const-eq-param-in-ty.rs:11:61 | LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} | - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A` @@ -15,7 +15,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} } = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:9:61 + --> $DIR/assoc-const-eq-param-in-ty.rs:11:61 | LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} | - ^ its type must not depend on the const parameter `Q` @@ -25,7 +25,7 @@ LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} } = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:27:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:30:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------ @@ -34,7 +34,7 @@ LL | fn take1(_: impl Project) {} | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:32:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:35:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -44,7 +44,7 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | trait Iface<'r> { | -- the lifetime parameter `'r` is defined here @@ -55,7 +55,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> | ^ its type must not depend on `Self` @@ -63,7 +63,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -73,7 +73,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | trait Iface<'r> { | -- the lifetime parameter `'r` is defined here @@ -85,7 +85,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> | ^ its type must not depend on `Self` @@ -94,7 +94,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:41:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:52 | LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs index d5d724c9b1537..301ddf2d01047 100644 --- a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -3,11 +3,13 @@ //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait: SuperTrait {} trait SuperTrait: SuperSuperTrait {} trait SuperSuperTrait { + #[type_const] const K: T; } diff --git a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs index 76df014ccd9bd..febd838e2c2ee 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs @@ -5,16 +5,19 @@ //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait Trait: SuperTrait { type N; type Q; + #[type_const] const N: usize; } trait SuperTrait { + #[type_const] const Q: &'static str; } diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 5b272cfeb0c28..4eed8bba53b1d 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -1,14 +1,16 @@ //@ run-pass -#![feature(associated_const_equality)] -#![allow(unused)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(unused, incomplete_features)] pub trait Foo { + #[type_const] const N: usize; } pub struct Bar; impl Foo for Bar { + #[type_const] const N: usize = 3; } diff --git a/tests/ui/associated-consts/equality-unused-issue-126729.rs b/tests/ui/associated-consts/equality-unused-issue-126729.rs index 1482b874b9d69..35b49314b5f59 100644 --- a/tests/ui/associated-consts/equality-unused-issue-126729.rs +++ b/tests/ui/associated-consts/equality-unused-issue-126729.rs @@ -1,25 +1,32 @@ //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] #![deny(dead_code)] trait Tr { + #[type_const] const I: i32; } impl Tr for () { + #[type_const] const I: i32 = 1; } fn foo() -> impl Tr {} trait Tr2 { + #[type_const] const J: i32; + #[type_const] const K: i32; } impl Tr2 for () { + #[type_const] const J: i32 = 1; + #[type_const] const K: i32 = 1; } @@ -27,10 +34,12 @@ fn foo2() -> impl Tr2 {} mod t { pub trait Tr3 { + #[type_const] const L: i32; } impl Tr3 for () { + #[type_const] const L: i32 = 1; } } diff --git a/tests/ui/associated-consts/issue-102335-const.rs b/tests/ui/associated-consts/issue-102335-const.rs index fd922cd0f1d89..f9b816fd3bc95 100644 --- a/tests/ui/associated-consts/issue-102335-const.rs +++ b/tests/ui/associated-consts/issue-102335-const.rs @@ -1,4 +1,5 @@ -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] trait T { type A: S = 34>; @@ -7,6 +8,7 @@ trait T { } trait S { + #[type_const] const C: i32; } diff --git a/tests/ui/associated-consts/issue-102335-const.stderr b/tests/ui/associated-consts/issue-102335-const.stderr index cf96c8cf8eb9d..536e39e5522d7 100644 --- a/tests/ui/associated-consts/issue-102335-const.stderr +++ b/tests/ui/associated-consts/issue-102335-const.stderr @@ -1,5 +1,5 @@ error[E0229]: associated item constraints are not allowed here - --> $DIR/issue-102335-const.rs:4:17 + --> $DIR/issue-102335-const.rs:5:17 | LL | type A: S = 34>; | ^^^^^^^^ associated item constraint not allowed here @@ -11,7 +11,7 @@ LL + type A: S; | error[E0229]: associated item constraints are not allowed here - --> $DIR/issue-102335-const.rs:4:17 + --> $DIR/issue-102335-const.rs:5:17 | LL | type A: S = 34>; | ^^^^^^^^ associated item constraint not allowed here diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index efd7e13e4bcdc..0284369f4d658 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -1,8 +1,10 @@ //@ check-pass -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] pub trait Trait { + #[type_const] const ASSOC: usize; } diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs index b1a0f39962b61..7f3304f076561 100644 --- a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs +++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs @@ -1,8 +1,10 @@ -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] // Issue 110549 pub trait TraitWAssocConst { + #[type_const] const A: usize; } diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr b/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr index 91bfcf29cb37f..232b15b7e981a 100644 --- a/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr +++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `::A == 32` - --> $DIR/projection-unspecified-but-bounded.rs:12:11 + --> $DIR/projection-unspecified-but-bounded.rs:14:11 | LL | foo::(); | ^ expected `32`, found `::A` @@ -7,7 +7,7 @@ LL | foo::(); = note: expected constant `32` found constant `::A` note: required by a bound in `foo` - --> $DIR/projection-unspecified-but-bounded.rs:9:28 + --> $DIR/projection-unspecified-but-bounded.rs:11:28 | LL | fn foo>() {} | ^^^^^^ required by this bound in `foo` diff --git a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr b/tests/ui/associated-type-bounds/const-projection-err.gce.stderr index 0b6207074979a..9ad851d188d37 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr +++ b/tests/ui/associated-type-bounds/const-projection-err.gce.stderr @@ -1,24 +1,15 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-projection-err.rs:4:26 - | -LL | #![cfg_attr(gce, feature(generic_const_exprs))] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:14:11 + --> $DIR/const-projection-err.rs:16:11 | LL | foo::(); | ^ expected `0`, found `1` | note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:11:28 + --> $DIR/const-projection-err.rs:13:28 | LL | fn foo>() {} | ^^^^^ required by this bound in `foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index 22f1897c07f15..80845ec3ee86e 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,10 +1,12 @@ //@ revisions: stock gce -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] +#![allow(incomplete_features)] + #![cfg_attr(gce, feature(generic_const_exprs))] -//[gce]~^ WARN the feature `generic_const_exprs` is incomplete trait TraitWAssocConst { + #[type_const] const A: usize; } diff --git a/tests/ui/associated-type-bounds/const-projection-err.stock.stderr b/tests/ui/associated-type-bounds/const-projection-err.stock.stderr index e782571c7dea5..0cacec26aaeef 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.stock.stderr +++ b/tests/ui/associated-type-bounds/const-projection-err.stock.stderr @@ -1,13 +1,13 @@ error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:14:11 + --> $DIR/const-projection-err.rs:16:11 | LL | foo::(); - | ^ expected `1`, found `::A` + | ^ expected `1`, found `0` | = note: expected constant `1` - found constant `::A` + found constant `0` note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:11:28 + --> $DIR/const-projection-err.rs:13:28 | LL | fn foo>() {} | ^^^^^ required by this bound in `foo` diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 01cc05f2545f1..72c1ab559bdf0 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,6 +1,12 @@ //@ edition: 2024 -#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)] +#![feature( + associated_const_equality, + min_generic_const_args, + type_alias_impl_trait, + return_type_notation +)] +#![expect(incomplete_features)] #![allow(refining_impl_trait_internal)] use std::iter; @@ -45,6 +51,7 @@ fn mismatch_2() -> impl Iterator { trait Trait { type Gat; + #[type_const] const ASSOC: i32; fn foo() -> impl Sized; @@ -53,6 +60,7 @@ trait Trait { impl Trait for () { type Gat = (); + #[type_const] const ASSOC: i32 = 3; fn foo() {} @@ -61,6 +69,7 @@ impl Trait for () { impl Trait for u32 { type Gat = (); + #[type_const] const ASSOC: i32 = 4; fn foo() -> u32 { @@ -79,6 +88,7 @@ type MustFail = dyn Iterator; //~| ERROR conflicting associated type bounds trait Trait2 { + #[type_const] const ASSOC: u32; } diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 1737d0dc5a385..a54425c3a2956 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:9:5 + --> $DIR/duplicate-bound-err.rs:15:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:13:5 + --> $DIR/duplicate-bound-err.rs:19:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:17:5 + --> $DIR/duplicate-bound-err.rs:23:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | +++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:21:51 + --> $DIR/duplicate-bound-err.rs:27:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:23:51 + --> $DIR/duplicate-bound-err.rs:29:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:25:57 + --> $DIR/duplicate-bound-err.rs:31:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:28:14 + --> $DIR/duplicate-bound-err.rs:34:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:30:14 + --> $DIR/duplicate-bound-err.rs:36:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:32:14 + --> $DIR/duplicate-bound-err.rs:38:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:35:18 + --> $DIR/duplicate-bound-err.rs:41:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:40:20 + --> $DIR/duplicate-bound-err.rs:46:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:100:17 + --> $DIR/duplicate-bound-err.rs:110:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:77:42 + --> $DIR/duplicate-bound-err.rs:86:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:77:17 + --> $DIR/duplicate-bound-err.rs:86:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:85:43 + --> $DIR/duplicate-bound-err.rs:95:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:85:18 + --> $DIR/duplicate-bound-err.rs:95:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:89:43 + --> $DIR/duplicate-bound-err.rs:99:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:92:43 + --> $DIR/duplicate-bound-err.rs:102:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:100:17 + --> $DIR/duplicate-bound-err.rs:110:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:96:31 + --> $DIR/duplicate-bound-err.rs:106:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:108:16 + --> $DIR/duplicate-bound-err.rs:118:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -179,13 +179,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:71:32 + --> $DIR/duplicate-bound-err.rs:80:32 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:109:16 + --> $DIR/duplicate-bound-err.rs:119:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -193,13 +193,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:71:44 + --> $DIR/duplicate-bound-err.rs:80:44 | LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:110:22 + --> $DIR/duplicate-bound-err.rs:120:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -209,13 +209,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:73:46 + --> $DIR/duplicate-bound-err.rs:82:46 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:111:22 + --> $DIR/duplicate-bound-err.rs:121:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -225,13 +225,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:73:35 + --> $DIR/duplicate-bound-err.rs:82:35 | LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:112:20 + --> $DIR/duplicate-bound-err.rs:122:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,13 +241,13 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:75:75 + --> $DIR/duplicate-bound-err.rs:84:75 | LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:113:20 + --> $DIR/duplicate-bound-err.rs:123:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -257,7 +257,7 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:75:48 + --> $DIR/duplicate-bound-err.rs:84:48 | LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} | ^^^^^^^^^ required by this bound in `uncallable_rtn` diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 696710d76f6df..3f40e429260f0 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -1,7 +1,8 @@ //@ edition: 2024 //@ run-pass -#![feature(associated_const_equality, return_type_notation)] +#![feature(associated_const_equality, min_generic_const_args, return_type_notation)] +#![expect(incomplete_features)] #![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)] use std::iter; @@ -188,6 +189,7 @@ trait Tra3 { trait Trait { type Gat; + #[type_const] const ASSOC: i32; fn foo() -> impl Sized; @@ -196,6 +198,7 @@ trait Trait { impl Trait for () { type Gat = (); + #[type_const] const ASSOC: i32 = 3; fn foo() {} diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs index dc42e00c2e834..3973c7af15b49 100644 --- a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs +++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs @@ -1,14 +1,18 @@ -#![feature(associated_const_equality, generic_const_items)] +//@ check-pass + +#![feature(associated_const_equality, min_generic_const_args, generic_const_items)] #![expect(incomplete_features)] // Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even // though it contained inference variables, which would cause ICEs. trait Foo { + #[type_const] const ASSOC: u32; } impl Foo for () { + #[type_const] const ASSOC: u32 = N; } @@ -16,9 +20,4 @@ fn bar = 10>>() {} fn main() { bar::<_, ()>(); - //~^ ERROR: type mismatch resolving `<() as Foo>::ASSOC<_> == 10` - - // FIXME(mgca): - // FIXME(associated_const_equality): - // This ought to start compiling once const items are aliases rather than bodies } diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr deleted file mode 100644 index 00741c901e4c1..0000000000000 --- a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0271]: type mismatch resolving `<() as Foo>::ASSOC<_> == 10` - --> $DIR/equality_bound_with_infer.rs:18:14 - | -LL | bar::<_, ()>(); - | ^^ expected `10`, found `<() as Foo>::ASSOC::<_>` - | - = note: expected constant `10` - found constant `<() as Foo>::ASSOC::<_>` -note: required by a bound in `bar` - --> $DIR/equality_bound_with_infer.rs:15:29 - | -LL | fn bar = 10>>() {} - | ^^^^^^^^^^^^^ required by this bound in `bar` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs index 99318ef75984e..edadcd7c80ed2 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -19,7 +19,7 @@ impl Trait for () where (U,): AssocConst {} fn foo() where (): Trait, - //~^ ERROR type mismatch resolving + //~^ ERROR type annotations needed { } diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr index e6799ec5c3aa4..4106c500215b9 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -14,26 +14,13 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self LL | impl Trait for () where (U,): AssocConst {} | ^ unconstrained type parameter -error[E0271]: type mismatch resolving `<(_,) as AssocConst>::A == 0` +error[E0282]: type annotations needed --> $DIR/unconstrained_impl_param.rs:21:5 | LL | (): Trait, - | ^^^^^^^^^ expected `0`, found `<(_,) as AssocConst>::A` - | - = note: expected constant `0` - found constant `<(_,) as AssocConst>::A` -note: required for `()` to implement `Trait` - --> $DIR/unconstrained_impl_param.rs:15:9 - | -LL | impl Trait for () where (U,): AssocConst {} - | ^^^^^ ^^ --------- unsatisfied trait bound introduced here - = help: see issue #48214 -help: add `#![feature(trivial_bounds)]` to the crate attributes to enable - | -LL + #![feature(trivial_bounds)] - | + | ^^^^^^^^^ cannot infer type for type parameter `U` error: aborting due to 3 previous errors -Some errors have detailed explanations: E0207, E0271, E0658. +Some errors have detailed explanations: E0207, E0282, E0658. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/const-generics/mgca/bad-type_const-syntax.rs b/tests/ui/const-generics/mgca/bad-type_const-syntax.rs index 1e9673a56b563..bb5bdb8d7c4cf 100644 --- a/tests/ui/const-generics/mgca/bad-type_const-syntax.rs +++ b/tests/ui/const-generics/mgca/bad-type_const-syntax.rs @@ -9,8 +9,7 @@ struct S; impl Tr for S { #[type_const] - //~^ ERROR must only be applied to trait associated constants - //~| ERROR experimental + //~^ ERROR experimental const N: usize = 0; } diff --git a/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr b/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr index 125c778ef1cd3..df442c22241b9 100644 --- a/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr +++ b/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr @@ -27,13 +27,7 @@ LL | #[type_const()] | | didn't expect any arguments here | help: must be of the form: `#[type_const]` -error: `#[type_const]` must only be applied to trait associated constants - --> $DIR/bad-type_const-syntax.rs:11:5 - | -LL | #[type_const] - | ^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0565, E0658. For more information about an error, try `rustc --explain E0565`. diff --git a/tests/ui/const-generics/mgca/projection-error.rs b/tests/ui/const-generics/mgca/projection-error.rs index d1c4fa8a492d3..edb6db0980844 100644 --- a/tests/ui/const-generics/mgca/projection-error.rs +++ b/tests/ui/const-generics/mgca/projection-error.rs @@ -7,6 +7,7 @@ pub trait Tr { + #[type_const] const SIZE: usize; } diff --git a/tests/ui/const-generics/mgca/projection-error.stderr b/tests/ui/const-generics/mgca/projection-error.stderr index e6888351da13a..e60acf9144b5c 100644 --- a/tests/ui/const-generics/mgca/projection-error.stderr +++ b/tests/ui/const-generics/mgca/projection-error.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `T` in this scope - --> $DIR/projection-error.rs:13:17 + --> $DIR/projection-error.rs:14:17 | LL | pub trait Tr { | --------------- similarly named trait `Tr` defined here @@ -17,7 +17,7 @@ LL | fn mk_array(_x: T) -> [(); >::SIZE] {} | +++ error[E0412]: cannot find type `T` in this scope - --> $DIR/projection-error.rs:13:29 + --> $DIR/projection-error.rs:14:29 | LL | pub trait Tr { | --------------- similarly named trait `Tr` defined here diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index 2607013ec6335..57b748a6b4756 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -1,6 +1,6 @@ // ICE: assertion failed: !value.has_infer() // issue: rust-lang/rust#115806 -#![feature(associated_const_equality)] +#![feature(associated_const_equality, min_generic_const_args)] #![allow(incomplete_features)] pub struct NoPin; @@ -8,6 +8,7 @@ pub struct NoPin; impl Pins for NoPin {} pub trait PinA { + #[type_const] const A: &'static () = &(); } diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr index 9a9baaddcba3a..34546349592f5 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` - --> $DIR/assoc-const-no-infer-ice-115806.rs:16:1 + --> $DIR/assoc-const-no-infer-ice-115806.rs:17:1 | LL | impl Pins for NoPin {} | --------------------------- first implementation here diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index c0179f02fd2eb..0620998188b26 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -1,17 +1,24 @@ //@ check-pass -#![feature(generic_const_items, associated_const_equality, adt_const_params)] +#![feature(generic_const_items, min_generic_const_args)] +#![feature(associated_const_equality, adt_const_params)] #![allow(incomplete_features)] trait Owner { + #[type_const] const C: u32; + #[type_const] const K: u32; + #[type_const] const Q: Maybe; } impl Owner for () { + #[type_const] const C: u32 = N; - const K: u32 = N + 1; + #[type_const] + const K: u32 = 99 + 1; + #[type_const] const Q: Maybe = Maybe::Nothing; } diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs index f4cde1d62b2c9..edea6f75444f4 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -1,12 +1,15 @@ // Regression test for #140571. The compiler used to ICE -#![feature(associated_const_equality, specialization)] +#![feature(associated_const_equality, min_generic_const_args, specialization)] //~^ WARN the feature `specialization` is incomplete +//~| WARN the feature `min_generic_const_args` is incomplete pub trait IsVoid { + #[type_const] const IS_VOID: bool; } impl IsVoid for T { + #[type_const] default const IS_VOID: bool = false; } diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr index a26b30fbb633c..bf15d0fae4e55 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -1,21 +1,29 @@ -warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes +warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39 | -LL | #![feature(associated_const_equality, specialization)] - | ^^^^^^^^^^^^^^ +LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:63 + | +LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^ | = note: see issue #31844 for more information = help: consider using `min_specialization` instead, which is more stable and complete - = note: `#[warn(incomplete_features)]` on by default error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()` - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:21:1 | LL | impl Maybe for T {} | ---------------------- first implementation here LL | impl Maybe for () where T: NotVoid + ?Sized {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0119`.