diff options
Diffstat (limited to 'compiler')
210 files changed, 2210 insertions, 1643 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 17b73468a31..dd4321bea1b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2947,6 +2947,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct ConstItem { pub defaultness: Defaultness, + pub generics: Generics, pub ty: P<Ty>, pub expr: Option<P<Expr>>, } @@ -3058,6 +3059,7 @@ impl ItemKind { match self { Self::Fn(box Fn { generics, .. }) | Self::TyAlias(box TyAlias { generics, .. }) + | Self::Const(box ConstItem { generics, .. }) | Self::Enum(_, generics) | Self::Struct(_, generics) | Self::Union(_, generics) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 15fe29580c2..8b9bb1df5dc 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -285,17 +285,17 @@ impl MetaItem { self.kind.value_str() } - fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> + fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> where - I: Iterator<Item = TokenTree>, + I: Iterator<Item = &'a TokenTree>, { // FIXME: Share code with `parse_path`. - let path = match tokens.next().map(TokenTree::uninterpolate) { - Some(TokenTree::Token( - Token { kind: kind @ (token::Ident(..) | token::ModSep), span }, + let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { + Some(&TokenTree::Token( + Token { kind: ref kind @ (token::Ident(..) | token::ModSep), span }, _, )) => 'arm: { - let mut segments = if let token::Ident(name, _) = kind { + let mut segments = if let &token::Ident(name, _) = kind { if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) = tokens.peek() { @@ -308,8 +308,8 @@ impl MetaItem { thin_vec![PathSegment::path_root(span)] }; loop { - if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = - tokens.next().map(TokenTree::uninterpolate) + if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = + tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() { segments.push(PathSegment::from_ident(Ident::new(name, span))); } else { @@ -326,7 +326,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &*nt { + Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), token::Nonterminal::NtPath(path) => (**path).clone(), _ => return None, @@ -354,7 +354,7 @@ impl MetaItemKind { } fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> { - let mut tokens = tokens.into_trees().peekable(); + let mut tokens = tokens.trees().peekable(); let mut result = ThinVec::new(); while tokens.peek().is_some() { let item = NestedMetaItem::from_tokens(&mut tokens)?; @@ -367,12 +367,12 @@ impl MetaItemKind { Some(result) } - fn name_value_from_tokens( - tokens: &mut impl Iterator<Item = TokenTree>, + fn name_value_from_tokens<'a>( + tokens: &mut impl Iterator<Item = &'a TokenTree>, ) -> Option<MetaItemKind> { match tokens.next() { Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => { - MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees()) + MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) } Some(TokenTree::Token(token, _)) => { MetaItemLit::from_token(&token).map(MetaItemKind::NameValue) @@ -381,8 +381,8 @@ impl MetaItemKind { } } - fn from_tokens( - tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>, + fn from_tokens<'a>( + tokens: &mut iter::Peekable<impl Iterator<Item = &'a TokenTree>>, ) -> Option<MetaItemKind> { match tokens.peek() { Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => { @@ -501,9 +501,9 @@ impl NestedMetaItem { self.meta_item().is_some() } - fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem> + fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem> where - I: Iterator<Item = TokenTree>, + I: Iterator<Item = &'a TokenTree>, { match tokens.peek() { Some(TokenTree::Token(token, _)) @@ -513,9 +513,8 @@ impl NestedMetaItem { return Some(NestedMetaItem::Lit(lit)); } Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => { - let inner_tokens = inner_tokens.clone(); tokens.next(); - return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable()); + return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable()); } _ => {} } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 53a9c9a046e..84b56efd325 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1149,10 +1149,11 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>( } fn visit_const_item<T: MutVisitor>( - ConstItem { defaultness, ty, expr }: &mut ConstItem, + ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, visitor: &mut T, ) { visit_defaultness(defaultness, visitor); + visitor.visit_generics(generics); visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 303bdd3a307..4c920e84f86 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -226,7 +226,9 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { .contains(&name) } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +// SAFETY: due to the `Clone` impl below, all fields of all variants other than +// `Interpolated` must impl `Copy`. +#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ Eq, @@ -299,6 +301,19 @@ pub enum TokenKind { Eof, } +impl Clone for TokenKind { + fn clone(&self) -> Self { + // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So + // for all other variants, this implementation of `clone` is just like + // a copy. This is faster than the `derive(Clone)` version which has a + // separate path for every variant. + match self { + Interpolated(nt) => Interpolated(nt.clone()), + _ => unsafe { std::ptr::read(self) }, + } + } +} + #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct Token { pub kind: TokenKind, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index ca4a739abd7..348c37c480f 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -25,6 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::{fmt, iter, mem}; /// When the main Rust parser encounters a syntax-extension invocation, it @@ -98,12 +99,13 @@ impl TokenTree { TokenTree::Token(Token::new(kind, span), Spacing::Joint) } - pub fn uninterpolate(self) -> TokenTree { + pub fn uninterpolate(&self) -> Cow<'_, TokenTree> { match self { - TokenTree::Token(token, spacing) => { - TokenTree::Token(token.uninterpolate().into_owned(), spacing) - } - tt => tt, + TokenTree::Token(token, spacing) => match token.uninterpolate() { + Cow::Owned(token) => Cow::Owned(TokenTree::Token(token, *spacing)), + Cow::Borrowed(_) => Cow::Borrowed(self), + }, + _ => Cow::Borrowed(self), } } } @@ -595,26 +597,21 @@ impl<'t> Iterator for RefTokenTreeCursor<'t> { } } -/// Owning by-value iterator over a [`TokenStream`], that produces `TokenTree` +/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree` /// items. -// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones. +/// +/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to +/// return `&T` from `next`; the need for an explicit lifetime in the `Item` +/// associated type gets in the way. Instead, use `next_ref` (which doesn't +/// involve associated types) for getting individual elements, or +/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for` +/// loop. #[derive(Clone)] pub struct TokenTreeCursor { pub stream: TokenStream, index: usize, } -impl Iterator for TokenTreeCursor { - type Item = TokenTree; - - fn next(&mut self) -> Option<TokenTree> { - self.stream.0.get(self.index).map(|tree| { - self.index += 1; - tree.clone() - }) - } -} - impl TokenTreeCursor { fn new(stream: TokenStream) -> Self { TokenTreeCursor { stream, index: 0 } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d9de5b8e197..aed24e11c4e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -308,8 +308,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { match &item.kind { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) - | ItemKind::Const(box ConstItem { ty, expr, .. }) => { + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, expr); + } + ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + visitor.visit_generics(generics); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } @@ -677,7 +681,8 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_ident(ident); walk_list!(visitor, visit_attribute, attrs); match kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { + AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => { + visitor.visit_generics(generics); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2f58f566c81..5a0474dbc01 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -231,9 +231,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); hir::ItemKind::Static(ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { - let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref()); - hir::ItemKind::Const(ty, body_id) + ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + let (generics, (ty, body_id)) = self.lower_generics( + generics, + Const::No, + id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| this.lower_const_item(ty, span, expr.as_deref()), + ); + hir::ItemKind::Const(ty, generics, body_id) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, @@ -715,11 +721,23 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { - let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); - (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) + AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + let (generics, kind) = self.lower_generics( + &generics, + Const::No, + i.id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |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))); + + hir::TraitItemKind::Const(ty, body) + }, + ); + (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { let asyncness = sig.header.asyncness; @@ -817,14 +835,19 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { - let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - ( - hir::Generics::empty(), - hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), - ) - } + AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( + &generics, + Const::No, + i.id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + + hir::ImplItemKind::Const(ty, body) + }, + ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b0dbc2c2340..c4efad7caf2 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -218,6 +218,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + if !attr.is_doc_comment() + && attr.get_normal_item().path.segments.len() == 2 + && attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic + && !self.features.diagnostic_namespace + { + let msg = "`#[diagnostic]` attribute name space is experimental"; + gate_feature_post!( + self, + diagnostic_namespace, + attr.get_normal_item().path.segments[0].ident.span, + msg + ); + } // Emit errors for non-staged-api crates. if !self.features.staged_api { @@ -556,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); + gate_all!(generic_const_items, "generic const items are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 5c01b7ea70a..d27a44f1206 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -30,10 +30,15 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(ty, mutbl, body) => { - let def = ast::Defaultness::Final; - self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def); - } + ast::ForeignItemKind::Static(ty, mutbl, body) => self.print_item_const( + ident, + Some(*mutbl), + &ast::Generics::default(), + ty, + body.as_deref(), + vis, + ast::Defaultness::Final, + ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, generics, @@ -67,6 +72,7 @@ impl<'a> State<'a> { &mut self, ident: Ident, mutbl: Option<ast::Mutability>, + generics: &ast::Generics, ty: &ast::Ty, body: Option<&ast::Expr>, vis: &ast::Visibility, @@ -82,6 +88,7 @@ impl<'a> State<'a> { }; self.word_space(leading); self.print_ident(ident); + self.print_generic_params(&generics.params); self.word_space(":"); self.print_type(ty); if body.is_some() { @@ -92,6 +99,7 @@ impl<'a> State<'a> { self.word_space("="); self.print_expr(body); } + self.print_where_clause(&generics.where_clause); self.word(";"); self.end(); // end the outer cbox } @@ -158,20 +166,21 @@ impl<'a> State<'a> { self.word(";"); } ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { - let def = ast::Defaultness::Final; self.print_item_const( item.ident, Some(*mutbl), + &ast::Generics::default(), ty, body.as_deref(), &item.vis, - def, + ast::Defaultness::Final, ); } - ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { + ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { self.print_item_const( item.ident, None, + generics, ty, expr.as_deref(), &item.vis, @@ -515,8 +524,16 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { - self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness); + ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + self.print_item_const( + ident, + None, + generics, + ty, + expr.as_deref(), + vis, + *defaultness, + ); } ast::AssocItemKind::Type(box ast::TyAlias { defaultness, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index a4e0e773a81..a2c7e767b4c 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -37,8 +37,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc)); - err.span_label(span, format!("use of borrowed {}", borrow_desc)); + err.span_label(borrow_span, format!("{borrow_desc} is borrowed here")); + err.span_label(span, format!("use of borrowed {borrow_desc}")); err } @@ -51,8 +51,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let via = - |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; + let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_err!( self, new_loan_span, @@ -143,9 +142,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { ); err.span_label( new_loan_span, - format!("{} construction occurs here{}", container_name, opt_via), + format!("{container_name} construction occurs here{opt_via}"), ); - err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via)); + err.span_label(old_loan_span, format!("borrow occurs here{old_opt_via}")); if let Some(previous_end_span) = previous_end_span { err.span_label(previous_end_span, "borrow ends here"); } @@ -173,13 +172,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { opt_via, kind_new, ); - err.span_label( - new_loan_span, - format!("{}borrow occurs here{}", second_borrow_desc, opt_via), - ); + err.span_label(new_loan_span, format!("{second_borrow_desc}borrow occurs here{opt_via}")); err.span_label( old_loan_span, - format!("{} construction occurs here{}", container_name, old_opt_via), + format!("{container_name} construction occurs here{old_opt_via}"), ); if let Some(previous_end_span) = previous_end_span { err.span_label(previous_end_span, "borrow from closure ends here"); @@ -199,8 +195,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { msg_old: &str, old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - let via = - |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; + let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_err!( self, span, @@ -216,22 +211,21 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { if msg_new == "" { // If `msg_new` is empty, then this isn't a borrow of a union field. - err.span_label(span, format!("{} borrow occurs here", kind_new)); - err.span_label(old_span, format!("{} borrow occurs here", kind_old)); + err.span_label(span, format!("{kind_new} borrow occurs here")); + err.span_label(old_span, format!("{kind_old} borrow occurs here")); } else { // If `msg_new` isn't empty, then this a borrow of a union field. err.span_label( span, format!( - "{} borrow of {} -- which overlaps with {} -- occurs here", - kind_new, msg_new, msg_old, + "{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here", ), ); err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old))); } if let Some(old_load_end_span) = old_load_end_span { - err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old)); + err.span_label(old_load_end_span, format!("{kind_old} borrow ends here")); } err } @@ -250,8 +244,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("{} is borrowed here", desc)); - err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc)); + err.span_label(borrow_span, format!("{desc} is borrowed here")); + err.span_label(span, format!("{desc} is assigned to here but it was already borrowed")); err } @@ -330,7 +324,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { optional_adverb_for_moved: &str, moved_path: Option<String>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default(); + let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); struct_span_err!( self, @@ -369,8 +363,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { immutable_place, immutable_section, ); - err.span_label(mutate_span, format!("cannot {}", action)); - err.span_label(immutable_span, format!("value is immutable in {}", immutable_section)); + err.span_label(mutate_span, format!("cannot {action}")); + err.span_label(immutable_span, format!("value is immutable in {immutable_section}")); err } @@ -428,7 +422,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err.span_label( span, - format!("{}s a {} data owned by the current function", return_kind, reference_desc), + format!("{return_kind}s a {reference_desc} data owned by the current function"), ); err @@ -449,8 +443,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \ which is owned by the current {scope}", ); - err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) - .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path)); + err.span_label(capture_span, format!("{borrowed_path} is borrowed here")) + .span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")); err } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 1064b44d2cd..1e89a9f5144 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -360,7 +360,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { return; } let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| { - panic!("could not find BorrowIndex for location {:?}", location); + panic!("could not find BorrowIndex for location {location:?}"); }); trans.gen(index); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 97c3e0b879a..03b90f4ab18 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -653,7 +653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_suggestion_verbose( sugg_span.shrink_to_hi(), "consider assigning a value", - format!(" = {}", assign_value), + format!(" = {assign_value}"), Applicability::MaybeIncorrect, ); } @@ -738,7 +738,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Try to find predicates on *generic params* that would allow copying `ty` let suggestion = if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { - format!(": {}.clone()", symbol) + format!(": {symbol}.clone()") } else { ".clone()".to_owned() }; @@ -1162,8 +1162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if union_type_name != "" { err.note(format!( - "{} is a field of the union `{}`, so it overlaps the field {}", - msg_place, union_type_name, msg_borrow, + "{msg_place} is a field of the union `{union_type_name}`, so it overlaps the field {msg_borrow}", )); } @@ -1353,8 +1352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let Some(trait_did) = tcx.trait_of_item(def_id) && tcx.is_diagnostic_item(sym::Iterator, trait_did) { err.note(format!( - "a for loop advances the iterator for you, the result is stored in `{}`.", - loop_bind + "a for loop advances the iterator for you, the result is stored in `{loop_bind}`." )); err.help("if you want to call `next` on a iterator within the loop, consider using `while let`."); } @@ -1825,7 +1823,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ConstraintCategory::CallArgument(None), var_or_use_span, - &format!("`{}`", name), + &format!("`{name}`"), "block", ), ( @@ -1847,7 +1845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { region_name, category, span, - &format!("`{}`", name), + &format!("`{name}`"), "function", ), ( @@ -1921,14 +1919,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name)); + let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`")); if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) { let region_name = annotation.emit(self, &mut err); err.span_label( borrow_span, - format!("`{}` would have to be valid for `{}`...", name, region_name), + format!("`{name}` would have to be valid for `{region_name}`..."), ); err.span_label( @@ -1939,7 +1937,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.infcx .tcx .opt_item_name(self.mir_def_id().to_def_id()) - .map(|name| format!("function `{}`", name)) + .map(|name| format!("function `{name}`")) .unwrap_or_else(|| { match &self.infcx.tcx.def_kind(self.mir_def_id()) { DefKind::Closure => "enclosing closure", @@ -1974,7 +1972,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name)); + err.span_label(drop_span, format!("`{name}` dropped here while still borrowed")); borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { @@ -2018,22 +2016,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_borrow_across_destructor(borrow_span); let what_was_dropped = match self.describe_place(place.as_ref()) { - Some(name) => format!("`{}`", name), + Some(name) => format!("`{name}`"), None => String::from("temporary value"), }; let label = match self.describe_place(borrow.borrowed_place.as_ref()) { Some(borrowed) => format!( - "here, drop of {D} needs exclusive access to `{B}`, \ - because the type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty, - B = borrowed + "here, drop of {what_was_dropped} needs exclusive access to `{borrowed}`, \ + because the type `{dropped_ty}` implements the `Drop` trait" ), None => format!( - "here is drop of {D}; whose type `{T}` implements the `Drop` trait", - D = what_was_dropped, - T = dropped_ty + "here is drop of {what_was_dropped}; whose type `{dropped_ty}` implements the `Drop` trait" ), }; err.span_label(drop_span, label); @@ -2245,10 +2238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { "local data " }; - ( - format!("{}`{}`", local_kind, place_desc), - format!("`{}` is borrowed here", place_desc), - ) + (format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here")) } else { let root_place = self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); @@ -2350,9 +2340,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_suggestion_verbose( sugg_span, format!( - "to force the {} to take ownership of {} (and any \ - other referenced variables), use the `move` keyword", - kind, captured_var + "to force the {kind} to take ownership of {captured_var} (and any \ + other referenced variables), use the `move` keyword" ), suggestion, Applicability::MachineApplicable, @@ -2360,7 +2349,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match category { ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { - let msg = format!("{} is returned here", kind); + let msg = format!("{kind} is returned here"); err.span_note(constraint_span, msg); } ConstraintCategory::CallArgument(_) => { @@ -2402,21 +2391,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( upvar_span, - format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from), + format!("`{upvar_name}` declared here, outside of the {escapes_from} body"), ); - err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from)); + err.span_label(borrow_span, format!("borrow is only valid in the {escapes_from} body")); if let Some(name) = name { err.span_label( escape_span, - format!("reference to `{}` escapes the {} body here", name, escapes_from), + format!("reference to `{name}` escapes the {escapes_from} body here"), ); } else { - err.span_label( - escape_span, - format!("reference escapes the {} body here", escapes_from), - ); + err.span_label(escape_span, format!("reference escapes the {escapes_from} body here")); } err @@ -2697,10 +2683,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }); if let Some(Ok(instance)) = deref_target { let deref_target_ty = instance.ty(tcx, self.param_env); - err.note(format!( - "borrow occurs due to deref coercion to `{}`", - deref_target_ty - )); + err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); err.span_note(tcx.def_span(instance.def_id()), "deref defined here"); } } @@ -2756,7 +2739,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "cannot assign twice to immutable variable" }; if span != assigned_span && !from_arg { - err.span_label(assigned_span, format!("first assignment to {}", place_description)); + err.span_label(assigned_span, format!("first assignment to {place_description}")); } if let Some(decl) = local_decl && let Some(name) = local_name @@ -2765,7 +2748,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_suggestion( decl.source_info.span, "consider making this binding mutable", - format!("mut {}", name), + format!("mut {name}"), Applicability::MachineApplicable, ); } @@ -3226,7 +3209,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { return_span, } => { let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); - diag.span_label(argument_span, format!("has type `{}`", argument_ty_name)); + diag.span_label(argument_span, format!("has type `{argument_ty_name}`")); let return_ty_name = cx.get_name_for_ty(return_ty, 0); let types_equal = return_ty_name == argument_ty_name; @@ -3253,15 +3236,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { // Region of return type and arguments checked to be the same earlier. let region_name = cx.get_region_name_for_ty(*return_ty, 0); for (_, argument_span) in arguments { - diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); + diag.span_label(*argument_span, format!("has lifetime `{region_name}`")); } - diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,)); + diag.span_label(*return_span, format!("also has lifetime `{region_name}`",)); diag.help(format!( - "use data from the highlighted arguments which match the `{}` lifetime of \ + "use data from the highlighted arguments which match the `{region_name}` lifetime of \ the return type", - region_name, )); region_name diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 87fad9a355d..9916ebca32f 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -202,7 +202,7 @@ trait FactCell { impl<A: Debug> FactCell for A { default fn to_string(&self, _location_table: &LocationTable) -> String { - format!("{:?}", self) + format!("{self:?}") } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 2fd42e2f56a..ba1d31ee002 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1817,8 +1817,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, location: {:?}", - location); + panic!("we don't allow assignments to subslices, location: {location:?}"); } ProjectionElem::Field(..) => { @@ -2017,8 +2016,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.infcx.tcx.sess.delay_span_bug( span, format!( - "Accessing `{:?}` with the kind `{:?}` shouldn't be possible", - place, kind, + "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible", ), ); } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index b5014a3f479..679a19710a7 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -347,7 +347,7 @@ pub(super) fn dump_mir_results<'tcx>( for_each_region_constraint( infcx.tcx, closure_region_requirements, - &mut |msg| writeln!(out, "| {}", msg), + &mut |msg| writeln!(out, "| {msg}"), )?; writeln!(out, "|")?; } @@ -426,7 +426,7 @@ pub(super) fn dump_annotation<'tcx>( }; if !opaque_type_values.is_empty() { - err.note(format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); + err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); } errors.buffer_non_error_diag(err); @@ -439,7 +439,7 @@ fn for_each_region_constraint<'tcx>( ) -> io::Result<()> { for req in &closure_region_requirements.outlives_requirements { let subject = match req.subject { - ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject), + ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"), ClosureOutlivesSubject::Ty(ty) => { format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) } diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 6524b594e44..4d620ac9de6 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -52,7 +52,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { writeln!(out, "|")?; writeln!(out, "| Inference Constraints")?; - self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {}", msg))?; + self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {msg}"))?; Ok(()) } @@ -69,7 +69,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for region in self.definitions.indices() { let value = self.liveness_constraints.region_value_str(region); if value != "{}" { - with_msg(&format!("{:?} live at {}", region, value))?; + with_msg(&format!("{region:?} live at {value}"))?; } } @@ -81,12 +81,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { Locations::All(span) => { ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) } - Locations::Single(loc) => ("Single", format!("{:?}", loc)), + Locations::Single(loc) => ("Single", format!("{loc:?}")), }; - with_msg(&format!( - "{:?}: {:?} due to {:?} at {}({}) ({:?}", - sup, sub, category, name, arg, span - ))?; + with_msg(&format!("{sup:?}: {sub:?} due to {category:?} at {name}({arg}) ({span:?}"))?; } Ok(()) diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 2e15586e03b..a0cf22e935a 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -49,7 +49,7 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { Some(dot::LabelText::LabelStr(Cow::Borrowed("box"))) } fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { - dot::LabelText::LabelStr(format!("{:?}", n).into()) + dot::LabelText::LabelStr(format!("{n:?}").into()) } fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) @@ -100,7 +100,7 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for SccConstraints<'a, 'tcx> { } fn node_label(&'this self, n: &ConstraintSccIndex) -> dot::LabelText<'this> { let nodes = &self.nodes_per_scc[*n]; - dot::LabelText::LabelStr(format!("{:?} = {:?}", n, nodes).into()) + dot::LabelText::LabelStr(format!("{n:?} = {nodes:?}").into()) } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index fbbccc58ad6..30dfb2d919a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -259,7 +259,7 @@ fn sccs_info<'cx, 'tcx>( let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); for (reg_var, origin) in var_to_origin_sorted.into_iter() { - reg_vars_to_origins_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); + reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n")); } debug!("{}", reg_vars_to_origins_str); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 17a4f2d76b6..90bde88f792 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -419,7 +419,7 @@ fn check_opaque_type_parameter_valid( return Err(tcx .sess .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, format!("{} used multiple times", descr)) + .span_note(spans, format!("{descr} used multiple times")) .emit()); } } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 9290e747914..d205862cd3f 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -470,7 +470,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String } push_sep(&mut result); - result.push_str(&format!("{:?}", fr)); + result.push_str(&format!("{fr:?}")); } RegionElement::PlaceholderRegion(placeholder) => { @@ -481,7 +481,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String } push_sep(&mut result); - result.push_str(&format!("{:?}", placeholder)); + result.push_str(&format!("{placeholder:?}")); } } } @@ -497,7 +497,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String fn push_location_range(str: &mut String, location1: Location, location2: Location) { if location1 == location2 { - str.push_str(&format!("{:?}", location1)); + str.push_str(&format!("{location1:?}")); } else { assert_eq!(location1.block, location2.block); str.push_str(&format!( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 78aa513033c..fd4a3ec1a5e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -409,18 +409,12 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() { - // const_trait_impl: use a non-const param env when checking that a FnDef type is well formed. - // this is because the well-formedness of the function does not need to be proved to have `const` - // impls for trait bounds. let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); - let prev = self.cx.param_env; - self.cx.param_env = prev.without_const(); self.cx.normalize_and_prove_instantiated_predicates( def_id, instantiated_predicates, locations, ); - self.cx.param_env = prev; } } } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 6bc4f6fc1fc..1580a6f6dd3 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -255,6 +255,7 @@ pub fn expand_test_or_bench( ast::ItemKind::Const( ast::ConstItem { defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), // test::TestDescAndFn { expr: Some( diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 4c69b9503a2..e4fce30e232 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -363,50 +363,44 @@ pub fn from_fn_attrs<'ll, 'tcx>( if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED) { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - // apply to argument place instead of function - let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]); - to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0)); - let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned; - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { - flags |= AllocKindFlags::Uninitialized; - } else { - flags |= AllocKindFlags::Zeroed; - } - to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags)); + to_add.push(create_alloc_family_attr(cx.llcx)); + // apply to argument place instead of function + let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]); + to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0)); + let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned; + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { + flags |= AllocKindFlags::Uninitialized; + } else { + flags |= AllocKindFlags::Zeroed; } + to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags)); // apply to return place instead of function (unlike all other attributes applied in this function) let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - to_add.push(llvm::CreateAllocKindAttr( - cx.llcx, - AllocKindFlags::Realloc | AllocKindFlags::Aligned, - )); - // applies to argument place instead of function place - let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); - // apply to argument place instead of function - let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]); - to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3)); - } + to_add.push(create_alloc_family_attr(cx.llcx)); + to_add.push(llvm::CreateAllocKindAttr( + cx.llcx, + AllocKindFlags::Realloc | AllocKindFlags::Aligned, + )); + // applies to argument place instead of function place + let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); + // apply to argument place instead of function + let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]); + to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3)); let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) { - if llvm_util::get_version() >= (15, 0, 0) { - to_add.push(create_alloc_family_attr(cx.llcx)); - to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); - // applies to argument place instead of function place - let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); - attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); - } + to_add.push(create_alloc_family_attr(cx.llcx)); + to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free)); + // applies to argument place instead of function place + let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 6df1b708ccd..623c08ce86b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2074,6 +2074,53 @@ fn generic_simd_intrinsic<'ll, 'tcx>( simd_neg: Int => neg, Float => fneg; } + // Unary integer intrinsics + if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_cttz) { + let vec_ty = bx.cx.type_vector( + match *in_elem.kind() { + ty::Int(i) => bx.cx.type_int_from_ty(i), + ty::Uint(i) => bx.cx.type_uint_from_ty(i), + _ => return_error!(InvalidMonomorphization::UnsupportedOperation { + span, + name, + in_ty, + in_elem + }), + }, + in_len as u64, + ); + let intrinsic_name = match name { + sym::simd_bswap => "bswap", + sym::simd_bitreverse => "bitreverse", + sym::simd_ctlz => "ctlz", + sym::simd_cttz => "cttz", + _ => unreachable!(), + }; + let llvm_intrinsic = &format!( + "llvm.{}.v{}i{}", + intrinsic_name, + in_len, + in_elem.int_size_and_signed(bx.tcx()).0.bits(), + ); + + return Ok(if matches!(name, sym::simd_ctlz | sym::simd_cttz) { + let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty); + let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); + bx.call( + fn_ty, + None, + None, + f, + &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)], + None, + ) + } else { + let fn_ty = bx.type_func(&[vec_ty], vec_ty); + let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); + bx.call(fn_ty, None, None, f, &[args[0].immediate()], None) + }); + } + if name == sym::simd_arith_offset { // This also checks that the first operand is a ptr type. let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 4f20fbf2045..6ae738174bf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -507,8 +507,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str .features .split(',') .filter(|v| !v.is_empty() && backend_feature_name(v).is_some()) - // Drop +atomics-32 feature introduced in LLVM 15. - .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0)) .map(String::from), ); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index dc862803274..79c284ecfbf 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -38,6 +38,7 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; use rustc_target::abi::{Align, FIRST_VARIANT}; +use std::cmp; use std::collections::BTreeSet; use std::time::{Duration, Instant}; @@ -682,10 +683,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // are large size variations, this can reduce memory usage significantly. let codegen_units: Vec<_> = { let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>(); - sorted_cgus.sort_by_cached_key(|cgu| cgu.size_estimate()); + sorted_cgus.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate())); let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2); - second_half.iter().rev().interleave(first_half).copied().collect() + first_half.iter().interleave(second_half.iter().rev()).copied().collect() }; // Calculate the CGU reuse diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index ffeff8d079a..d39a7e8a192 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -138,7 +138,10 @@ where err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { ErrorHandled::TooGeneric } - err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(error_reported), + err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar), + err_inval!(Layout(LayoutError::ReferencesError(guar))) => { + ErrorHandled::Reported(guar.into()) + } err_inval!(Layout(layout_error @ LayoutError::SizeOverflow(_))) => { // We must *always* hard error on these, even if the caller wants just a lint. // The `message` makes little sense here, this is a more serious error than the diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 55d719d2703..4c7e9194401 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -52,7 +52,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( trace!( "eval_body_using_ecx: pushing stack frame for global: {}{}", with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())), - cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p)) + cid.promoted.map_or_else(String::new, |p| format!("::promoted[{p:?}]")) ); ecx.push_stack_frame( @@ -228,7 +228,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - assert!(key.param_env.is_const()); // see comment in eval_to_allocation_raw_provider for what we're doing here if key.param_env.reveal() == Reveal::All { let mut key = key; @@ -269,7 +268,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { - assert!(key.param_env.is_const()); // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index fa8253d5e49..cc39387c41f 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -28,15 +28,18 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { && tcx.constness(parent_id) == hir::Constness::Const } -/// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If -/// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic, -/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return -/// `Constness::NotConst`. +/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const, +/// const block, const item or associated const, it is const. If it is a trait impl/function, +/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic +/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`. fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { let node = tcx.hir().get_by_def_id(def_id); match node { - hir::Node::Ctor(_) => hir::Constness::Const, + hir::Node::Ctor(_) + | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const, hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 744dd114ca7..7c1dbddfc26 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -55,7 +55,7 @@ fn slice_branches<'tcx>( place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { - let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {:?}", place)); + let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}")); let mut elems = Vec::with_capacity(n as usize); for i in 0..n { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0e6125388a6..3ac6f07e8b7 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -958,7 +958,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - let param_env = param_env.with_const(); let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?; self.raw_const_to_mplace(val) } @@ -1016,7 +1015,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug match self.place { Place::Local { frame, local, offset } => { let mut allocs = Vec::new(); - write!(fmt, "{:?}", local)?; + write!(fmt, "{local:?}")?; if let Some(offset) = offset { write!(fmt, "+{:#x}", offset.bytes())?; } @@ -1035,7 +1034,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug fmt, " by {} ref {:?}:", match mplace.meta { - MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Meta(meta) => format!(" meta({meta:?})"), MemPlaceMeta::None => String::new(), }, mplace.ptr, @@ -1043,13 +1042,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id)); } LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { - write!(fmt, " {:?}", val)?; + write!(fmt, " {val:?}")?; if let Scalar::Ptr(ptr, _size) = val { allocs.push(ptr.provenance.get_alloc_id()); } } LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { - write!(fmt, " ({:?}, {:?})", val1, val2)?; + write!(fmt, " ({val1:?}, {val2:?})")?; if let Scalar::Ptr(ptr, _size) = val1 { allocs.push(ptr.provenance.get_alloc_id()); } @@ -1065,7 +1064,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug Some(alloc_id) => { write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id)) } - ptr => write!(fmt, " integral by ref: {:?}", ptr), + ptr => write!(fmt, " integral by ref: {ptr:?}"), }, } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4020d96b80e..be7c14f33c2 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -394,17 +394,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // For *all* intrinsics we first check `is_uninhabited` to give a more specific // error message. _ if layout.abi.is_uninhabited() => format!( - "aborted execution: attempted to instantiate uninhabited type `{}`", - ty + "aborted execution: attempted to instantiate uninhabited type `{ty}`" ), ValidityRequirement::Inhabited => bug!("handled earlier"), ValidityRequirement::Zero => format!( - "aborted execution: attempted to zero-initialize type `{}`, which is invalid", - ty + "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" ), ValidityRequirement::UninitMitigated0x01Fill => format!( - "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", - ty + "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" ), ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), }; @@ -420,9 +417,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(input_len, dest_len, "Return vector length must match input length"); assert!( index < dest_len, - "Index `{}` must be in bounds of vector with length {}", - index, - dest_len + "Index `{index}` must be in bounds of vector with length {dest_len}" ); for i in 0..dest_len { @@ -440,9 +435,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (input, input_len) = self.operand_to_simd(&args[0])?; assert!( index < input_len, - "index `{}` must be in bounds of vector with length {}", - index, - input_len + "index `{index}` must be in bounds of vector with length {input_len}" ); self.copy_op( &self.project_index(&input, index)?, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 7b44a20ef03..02d022a2252 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -53,7 +53,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> { match self { MemoryKind::Stack => write!(f, "stack variable"), MemoryKind::CallerLocation => write!(f, "caller location"), - MemoryKind::Machine(m) => write!(f, "{}", m), + MemoryKind::Machine(m) => write!(f, "{m}"), } } } @@ -907,7 +907,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, match self.ecx.memory.alloc_map.get(id) { Some((kind, alloc)) => { // normal alloc - write!(fmt, " ({}, ", kind)?; + write!(fmt, " ({kind}, ")?; write_allocation_track_relocs( &mut *fmt, *self.ecx.tcx, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index d1427b09632..6e57a56b445 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -698,10 +698,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Unevaluated(uv) => { let instance = self.resolve(uv.def, uv.args)?; let cid = GlobalId { instance, promoted: None }; - self.ctfe_query(span, |tcx| { - tcx.eval_to_valtree(self.param_env.with_const().and(cid)) - })? - .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}")) + self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))? + .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}")) } ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => { span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}") diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 49c3b152e1d..eb064578067 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -24,8 +24,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { debug_assert_eq!( Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]), dest.layout.ty, - "type mismatch for result of {:?}", - op, + "type mismatch for result of {op:?}", ); // Write the result to `dest`. if let Abi::ScalarPair(..) = dest.layout.abi { @@ -56,7 +55,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?; - assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op); + assert_eq!(ty, dest.layout.ty, "type mismatch for result of {op:?}"); self.write_scalar(val, dest) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 1f2d04f4008..91341ddacd1 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -178,7 +178,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The operand always has the same type as the result. let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?; let val = self.unary_op(un_op, &val)?; - assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op); + assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}"); self.write_immediate(*val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 4fd5fd13c3c..aee95f70bc2 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -164,14 +164,14 @@ fn write_path(out: &mut String, path: &[PathElem]) { for elem in path.iter() { match elem { - Field(name) => write!(out, ".{}", name), + Field(name) => write!(out, ".{name}"), EnumTag => write!(out, ".<enum-tag>"), - Variant(name) => write!(out, ".<enum-variant({})>", name), + Variant(name) => write!(out, ".<enum-variant({name})>"), GeneratorTag => write!(out, ".<generator-tag>"), GeneratorState(idx) => write!(out, ".<generator-state({})>", idx.index()), - CapturedVar(name) => write!(out, ".<captured-var({})>", name), - TupleElem(idx) => write!(out, ".{}", idx), - ArrayElem(idx) => write!(out, "[{}]", idx), + CapturedVar(name) => write!(out, ".<captured-var({name})>"), + TupleElem(idx) => write!(out, ".{idx}"), + ArrayElem(idx) => write!(out, "[{idx}]"), // `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and // some of the other items here also are not Rust syntax. Actually we can't // even use the usual syntax because we are just showing the projections, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 15a7c0536cb..ad5ffa6511f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -21,7 +21,7 @@ use std::mem; use std::ops::Deref; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; +use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -34,7 +34,7 @@ type QualifResults<'mir, 'tcx, Q> = pub struct Qualifs<'mir, 'tcx> { has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>, needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>, - needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>, + // needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>, } impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { @@ -77,15 +77,17 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { local: Local, location: Location, ) -> bool { + // FIXME(effects) replace with `NeedsNonconstDrop` after const traits work again + /* let ty = ccx.body.local_decls[local].ty; - if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) { + if !NeedsDrop::in_any_value_of_ty(ccx, ty) { return false; } let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| { let ConstCx { tcx, body, .. } = *ccx; - FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) + FlowSensitiveAnalysis::new(NeedsDrop, ccx) .into_engine(tcx, &body) .iterate_to_fixpoint() .into_results_cursor(&body) @@ -93,6 +95,9 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { needs_non_const_drop.seek_before_primary_effect(location); needs_non_const_drop.get().contains(local) + */ + + self.needs_drop(ccx, local, location) } /// Returns `true` if `local` is `HasMutInterior` at the given `Location`. @@ -798,16 +803,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Ok(Some(ImplSource::UserDefined(data))) => { let callee_name = tcx.item_name(callee); - if let Some(&did) = tcx - .associated_item_def_ids(data.impl_def_id) - .iter() - .find(|did| tcx.item_name(**did) == callee_name) - { - // using internal args is ok here, since this is only - // used for the `resolve` call below - fn_args = GenericArgs::identity_for_item(tcx, did); - callee = did; - } if let hir::Constness::NotConst = tcx.constness(data.impl_def_id) { self.check_op(ops::FnCallNonConst { @@ -820,6 +815,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }); return; } + + if let Some(&did) = tcx + .associated_item_def_ids(data.impl_def_id) + .iter() + .find(|did| tcx.item_name(**did) == callee_name) + { + // using internal args is ok here, since this is only + // used for the `resolve` call below + fn_args = GenericArgs::identity_for_item(tcx, did); + callee = did; + } } _ if !tcx.is_const_fn_raw(callee) => { // At this point, it is only legal when the caller is in a trait @@ -996,8 +1002,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let mut err_span = self.span; let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty; + // FIXME(effects) replace with `NeedsNonConstDrop` once we fix const traits let ty_needs_non_const_drop = - qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place); + qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place); debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 81337079af2..e785196c744 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -310,8 +310,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() { err.help(format!( - "add `#![feature({})]` to the crate attributes to enable", - feature, + "add `#![feature({feature})]` to the crate attributes to enable", )); } @@ -346,10 +345,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { err.help("const-stable functions can only call other const-stable functions"); } else if ccx.tcx.sess.is_nightly_build() { if let Some(feature) = feature { - err.help(format!( - "add `#![feature({})]` to the crate attributes to enable", - feature - )); + err.help(format!("add `#![feature({feature})]` to the crate attributes to enable")); } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index 1f1640fd80a..e3377bd10c6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -5,7 +5,7 @@ use rustc_span::{symbol::sym, Span}; use super::check::Qualifs; use super::ops::{self, NonConstOp}; -use super::qualifs::{NeedsNonConstDrop, Qualif}; +use super::qualifs::{NeedsDrop, Qualif}; use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop @@ -82,7 +82,9 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { match &terminator.kind { mir::TerminatorKind::Drop { place: dropped_place, .. } => { let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; - if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) { + + // FIXME(effects) use `NeedsNonConstDrop` + if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { // Instead of throwing a bug, we just return here. This is because we have to // run custom `const Drop` impls. return; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index b3730dd2648..b152644a551 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -23,7 +23,8 @@ pub fn in_any_value_of_ty<'tcx>( ConstQualifs { has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), - needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), + // FIXME(effects) + needs_non_const_drop: NeedsDrop::in_any_value_of_ty(cx, ty), custom_eq: CustomEq::in_any_value_of_ty(cx, ty), tainted_by_errors, } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 7b2bed302db..31effadd2c2 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { } } } else { - self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) + self.fail(location, format!("encountered jump to invalid basic block {bb:?}")) } } @@ -222,8 +222,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { self.fail( Location { block: bb, statement_index: 0 }, format!( - "Cleanup control flow violation: Cycle involving edge {:?} -> {:?}", - bb, parent, + "Cleanup control flow violation: Cycle involving edge {bb:?} -> {parent:?}", ), ); break; @@ -257,7 +256,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { if self.body.local_decls.get(local).is_none() { self.fail( location, - format!("local {:?} has no corresponding declaration in `body.local_decls`", local), + format!("local {local:?} has no corresponding declaration in `body.local_decls`"), ); } @@ -272,7 +271,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.storage_liveness.seek_after_primary_effect(location); let locals_with_storage = self.storage_liveness.get(); if !locals_with_storage.contains(local) { - self.fail(location, format!("use of local {:?}, which has no storage here", local)); + self.fail(location, format!("use of local {local:?}, which has no storage here")); } } } @@ -323,7 +322,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { // DropsLowered`. However, this causes ICEs with generation of drop shims, which // seem to fail to set their `MirPhase` correctly. if matches!(kind, RetagKind::Raw | RetagKind::TwoPhase) { - self.fail(location, format!("explicit `{:?}` is forbidden", kind)); + self.fail(location, format!("explicit `{kind:?}` is forbidden")); } } StatementKind::StorageLive(local) => { @@ -556,7 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty = place.ty(&self.body.local_decls, self.tcx).ty; if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { - self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}")); } } } @@ -575,7 +574,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ProjectionElem::Index(index) => { let index_ty = self.body.local_decls[index].ty; if index_ty != self.tcx.types.usize { - self.fail(location, format!("bad index ({:?} != usize)", index_ty)) + self.fail(location, format!("bad index ({index_ty:?} != usize)")) } } ProjectionElem::Deref @@ -586,22 +585,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if base_ty.is_box() { self.fail( location, - format!("{:?} dereferenced after ElaborateBoxDerefs", base_ty), + format!("{base_ty:?} dereferenced after ElaborateBoxDerefs"), ) } } ProjectionElem::Field(f, ty) => { let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx); let fail_out_of_bounds = |this: &mut Self, location| { - this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty)); + this.fail(location, format!("Out of bounds field {f:?} for {parent_ty:?}")); }; let check_equal = |this: &mut Self, location, f_ty| { if !this.mir_assign_valid_types(ty, f_ty) { this.fail( location, format!( - "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`", - place_ref, f, ty, f_ty + "Field projection `{place_ref:?}.{f:?}` specified type `{ty:?}`, but actual type is `{f_ty:?}`" ) ) } @@ -649,7 +647,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let Some(layout) = gen_body.generator_layout() else { self.fail( location, - format!("No generator layout for {:?}", parent_ty), + format!("No generator layout for {parent_ty:?}"), ); return; }; @@ -662,7 +660,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let Some(f_ty) = layout.field_tys.get(local) else { self.fail( location, - format!("Out of bounds local {:?} for {:?}", local, parent_ty), + format!("Out of bounds local {local:?} for {parent_ty:?}"), ); return; }; @@ -705,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) { self.fail( START_BLOCK.start_location(), - format!("debuginfo {:?}, has both ref and deref", debuginfo), + format!("debuginfo {debuginfo:?}, has both ref and deref"), ); } } @@ -715,7 +713,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if ty.is_union() || ty.is_enum() { self.fail( START_BLOCK.start_location(), - format!("invalid type {:?} for composite debuginfo", ty), + format!("invalid type {ty:?} for composite debuginfo"), ); } if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { @@ -742,7 +740,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo) && place.projection[1..].contains(&ProjectionElem::Deref) { - self.fail(location, format!("{:?}, has deref at the wrong place", place)); + self.fail(location, format!("{place:?}, has deref at the wrong place")); } self.super_place(place, cntxt, location); @@ -802,7 +800,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Offset => { check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..)); if b != self.tcx.types.isize && b != self.tcx.types.usize { - self.fail(location, format!("Cannot offset by non-isize type {:?}", b)); + self.fail(location, format!("Cannot offset by non-isize type {b:?}")); } } Eq | Lt | Le | Ne | Ge | Gt => { @@ -867,13 +865,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail( location, format!( - "Cannot perform checked arithmetic on unequal types {:?} and {:?}", - a, b + "Cannot perform checked arithmetic on unequal types {a:?} and {b:?}" ), ); } } - _ => self.fail(location, format!("There is no checked version of {:?}", op)), + _ => self.fail(location, format!("There is no checked version of {op:?}")), } } Rvalue::UnaryOp(op, operand) => { @@ -1078,7 +1075,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !ty.is_bool() { self.fail( location, - format!("`assume` argument must be `bool`, but got: `{}`", ty), + format!("`assume` argument must be `bool`, but got: `{ty}`"), ); } } @@ -1091,7 +1088,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } else { self.fail( location, - format!("Expected src to be ptr in copy_nonoverlapping, got: {}", src_ty), + format!("Expected src to be ptr in copy_nonoverlapping, got: {src_ty}"), ); return; }; @@ -1101,19 +1098,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } else { self.fail( location, - format!("Expected dst to be ptr in copy_nonoverlapping, got: {}", dst_ty), + format!("Expected dst to be ptr in copy_nonoverlapping, got: {dst_ty}"), ); return; }; // since CopyNonOverlapping is parametrized by 1 type, // we only need to check that they are equal and not keep an extra parameter. if !self.mir_assign_valid_types(op_src_ty, op_dst_ty) { - self.fail(location, format!("bad arg ({:?} != {:?})", op_src_ty, op_dst_ty)); + self.fail(location, format!("bad arg ({op_src_ty:?} != {op_dst_ty:?})")); } let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx); if op_cnt_ty != self.tcx.types.usize { - self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty)) + self.fail(location, format!("bad arg ({op_cnt_ty:?} != usize)")) } } StatementKind::SetDiscriminant { place, .. } => { @@ -1125,8 +1122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail( location, format!( - "`SetDiscriminant` is only allowed on ADTs and generators, not {:?}", - pty + "`SetDiscriminant` is only allowed on ADTs and generators, not {pty:?}" ), ); } @@ -1141,7 +1137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // DropsLowered`. However, this causes ICEs with generation of drop shims, which // seem to fail to set their `MirPhase` correctly. if matches!(kind, RetagKind::Raw | RetagKind::TwoPhase) { - self.fail(location, format!("explicit `{:?}` is forbidden", kind)); + self.fail(location, format!("explicit `{kind:?}` is forbidden")); } } StatementKind::StorageLive(_) @@ -1174,7 +1170,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if Scalar::<()>::try_from_uint(value, size).is_none() { self.fail( location, - format!("the value {:#x} is not a proper {:?}", value, switch_ty), + format!("the value {value:#x} is not a proper {switch_ty:?}"), ) } } @@ -1185,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::FnPtr(..) | ty::FnDef(..) => {} _ => self.fail( location, - format!("encountered non-callable type {} in `Call` terminator", func_ty), + format!("encountered non-callable type {func_ty} in `Call` terminator"), ), } } @@ -1195,8 +1191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail( location, format!( - "encountered non-boolean condition of type {} in `Assert` terminator", - cond_ty + "encountered non-boolean condition of type {cond_ty} in `Assert` terminator" ), ); } diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 88d4f5e715c..83376c8e992 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -57,12 +57,15 @@ pub fn is_subtype<'tcx>( // we would get unification errors because we're unable to look into opaque types, // even if they're constrained in our current function. for (key, ty) in infcx.take_opaque_types() { - span_bug!( - ty.hidden_type.span, - "{}, {}", - tcx.type_of(key.def_id).instantiate(tcx, key.args), - ty.hidden_type.ty - ); + let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args); + if hidden_ty != ty.hidden_type.ty { + span_bug!( + ty.hidden_type.span, + "{}, {}", + tcx.type_of(key.def_id).instantiate(tcx, key.args), + ty.hidden_type.ty + ); + } } errors.is_empty() } diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl index 8e8223c3cf8..d68dba0be5e 100644 --- a/compiler/rustc_errors/messages.ftl +++ b/compiler/rustc_errors/messages.ftl @@ -1,3 +1,25 @@ +errors_delayed_at_with_newline = + delayed at {$emitted_at} + {$note} + +errors_delayed_at_without_newline = + delayed at {$emitted_at} - {$note} + +errors_expected_lifetime_parameter = + expected lifetime {$count -> + [1] parameter + *[other] parameters + } + +errors_indicate_anonymous_lifetime = + indicate the anonymous {$count -> + [1] lifetime + *[other] lifetimes + } + +errors_invalid_flushed_delayed_diagnostic_level = + `flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug` + errors_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}` diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 132f2c015b8..a170e3a8943 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,3 +1,4 @@ +use crate::diagnostic::DiagnosticLocation; use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg}; use rustc_ast as ast; @@ -10,6 +11,7 @@ use rustc_span::Span; use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir as type_ir; +use std::backtrace::Backtrace; use std::borrow::Cow; use std::fmt; use std::num::ParseIntError; @@ -317,3 +319,62 @@ pub enum LabelKind { Label, Help, } + +#[derive(Subdiagnostic)] +#[label(errors_expected_lifetime_parameter)] +pub struct ExpectedLifetimeParameter { + #[primary_span] + pub span: Span, + pub count: usize, +} + +#[derive(Subdiagnostic)] +#[note(errors_delayed_at_with_newline)] +pub struct DelayedAtWithNewline { + #[primary_span] + pub span: Span, + pub emitted_at: DiagnosticLocation, + pub note: Backtrace, +} +#[derive(Subdiagnostic)] +#[note(errors_delayed_at_without_newline)] +pub struct DelayedAtWithoutNewline { + #[primary_span] + pub span: Span, + pub emitted_at: DiagnosticLocation, + pub note: Backtrace, +} + +impl IntoDiagnosticArg for DiagnosticLocation { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::from(self.to_string())) + } +} + +impl IntoDiagnosticArg for Backtrace { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::from(self.to_string())) + } +} + +#[derive(Subdiagnostic)] +#[note(errors_invalid_flushed_delayed_diagnostic_level)] +pub struct InvalidFlushedDelayedDiagnosticLevel { + #[primary_span] + pub span: Span, + pub level: rustc_errors::Level, +} +impl IntoDiagnosticArg for rustc_errors::Level { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::from(self.to_string())) + } +} + +#[derive(Subdiagnostic)] +#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")] +pub struct IndicateAnonymousLifetime { + #[primary_span] + pub span: Span, + pub count: usize, + pub suggestion: String, +} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index d18e01d178e..2181bd526eb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -22,6 +22,8 @@ extern crate rustc_macros; #[macro_use] extern crate tracing; +extern crate self as rustc_errors; + pub use emitter::ColorConfig; use rustc_lint_defs::LintExpectationId; @@ -377,13 +379,16 @@ pub struct ExplicitBug; /// rather than a failed assertion, etc. pub struct DelayedBugPanic; +use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; pub use diagnostic_impls::{ - DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans, + DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, + IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, LabelKind, + SingleLabelManySpans, }; use std::backtrace::{Backtrace, BacktraceStatus}; @@ -1650,11 +1655,11 @@ impl HandlerInner { let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); for bug in bugs { if let Some(file) = self.ice_file.as_ref() - && let Ok(mut out) = std::fs::File::options().append(true).open(file) + && let Ok(mut out) = std::fs::File::options().create(true).append(true).open(file) { let _ = write!( &mut out, - "\n\ndelayed span bug: {}\n{}", + "delayed span bug: {}\n{}\n", bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(), &bug.note ); @@ -1673,11 +1678,10 @@ impl HandlerInner { if bug.level != Level::DelayedBug { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. - bug.note(format!( - "`flushed_delayed` got diagnostic with level {:?}, \ - instead of the expected `DelayedBug`", - bug.level, - )); + bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { + span: bug.span.primary_span().unwrap(), + level: bug.level, + }); } bug.level = Level::Bug; @@ -1744,12 +1748,22 @@ impl DelayedDiagnostic { fn decorate(mut self) -> Diagnostic { match self.note.status() { BacktraceStatus::Captured => { - self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note)); + let inner = &self.inner; + self.inner.subdiagnostic(DelayedAtWithNewline { + span: inner.span.primary_span().unwrap(), + emitted_at: inner.emitted_at.clone(), + note: self.note, + }); } // Avoid the needless newline when no backtrace has been captured, // the display impl should just be a single line. _ => { - self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note)); + let inner = &self.inner; + self.inner.subdiagnostic(DelayedAtWithoutNewline { + span: inner.span.primary_span().unwrap(), + emitted_at: inner.emitted_at.clone(), + note: self.note, + }); } } @@ -1841,7 +1855,7 @@ pub fn add_elided_lifetime_in_path_suggestion( incl_angl_brckt: bool, insertion_span: Span, ) { - diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n))); + diag.subdiagnostic(ExpectedLifetimeParameter { span: path_span, count: n }); if !source_map.is_span_accessible(insertion_span) { // Do not try to suggest anything if generated by a proc-macro. return; @@ -1849,12 +1863,28 @@ pub fn add_elided_lifetime_in_path_suggestion( let anon_lts = vec!["'_"; n].join(", "); let suggestion = if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) }; - diag.span_suggestion_verbose( - insertion_span.shrink_to_hi(), - format!("indicate the anonymous lifetime{}", pluralize!(n)), + + diag.subdiagnostic(IndicateAnonymousLifetime { + span: insertion_span.shrink_to_hi(), + count: n, suggestion, - Applicability::MachineApplicable, - ); + }); +} + +pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( + db: &mut DiagnosticBuilder<'a, G>, + ambiguity: rustc_lint_defs::AmbiguityErrorDiag, +) { + db.span_label(ambiguity.label_span, ambiguity.label_msg); + db.note(ambiguity.note_msg); + db.span_note(ambiguity.b1_span, ambiguity.b1_note_msg); + for help_msg in ambiguity.b1_help_msgs { + db.help(help_msg); + } + db.span_note(ambiguity.b2_span, ambiguity.b2_note_msg); + for help_msg in ambiguity.b2_help_msgs { + db.help(help_msg); + } } #[derive(Clone, Copy, PartialEq, Hash, Debug)] diff --git a/compiler/rustc_errors/src/markdown/tests/term.rs b/compiler/rustc_errors/src/markdown/tests/term.rs index 3b31c6d6295..6f68fb25a58 100644 --- a/compiler/rustc_errors/src/markdown/tests/term.rs +++ b/compiler/rustc_errors/src/markdown/tests/term.rs @@ -63,7 +63,7 @@ fn test_wrapping_write() { #[test] fn test_output() { // Capture `--bless` when run via ./x - let bless = std::env::var("RUSTC_BLESS").unwrap_or_default() == "1"; + let bless = std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); let ast = MdStream::parse_str(INPUT); let bufwtr = BufferWriter::stderr(ColorChoice::Always); let mut buffer = bufwtr.buffer(); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 264f30fb10a..7de46994434 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -643,7 +643,16 @@ impl<'a> ExtCtxt<'a> { span, name, AttrVec::new(), - ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()), + ast::ItemKind::Const( + ast::ConstItem { + defaultness, + // FIXME(generic_const_items): Pass the generics as a parameter. + generics: ast::Generics::default(), + ty, + expr: Some(expr), + } + .into(), + ), ) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 4ec5ac22e90..aeb4f6e861b 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -365,9 +365,9 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let mut orig_trees = orig_tokens.into_trees(); + let mut orig_trees = orig_tokens.trees(); let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) = - orig_trees.next().unwrap() + orig_trees.next().unwrap().clone() else { panic!("Bad tokens for attribute {:?}", attr); }; @@ -377,7 +377,7 @@ impl<'a> StripUnconfigured<'a> { if attr.style == AttrStyle::Inner { // For inner attributes, we do the same thing for the `!` in `#![some_attr]` let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = - orig_trees.next().unwrap() + orig_trees.next().unwrap().clone() else { panic!("Bad tokens for attribute {:?}", attr); }; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 102bae2a744..7398a124fdb 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -500,7 +500,7 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedTokenTree(tt) = m { let tt = mbe::quoted::parse( - TokenStream::new(vec![tt.clone()]), + &TokenStream::new(vec![tt.clone()]), true, &sess.parse_sess, def.id, @@ -524,7 +524,7 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedTokenTree(tt) = m { return mbe::quoted::parse( - TokenStream::new(vec![tt.clone()]), + &TokenStream::new(vec![tt.clone()]), false, &sess.parse_sess, def.id, diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 40bfa3715be..ac862ae8c4f 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -36,7 +36,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ /// /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`. pub(super) fn parse( - input: tokenstream::TokenStream, + input: &tokenstream::TokenStream, parsing_patterns: bool, sess: &ParseSess, node_id: NodeId, @@ -48,7 +48,7 @@ pub(super) fn parse( // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming // additional trees if need be. - let mut trees = input.into_trees(); + let mut trees = input.trees(); while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). @@ -56,7 +56,7 @@ pub(super) fn parse( match tree { TokenTree::MetaVar(start_sp, ident) if parsing_patterns => { let span = match trees.next() { - Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => { + Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => { match trees.next() { Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() { Some((frag, _)) => { @@ -96,10 +96,10 @@ pub(super) fn parse( } _ => token.span, }, - tree => tree.as_ref().map_or(span, tokenstream::TokenTree::span), + tree => tree.map_or(span, tokenstream::TokenTree::span), } } - tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span), + tree => tree.map_or(start_sp, tokenstream::TokenTree::span), }; result.push(TokenTree::MetaVarDecl(span, ident, None)); @@ -134,9 +134,9 @@ fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, /// - `parsing_patterns`: same as [parse]. /// - `sess`: the parsing session. Any errors will be emitted to this session. /// - `features`: language features so we can do feature gating. -fn parse_tree( - tree: tokenstream::TokenTree, - outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>, +fn parse_tree<'a>( + tree: &'a tokenstream::TokenTree, + outer_trees: &mut impl Iterator<Item = &'a tokenstream::TokenTree>, parsing_patterns: bool, sess: &ParseSess, node_id: NodeId, @@ -146,13 +146,13 @@ fn parse_tree( // Depending on what `tree` is, we could be parsing different parts of a macro match tree { // `tree` is a `$` token. Look at the next token in `trees` - tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => { + &tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => { // FIXME: Handle `Invisible`-delimited groups in a more systematic way // during parsing. let mut next = outer_trees.next(); - let mut trees: Box<dyn Iterator<Item = tokenstream::TokenTree>>; + let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>; if let Some(tokenstream::TokenTree::Delimited(_, Delimiter::Invisible, tts)) = next { - trees = Box::new(tts.into_trees()); + trees = Box::new(tts.trees()); next = trees.next(); } else { trees = Box::new(outer_trees); @@ -160,7 +160,7 @@ fn parse_tree( match next { // `tree` is followed by a delimited set of token trees. - Some(tokenstream::TokenTree::Delimited(delim_span, delim, tts)) => { + Some(&tokenstream::TokenTree::Delimited(delim_span, delim, ref tts)) => { if parsing_patterns { if delim != Delimiter::Parenthesis { span_dollar_dollar_or_metavar_in_the_lhs_err( @@ -228,7 +228,7 @@ fn parse_tree( } // `tree` is followed by another `$`. This is an escaped `$`. - Some(tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => { + Some(&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => { if parsing_patterns { span_dollar_dollar_or_metavar_in_the_lhs_err( sess, @@ -256,11 +256,11 @@ fn parse_tree( } // `tree` is an arbitrary token. Keep it. - tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token), + tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()), // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. - tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( + &tokenstream::TokenTree::Delimited(span, delim, ref tts) => TokenTree::Delimited( span, Delimited { delim, @@ -286,16 +286,16 @@ fn kleene_op(token: &Token) -> Option<KleeneOp> { /// - Ok(Ok((op, span))) if the next token tree is a KleeneOp /// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp /// - Err(span) if the next token tree is not a token -fn parse_kleene_op( - input: &mut impl Iterator<Item = tokenstream::TokenTree>, +fn parse_kleene_op<'a>( + input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>, span: Span, ) -> Result<Result<(KleeneOp, Span), Token>, Span> { match input.next() { Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(&token) { Some(op) => Ok(Ok((op, token.span))), - None => Ok(Err(token)), + None => Ok(Err(token.clone())), }, - tree => Err(tree.as_ref().map_or(span, tokenstream::TokenTree::span)), + tree => Err(tree.map_or(span, tokenstream::TokenTree::span)), } } @@ -311,8 +311,8 @@ fn parse_kleene_op( /// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene /// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an /// error with the appropriate span is emitted to `sess` and a dummy value is returned. -fn parse_sep_and_kleene_op( - input: &mut impl Iterator<Item = tokenstream::TokenTree>, +fn parse_sep_and_kleene_op<'a>( + input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>, span: Span, sess: &ParseSess, ) -> (Option<Token>, KleeneToken) { diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index e133501c5d0..bdc20882a9d 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -69,9 +69,8 @@ fn bad_path_expr_1() { #[test] fn string_to_tts_macro() { create_default_session_globals_then(|| { - let tts: Vec<_> = - string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).into_trees().collect(); - let tts: &[TokenTree] = &tts[..]; + let stream = string_to_stream("macro_rules! zip (($a)=>($a))".to_string()); + let tts = &stream.trees().collect::<Vec<_>>()[..]; match tts { [ @@ -300,9 +299,7 @@ fn ttdelim_span() { .unwrap(); let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") }; - let tts: Vec<_> = mac.args.tokens.clone().into_trees().collect(); - - let span = tts.iter().rev().next().unwrap().span(); + let span = mac.args.tokens.trees().last().unwrap().span(); match sess.source_map().span_to_snippet(span) { Ok(s) => assert_eq!(&s[..], "{ body }"), diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ecd2315112a..ac73b5d72b7 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -94,10 +94,10 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre // Estimate the capacity as `stream.len()` rounded up to the next power // of two to limit the number of required reallocations. let mut trees = Vec::with_capacity(stream.len().next_power_of_two()); - let mut cursor = stream.into_trees(); + let mut cursor = stream.trees(); while let Some(tree) = cursor.next() { - let (Token { kind, span }, joint) = match tree { + let (Token { kind, span }, joint) = match tree.clone() { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = pm::Delimiter::from_internal(delim); trees.push(TokenTree::Group(Group { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 56a2c5eff3d..22380a52104 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -379,6 +379,8 @@ declare_features! ( (active, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), + /// Allows using the `#[diagnostic]` attribute tool namespace + (active, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(94785), None), /// Controls errors in trait implementations. (active, do_not_recommend, "1.67.0", Some(51992), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. @@ -422,6 +424,8 @@ declare_features! ( (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), + /// Allows generic parameters and where-clauses on free & associated const items. + (incomplete, generic_const_items, "CURRENT_RUSTC_VERSION", Some(113521), None), /// Allows using `..=X` as a patterns in slices. (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3663c450ba6..6b76e16825f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3130,9 +3130,9 @@ impl<'hir> Item<'hir> { } /// Expect an [`ItemKind::Const`] or panic. #[track_caller] - pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; - (ty, body) + pub fn expect_const(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Const(ty, gen, body) = self.kind else { self.expect_failed("a constant") }; + (ty, gen, body) } /// Expect an [`ItemKind::Fn`] or panic. #[track_caller] @@ -3319,7 +3319,7 @@ pub enum ItemKind<'hir> { /// A `static` item. Static(&'hir Ty<'hir>, Mutability, BodyId), /// A `const` item. - Const(&'hir Ty<'hir>, BodyId), + Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), /// A function declaration. Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). @@ -3372,6 +3372,7 @@ impl ItemKind<'_> { Some(match *self { ItemKind::Fn(_, ref generics, _) | ItemKind::TyAlias(_, ref generics) + | ItemKind::Const(_, ref generics, _) | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) @@ -3567,7 +3568,9 @@ impl<'hir> OwnerNode<'hir> { match self { OwnerNode::Item(Item { kind: - ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), + ItemKind::Static(_, _, body) + | ItemKind::Const(_, _, body) + | ItemKind::Fn(_, _, body), .. }) | OwnerNode::TraitItem(TraitItem { @@ -3770,9 +3773,9 @@ impl<'hir> Node<'hir> { pub fn ty(self) -> Option<&'hir Ty<'hir>> { match self { Node::Item(it) => match it.kind { - ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => { - Some(ty) - } + ItemKind::TyAlias(ty, _) + | ItemKind::Static(ty, _, _) + | ItemKind::Const(ty, _, _) => Some(ty), _ => None, }, Node::TraitItem(it) => match it.kind { @@ -3800,7 +3803,9 @@ impl<'hir> Node<'hir> { match self { Node::Item(Item { kind: - ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), + ItemKind::Static(_, _, body) + | ItemKind::Const(_, _, body) + | ItemKind::Fn(_, _, body), .. }) | Node::TraitItem(TraitItem { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 347c1f4637f..a8a94e6a476 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -467,11 +467,17 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { ItemKind::Use(ref path, _) => { visitor.visit_use(path, item.hir_id()); } - ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => { + ItemKind::Static(ref typ, _, body) => { visitor.visit_id(item.hir_id()); visitor.visit_ty(typ); visitor.visit_nested_body(body); } + ItemKind::Const(ref typ, ref generics, body) => { + visitor.visit_id(item.hir_id()); + visitor.visit_ty(typ); + visitor.visit_generics(generics); + visitor.visit_nested_body(body); + } ItemKind::Fn(ref sig, ref generics, body_id) => { visitor.visit_id(item.hir_id()); visitor.visit_fn( diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 7f4927bbb98..bd311c98fac 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -197,7 +197,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - err.span_label(span, format!("associated type `{}` not found", assoc_name)); + err.span_label(span, format!("associated type `{assoc_name}` not found")); err.emit() } @@ -393,7 +393,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .into_iter() .map(|error| error.root_obligation.predicate) .filter_map(format_pred) - .map(|(p, _)| format!("`{}`", p)) + .map(|(p, _)| format!("`{p}`")) .collect(); bounds.sort(); bounds.dedup(); @@ -652,7 +652,7 @@ pub(crate) fn fn_trait_to_string( } .map(|s| { // `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma - if parenthesized || s.is_empty() { format!("({})", s) } else { format!("({},)", s) } + if parenthesized || s.is_empty() { format!("({s})") } else { format!("({s},)") } }) .ok(), _ => None, diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index e81c61d80ed..1372cc896be 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -81,7 +81,7 @@ fn generic_arg_mismatch_err( err.span_suggestion( tcx.def_span(src_def_id), "consider changing this type parameter to a const parameter", - format!("const {}: {}", param_name, param_type), + format!("const {param_name}: {param_type}"), Applicability::MaybeIncorrect, ); }; @@ -102,7 +102,7 @@ fn generic_arg_mismatch_err( err.span_suggestion( arg.span(), "array type provided where a `usize` was expected, try", - format!("{{ {} }}", snippet), + format!("{{ {snippet} }}"), Applicability::MaybeIncorrect, ); } @@ -130,7 +130,7 @@ fn generic_arg_mismatch_err( } else { (arg.descr(), param.kind.descr()) }; - err.note(format!("{} arguments must be provided before {} arguments", first, last)); + err.note(format!("{first} arguments must be provided before {last} arguments")); if let Some(help) = help { err.help(help); } @@ -304,7 +304,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>( "reorder the arguments: {}: `<{}>`", param_types_present .into_iter() - .map(|ord| format!("{}s", ord)) + .map(|ord| format!("{ord}s")) .collect::<Vec<String>>() .join(", then "), ordered_params diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index ff55174f97a..1bd1270beaf 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -34,9 +34,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_name = generics.params.next_type_param_name(None); let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { - (span, format!(", {}: {}", param_name, impl_trait_name)) + (span, format!(", {param_name}: {impl_trait_name}")) } else { - (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) + (generics.span, format!("<{param_name}: {impl_trait_name}>")) }; diag.multipart_suggestion( format!("alternatively use a blanket \ diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index ecbbfd92539..3235a9ceba1 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1128,7 +1128,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_name ) }; - err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); + err.span_label(span, format!("ambiguous associated type `{assoc_name}`")); let mut where_bounds = vec![]; for bound in bounds { @@ -1407,7 +1407,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { _ => { let reported = if variant_resolution.is_some() { // Variant in type position - let msg = format!("expected type, found variant `{}`", assoc_ident); + let msg = format!("expected type, found variant `{assoc_ident}`"); tcx.sess.span_err(span, msg) } else if qself_ty.is_enum() { let mut err = struct_span_err!( @@ -1438,12 +1438,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { err.span_label( assoc_ident.span, - format!("variant not found in `{}`", qself_ty), + format!("variant not found in `{qself_ty}`"), ); } if let Some(sp) = tcx.hir().span_if_local(adt_def.did()) { - err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); + err.span_label(sp, format!("variant `{assoc_ident}` not found here")); } err.emit() @@ -2750,7 +2750,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => { "an anonymous lifetime".to_string() } - ty::BrNamed(_, name) => format!("lifetime `{}`", name), + ty::BrNamed(_, name) => format!("lifetime `{name}`"), }; let mut err = generate_err(&br_name); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a876f169c3a..84452979aa5 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -345,7 +345,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( err.span_suggestion( span, "consider spelling out the type instead", - name.unwrap_or_else(|| format!("{:?}", ty)), + name.unwrap_or_else(|| format!("{ty:?}")), Applicability::MaybeIncorrect, ); } @@ -797,7 +797,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { "replace the {} parameters with concrete {}{}", kinds, kinds_pl, - egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), + egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(), ), ) .emit(); @@ -882,7 +882,7 @@ pub(super) fn check_specialization_validity<'tcx>( } else { tcx.sess.delay_span_bug( DUMMY_SP, - format!("parent item: {:?} not marked as default", parent_impl), + format!("parent item: {parent_impl:?} not marked as default"), ); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 89877280a73..a8c66ff9001 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -76,7 +76,7 @@ fn check_method_is_structurally_compatible<'tcx>( Ok(()) } -/// This function is best explained by example. Consider a trait with it's implementation: +/// This function is best explained by example. Consider a trait with its implementation: /// /// ```rust /// trait Trait<'t, T> { @@ -120,7 +120,7 @@ fn check_method_is_structurally_compatible<'tcx>( /// types: /// /// ```rust,ignore (pseudo-Rust) -/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo /// ``` /// /// We now want to extract and substitute the type of the *trait* @@ -137,7 +137,7 @@ fn check_method_is_structurally_compatible<'tcx>( /// Applying this to the trait method type yields: /// /// ```rust,ignore (pseudo-Rust) -/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo /// ``` /// /// This type is also the same but the name of the bound region (`'a` @@ -219,11 +219,7 @@ fn compare_method_predicate_entailment<'tcx>( // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); - let param_env = ty::ParamEnv::new( - tcx.mk_clauses(&hybrid_preds.predicates), - Reveal::UserFacing, - hir::Constness::NotConst, - ); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = &tcx.infer_ctxt().build(); @@ -262,8 +258,6 @@ fn compare_method_predicate_entailment<'tcx>( // type. // Compute placeholder form of impl and trait method tys. - let tcx = infcx.tcx; - let mut wf_tys = FxIndexSet::default(); let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( @@ -760,7 +754,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; - let mut collected_tys = FxHashMap::default(); + let mut remapped_types = FxHashMap::default(); for (def_id, (ty, args)) in collected_types { match infcx.fully_resolve((ty, args)) { Ok((ty, args)) => { @@ -810,19 +804,37 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Ok(ty) => ty, Err(guar) => Ty::new_error(tcx, guar), }; - collected_tys.insert(def_id, ty::EarlyBinder::bind(ty)); + remapped_types.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported))); + remapped_types.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported))); } } } - Ok(&*tcx.arena.alloc(collected_tys)) + // We may not collect all RPITITs that we see in the HIR for a trait signature + // because an RPITIT was located within a missing item. Like if we have a sig + // returning `-> Missing<impl Sized>`, that gets converted to `-> [type error]`, + // and when walking through the signature we end up never collecting the def id + // of the `impl Sized`. Insert that here, so we don't ICE later. + for assoc_item in tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) { + if !remapped_types.contains_key(assoc_item) { + remapped_types.insert( + *assoc_item, + ty::EarlyBinder::bind(Ty::new_error_with_message( + tcx, + return_span, + "missing synthetic item for RPITIT", + )), + ); + } + } + + Ok(&*tcx.arena.alloc(remapped_types)) } struct ImplTraitInTraitCollector<'a, 'tcx> { @@ -1672,19 +1684,19 @@ fn compare_synthetic_generics<'tcx>( /// ```rust,ignore (pseudo-Rust) /// trait Foo { /// fn foo<const N: u8>(); -/// type bar<const N: u8>; +/// type Bar<const N: u8>; /// fn baz<const N: u32>(); -/// type blah<T>; +/// type Blah<T>; /// } /// /// impl Foo for () { /// fn foo<const N: u64>() {} /// //~^ error -/// type bar<const N: u64> {} +/// type Bar<const N: u64> = (); /// //~^ error /// fn baz<T>() {} /// //~^ error -/// type blah<const N: i64> = u32; +/// type Blah<const N: i64> = u32; /// //~^ error /// } /// ``` @@ -1744,7 +1756,7 @@ fn compare_generic_param_kinds<'tcx>( tcx.type_of(param.def_id).instantiate_identity() ) } - Type { .. } => format!("{} type parameter", prefix), + Type { .. } => format!("{prefix} type parameter"), Lifetime { .. } => unreachable!(), }; @@ -1773,36 +1785,82 @@ pub(super) fn compare_impl_const_raw( let trait_const_item = tcx.associated_item(trait_const_item_def); let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity(); - debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id()); + debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref); - let infcx = tcx.infer_ctxt().build(); - let param_env = tcx.param_env(impl_const_item_def.to_def_id()); - let ocx = ObligationCtxt::new(&infcx); + compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; + compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; + compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref) +} + +/// The equivalent of [compare_method_predicate_entailment], but for associated constants +/// instead of associated functions. +// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`. +fn compare_const_predicate_entailment<'tcx>( + tcx: TyCtxt<'tcx>, + impl_ct: ty::AssocItem, + trait_ct: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorGuaranteed> { + let impl_ct_def_id = impl_ct.def_id.expect_local(); + let impl_ct_span = tcx.def_span(impl_ct_def_id); // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let trait_to_impl_args = impl_trait_ref.args; + let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id); + let trait_to_impl_args = + impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args); // Create a parameter environment that represents the implementation's // method. // Compute placeholder form of impl and trait const tys. - let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).instantiate_identity(); - let trait_ty = tcx.type_of(trait_const_item_def).instantiate(tcx, trait_to_impl_args); - let mut cause = ObligationCause::new( - impl_c_span, - impl_const_item_def, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_const_item_def, - trait_item_def_id: trait_const_item_def, - kind: impl_const_item.kind, - }, + let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity(); + + let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args); + let code = ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_ct_def_id, + trait_item_def_id: trait_ct.def_id, + kind: impl_ct.kind, + }; + let mut cause = ObligationCause::new(impl_ct_span, impl_ct_def_id, code.clone()); + + let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id); + let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id); + + check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?; + + // The predicates declared by the impl definition, the trait and the + // associated const in the trait are assumed. + let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); + hybrid_preds.predicates.extend( + trait_ct_predicates + .instantiate_own(tcx, trait_to_impl_args) + .map(|(predicate, _)| predicate), + ); + + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = traits::normalize_param_env_or_error( + tcx, + param_env, + ObligationCause::misc(impl_ct_span, impl_ct_def_id), ); + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + + let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); + for (predicate, span) in impl_ct_own_bounds { + let cause = ObligationCause::misc(span, impl_ct_def_id); + let predicate = ocx.normalize(&cause, param_env, predicate); + + let cause = ObligationCause::new(span, impl_ct_def_id, code.clone()); + ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); + } + // There is no "body" here, so just pass dummy id. let impl_ty = ocx.normalize(&cause, param_env, impl_ty); @@ -1821,7 +1879,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); + let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1829,12 +1887,12 @@ pub(super) fn compare_impl_const_raw( cause.span, E0326, "implemented const `{}` has an incompatible type for trait", - trait_const_item.name + trait_ct.name ); - let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { + let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { // Add a label to the Span containing just the type of the const - let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); + let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const(); ty.span }); @@ -1861,7 +1919,7 @@ pub(super) fn compare_impl_const_raw( } let outlives_env = OutlivesEnvironment::new(param_env); - ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env) + ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env) } pub(super) fn compare_impl_ty<'tcx>( @@ -1903,7 +1961,7 @@ fn compare_type_predicate_entailment<'tcx>( return Ok(()); } - // This `HirId` should be used for the `body_id` field on each + // This `DefId` should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_def_id = impl_ty.def_id.expect_local(); @@ -1922,12 +1980,8 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); let impl_ty_span = tcx.def_span(impl_ty_def_id); - let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id); - let param_env = ty::ParamEnv::new( - tcx.mk_clauses(&hybrid_preds.predicates), - Reveal::UserFacing, - hir::Constness::NotConst, - ); + let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id); + let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(&infcx); @@ -1971,7 +2025,7 @@ fn compare_type_predicate_entailment<'tcx>( /// /// trait X { type Y: Copy } impl X for T { type Y = S; } /// -/// We are able to normalize `<T as X>::U` to `S`, and so when we check the +/// We are able to normalize `<T as X>::Y` to `S`, and so when we check the /// impl is well-formed we have to prove `S: Copy`. /// /// For default associated types the normalization is not possible (the value @@ -2102,7 +2156,7 @@ pub(super) fn check_type_bounds<'tcx>( .to_predicate(tcx), ), }; - ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing, param_env.constness()) + ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) }; debug!(?normalize_param_env); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 4ac3a7c23ae..dda3f742569 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -129,9 +129,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)) - .instantiate(tcx, adt_to_impl_args) - .with_constness(tcx.constness(drop_impl_def_id)); + let param_env = + ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d5c9840887a..064021b1ea4 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -134,7 +134,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, /// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { - let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{}", n))); + let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{n}"))); let intrinsic_id = it.owner_id.to_def_id(); let intrinsic_name = tcx.item_name(intrinsic_id); let name_str = intrinsic_name.as_str(); @@ -494,7 +494,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { /// Type-check `extern "platform-intrinsic" { ... }` functions. pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)); + let name = Symbol::intern(&format!("P{n}")); Ty::new_param(tcx, n, name) }; @@ -521,6 +521,10 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)), sym::simd_arith_offset => (2, vec![param(0), param(1)], param(0)), sym::simd_neg + | sym::simd_bswap + | sym::simd_bitreverse + | sym::simd_ctlz + | sym::simd_cttz | sym::simd_fsqrt | sym::simd_fsin | sym::simd_fcos diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 8423a9550ba..b0dd5e5787d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // register class is usable at all. if let Some(feature) = feature { if !target_features.contains(feature) { - let msg = format!("`{}` target feature is not enabled", feature); + let msg = format!("`{feature}` target feature is not enabled"); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(format!( "this is required to use type `{}` with register class `{}`", diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index def7a3a9d88..4cf3587327d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -214,7 +214,7 @@ fn missing_items_err( trait_item, tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(), ); - let code = format!("{}{}\n{}", padding, snippet, padding); + let code = format!("{padding}{snippet}\n{padding}"); if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { missing_trait_item_label .push(errors::MissingTraitItemLabel { span, item: trait_item.name }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4e194f1c381..4df572f6199 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -75,12 +75,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { self.body_def_id, ObligationCauseCode::WellFormed(loc), ); - // for a type to be WF, we do not need to check if const trait predicates satisfy. - let param_env = self.param_env.without_const(); self.ocx.register_obligation(traits::Obligation::new( self.tcx(), cause, - param_env, + self.param_env, ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))), )); } @@ -286,6 +284,17 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { }; check_object_unsafe_self_trait_by_name(tcx, trait_item); check_associated_item(tcx, def_id, span, method_sig); + + if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { + for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { + check_associated_item( + tcx, + assoc_ty_def_id.expect_local(), + tcx.def_span(assoc_ty_def_id), + None, + ); + } + } } /// Require that the user writes where clauses on GATs for the implicit @@ -472,8 +481,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let bound = if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" }; err.note(format!( - "{} currently required to ensure that impls have maximum flexibility", - bound + "{bound} currently required to ensure that impls have maximum flexibility" )); err.note( "we are soliciting feedback, see issue #87479 \ @@ -505,7 +513,7 @@ fn augment_param_env<'tcx>( ); // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this // i.e. traits::normalize_param_env_or_error - ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness()) + ty::ParamEnv::new(bounds, param_env.reveal()) } /// We use the following trait as an example throughout this function. @@ -989,7 +997,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b let ty = tcx.erase_regions(ty); if ty.has_infer() { tcx.sess - .delay_span_bug(item.span, format!("inference variables in {:?}", ty)); + .delay_span_bug(item.span, format!("inference variables in {ty:?}")); // Just treat unresolved type expression as if it needs drop. true } else { @@ -1416,7 +1424,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { traits::wf::predicate_obligations( infcx, - wfcx.param_env.without_const(), + wfcx.param_env, wfcx.body_def_id, p.as_predicate(), sp, @@ -1469,13 +1477,6 @@ fn check_fn_or_method<'tcx>( check_where_clauses(wfcx, span, def_id); - check_return_position_impl_trait_in_trait_bounds( - wfcx, - def_id, - sig.output(), - hir_decl.output.span(), - ); - if sig.abi == Abi::RustCall { let span = tcx.def_span(def_id); let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None; @@ -1510,87 +1511,6 @@ fn check_fn_or_method<'tcx>( } } -/// Basically `check_associated_type_bounds`, but separated for now and should be -/// deduplicated when RPITITs get lowered into real associated items. -#[tracing::instrument(level = "trace", skip(wfcx))] -fn check_return_position_impl_trait_in_trait_bounds<'tcx>( - wfcx: &WfCheckingCtxt<'_, 'tcx>, - fn_def_id: LocalDefId, - fn_output: Ty<'tcx>, - span: Span, -) { - let tcx = wfcx.tcx(); - let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else { - return; - }; - if assoc_item.container != ty::AssocItemContainer::TraitContainer { - return; - } - fn_output.visit_with(&mut ImplTraitInTraitFinder { - wfcx, - fn_def_id, - depth: ty::INNERMOST, - seen: FxHashSet::default(), - }); -} - -// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering -// strategy, we can't just call `check_associated_item` on the new RPITITs, -// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. -// That's because we need to check that the bounds of the RPITIT hold using -// the special args that we create during opaque type lowering, otherwise we're -// getting a bunch of early bound and free regions mixed up... Haven't looked too -// deep into this, though. -struct ImplTraitInTraitFinder<'a, 'tcx> { - wfcx: &'a WfCheckingCtxt<'a, 'tcx>, - fn_def_id: LocalDefId, - depth: ty::DebruijnIndex, - seen: FxHashSet<DefId>, -} -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { - type BreakTy = !; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> { - let tcx = self.wfcx.tcx(); - if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() - && self.seen.insert(unshifted_opaque_ty.def_id) - && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() - && let origin = tcx.opaque_type_origin(opaque_def_id) - && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin - && source == self.fn_def_id - { - let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { - match re.kind() { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re, - r => bug!("unexpected region: {r:?}"), - } - }); - for (bound, bound_span) in tcx - .explicit_item_bounds(opaque_ty.def_id) - .iter_instantiated_copied(tcx, opaque_ty.args) - { - let bound = self.wfcx.normalize(bound_span, None, bound); - self.wfcx.register_obligations(traits::wf::predicate_obligations( - self.wfcx.infcx, - self.wfcx.param_env, - self.wfcx.body_def_id, - bound.as_predicate(), - bound_span, - )); - // Set the debruijn index back to innermost here, since we already eagerly - // shifted the args that we use to generate these bounds. This is unfortunately - // subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`, - // but that function doesn't actually need to normalize the bound it's visiting - // (whereas we have to do so here)... - let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST); - bound.visit_with(self); - self.depth = old_depth; - } - } - ty.super_visit_with(self) - } -} - const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \ `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \ of the previous types except `Self`)"; @@ -1863,8 +1783,7 @@ fn report_bivariance( if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds { err.help(format!( - "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead", - param_name + "if you intended `{param_name}` to be a const parameter, use `const {param_name}: usize` instead" )); } err.emit() diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index d10bc5b34ea..9ad73eeffc6 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -36,7 +36,7 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { } let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { - format!("unused import: `{}`", snippet) + format!("unused import: `{snippet}`") } else { "unused import".to_owned() }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 3f65adcd36e..c930537d4ae 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -171,8 +171,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef create_err(&format!( "the trait `DispatchFromDyn` may only be implemented \ for a coercion between structures with the same \ - definition; expected `{}`, found `{}`", - source_path, target_path, + definition; expected `{source_path}`, found `{target_path}`", )) .emit(); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index f5326e50614..a94c75f918a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -148,8 +148,7 @@ impl<'tcx> InherentCollect<'tcx> { if let ty::Ref(_, subty, _) = ty.kind() { err.note(format!( "you could also try moving the reference to \ - uses of `{}` (such as `self`) within the implementation", - subty + uses of `{subty}` (such as `self`) within the implementation" )); } err.emit(); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 3bd2931265c..7205b7a21a8 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -77,8 +77,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> { "duplicate definitions with name `{}`", ident, ); - err.span_label(span, format!("duplicate definitions for `{}`", ident)); - err.span_label(*former, format!("other definition for `{}`", ident)); + err.span_label(span, format!("duplicate definitions for `{ident}`")); + err.span_label(*former, format!("other definition for `{ident}`")); err.emit(); } @@ -114,11 +114,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { ); err.span_label( self.tcx.def_span(item1.def_id), - format!("duplicate definitions for `{}`", name), + format!("duplicate definitions for `{name}`"), ); err.span_label( self.tcx.def_span(item2.def_id), - format!("other definition for `{}`", name), + format!("other definition for `{name}`"), ); for cause in &overlap.intercrate_ambiguity_causes { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 8d9a6f4d446..bbdb108c59b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -412,9 +412,8 @@ fn emit_orphan_check_error<'tcx>( .span_label( sp, format!( - "type parameter `{}` must be covered by another type \ - when it appears before the first local type (`{}`)", - param_ty, local_type + "type parameter `{param_ty}` must be covered by another type \ + when it appears before the first local type (`{local_type}`)" ), ) .note( @@ -441,9 +440,8 @@ fn emit_orphan_check_error<'tcx>( .span_label( sp, format!( - "type parameter `{}` must be used as the type parameter for some \ + "type parameter `{param_ty}` must be used as the type parameter for some \ local type", - param_ty, ), ) .note( @@ -541,17 +539,16 @@ fn lint_auto_trait_impl<'tcx>( let self_descr = tcx.def_descr(self_type_did); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { - lint.note(format!("`{}` is mentioned multiple times", arg)); + lint.note(format!("`{arg}` is mentioned multiple times")); } ty::util::NotUniqueParam::NotParam(arg) => { - lint.note(format!("`{}` is not a generic parameter", arg)); + lint.note(format!("`{arg}` is not a generic parameter")); } } lint.span_note( item_span, format!( - "try using the same sequence of generic parameters as the {} definition", - self_descr, + "try using the same sequence of generic parameters as the {self_descr} definition", ), ) }, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c160cf2df6e..f568b751951 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -195,9 +195,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( sugg.push((arg.span, (*type_name).to_string())); } else if let Some(span) = generics.span_for_param_suggestion() { // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`. - sugg.push((span, format!(", {}", type_name))); + sugg.push((span, format!(", {type_name}"))); } else { - sugg.push((generics.span, format!("<{}>", type_name))); + sugg.push((generics.span, format!("<{type_name}>"))); } } @@ -329,7 +329,7 @@ fn bad_placeholder<'tcx>( mut spans: Vec<Span>, kind: &'static str, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) }; + let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") }; spans.sort(); tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) @@ -425,10 +425,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { | hir::ItemKind::Union(_, generics) => { let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics); let (lt_sp, sugg) = match generics.params { - [] => (generics.span, format!("<{}>", lt_name)), - [bound, ..] => { - (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) - } + [] => (generics.span, format!("<{lt_name}>")), + [bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")), }; mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { fspan: lt_sp, @@ -1027,7 +1025,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } else { tcx.sess.span_err( meta.span(), - format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta), + format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"), ); } } @@ -1505,7 +1503,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .sess .source_map() .span_to_snippet(ast_ty.span) - .map_or_else(|_| String::new(), |s| format!(" `{}`", s)); + .map_or_else(|_| String::new(), |s| format!(" `{s}`")); tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip }); } }; diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index edcb9527fe2..6e1762c54f2 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -209,6 +209,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { | ItemKind::Struct(..) | ItemKind::OpaqueTy(..) | ItemKind::Union(..) => (None, Defaults::Allowed), + ItemKind::Const(..) => (None, Defaults::Deny), _ => (None, Defaults::FutureCompatDisallowed), } } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 979b101e7fe..ab3b2dde078 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -156,6 +156,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } ItemKind::Fn(.., generics, _) | ItemKind::TyAlias(_, generics) + | ItemKind::Const(_, generics, _) | ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics) | ItemKind::Union(_, generics) => generics, @@ -762,6 +763,7 @@ pub(super) fn type_param_predicates( ItemKind::Fn(.., generics, _) | ItemKind::Impl(&hir::Impl { generics, .. }) | ItemKind::TyAlias(_, generics) + | ItemKind::Const(_, generics, _) | ItemKind::OpaqueTy(&OpaqueTy { generics, origin: hir::OpaqueTyOrigin::TyAlias { .. }, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 5e261f80387..3cc6f574aec 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -518,7 +518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) | hir::ItemKind::GlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); @@ -583,6 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) } hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::Enum(_, generics) | hir::ItemKind::Struct(_, generics) | hir::ItemKind::Union(_, generics) @@ -590,21 +590,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::TraitAlias(generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. - let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); - self.record_late_bound_vars(item.hir_id(), vec![]); - let scope = Scope::Binder { - hir_id: item.hir_id(), - bound_vars, - scope_type: BinderScopeType::Normal, - s: self.scope, - where_bound_origin: None, - }; - self.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| { - intravisit::walk_item(this, item); - }); - }); + self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item)); } } } @@ -777,39 +763,24 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(_, _) => { - self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { + self.visit_early_late(trait_item.hir_id(), trait_item.generics, |this| { intravisit::walk_trait_item(this, trait_item) }); } Type(bounds, ty) => { - let generics = &trait_item.generics; - let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); - self.record_late_bound_vars(trait_item.hir_id(), vec![]); - let scope = Scope::Binder { - hir_id: trait_item.hir_id(), - bound_vars, - s: self.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; - self.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - if let Some(ty) = ty { - this.visit_ty(ty); - } - }) - }); - } - Const(_, _) => { - // Only methods and types support generics. - assert!(trait_item.generics.params.is_empty()); - intravisit::walk_trait_item(self, trait_item); + self.visit_early(trait_item.hir_id(), trait_item.generics, |this| { + this.visit_generics(&trait_item.generics); + for bound in bounds { + this.visit_param_bound(bound); + } + if let Some(ty) = ty { + this.visit_ty(ty); + } + }) } + Const(_, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| { + intravisit::walk_trait_item(this, trait_item) + }), } } @@ -817,34 +788,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; match impl_item.kind { - Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { + Fn(..) => self.visit_early_late(impl_item.hir_id(), impl_item.generics, |this| { + intravisit::walk_impl_item(this, impl_item) + }), + Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| { + this.visit_generics(impl_item.generics); + this.visit_ty(ty); + }), + Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| { intravisit::walk_impl_item(this, impl_item) }), - Type(ty) => { - let generics = &impl_item.generics; - let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = - generics.params.iter().map(ResolvedArg::early).collect(); - self.record_late_bound_vars(impl_item.hir_id(), vec![]); - let scope = Scope::Binder { - hir_id: impl_item.hir_id(), - bound_vars, - s: self.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; - self.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| { - this.visit_generics(generics); - this.visit_ty(ty); - }) - }); - } - Const(_, _) => { - // Only methods and types support generics. - assert!(impl_item.generics.params.is_empty()); - intravisit::walk_impl_item(self, impl_item); - } } } @@ -1180,6 +1133,25 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.with(scope, walk); } + fn visit_early<F>(&mut self, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F) + where + F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>), + { + let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); + self.record_late_bound_vars(hir_id, vec![]); + let scope = Scope::Binder { + hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, walk) + }); + } + #[instrument(level = "debug", skip(self))] fn resolve_lifetime_ref( &mut self, @@ -2040,8 +2012,7 @@ fn is_late_bound_map( tcx.sess.delay_span_bug( *span, format!( - "Incorrect generic arg count for alias {:?}", - alias_def + "Incorrect generic arg count for alias {alias_def:?}" ), ); None diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c39edaa1577..2bbdbe3a1f6 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -156,7 +156,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { return Ty::new_error_with_message(tcx, tcx.def_span(def_id), - format!("unable to find type-dependent def for {:?}", parent_node_id), + format!("unable to find type-dependent def for {parent_node_id:?}"), ); }; let idx = segment @@ -197,14 +197,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } else { return Ty::new_error_with_message(tcx, tcx.def_span(def_id), - format!("unable to find const parent for {} in pat {:?}", hir_id, pat), + format!("unable to find const parent for {hir_id} in pat {pat:?}"), ); } } _ => { return Ty::new_error_with_message(tcx, tcx.def_span(def_id), - format!("unexpected const parent path {:?}", parent_node), + format!("unexpected const parent path {parent_node:?}"), ); } }; @@ -404,7 +404,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty icx.to_ty(ty) } } - ItemKind::Const(ty, body_id) => { + ItemKind::Const(ty, _, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, def_id, body_id, ty.span, item.ident, "constant", @@ -544,7 +544,7 @@ fn infer_placeholder_type<'a>( if let Some(ty) = ty.make_suggestable(tcx, false) { err.span_suggestion( span, - format!("provide a type for the {item}", item = kind), + format!("provide a type for the {kind}"), format!("{colon} {ty}"), Applicability::MachineApplicable, ); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c2d2e5f7e50..0babdf7e5b3 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -216,7 +216,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { "parameters", self.missing_type_params .iter() - .map(|n| format!("`{}`", n)) + .map(|n| format!("`{n}`")) .collect::<Vec<_>>() .join(", "), ); diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f1765174d79..ca7679cfba0 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -130,7 +130,7 @@ fn diagnostic_hir_wf_check<'tcx>( hir::Node::Item(item) => match item.kind { hir::ItemKind::TyAlias(ty, _) | hir::ItemKind::Static(ty, _, _) - | hir::ItemKind::Const(ty, _) => vec![ty], + | hir::ItemKind::Const(ty, _, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 62f22bda9f9..4f705eaf10a 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -77,8 +77,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) tcx.sess.delay_span_bug( tcx.def_span(impl_def_id), format!( - "potentially unconstrained type parameters weren't evaluated: {:?}", - impl_self_ty, + "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}", ), ); return; @@ -180,7 +179,7 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol kind, name ); - err.span_label(span, format!("unconstrained {} parameter", kind)); + err.span_label(span, format!("unconstrained {kind} parameter")); if kind == "const" { err.note( "expressions using a const parameter must map each value to a distinct output value", diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 81993789bcf..8b2c93d8fd3 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -294,7 +294,7 @@ fn check_duplicate_params<'tcx>( if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; tcx.sess - .struct_span_err(span, format!("specializing impl repeats parameter `{}`", param)) + .struct_span_err(span, format!("specializing impl repeats parameter `{param}`")) .emit(); } } @@ -523,7 +523,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc } _ => { tcx.sess - .struct_span_err(span, format!("cannot specialize on predicate `{}`", predicate)) + .struct_span_err(span, format!("cannot specialize on predicate `{predicate}`")) .emit(); } } diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 0828fe9e0f2..6be8d72aed2 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { verb ) } else { - format!("missing generics for {} `{}`", def_kind, def_path) + format!("missing generics for {def_kind} `{def_path}`") } } @@ -599,7 +599,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let span = self.path_segment.ident.span; // insert a suggestion of the form "Y<'a, 'b>" - let sugg = format!("<{}>", suggested_args); + let sugg = format!("<{suggested_args}>"); debug!("sugg: {:?}", sugg); err.span_suggestion_verbose( @@ -624,7 +624,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let sugg_suffix = if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" }; - let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix); + let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}"); debug!("sugg: {:?}", sugg); err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders); @@ -649,7 +649,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let span = self.path_segment.ident.span; // insert a suggestion of the form "Y<T, U>" - let sugg = format!("<{}>", suggested_args); + let sugg = format!("<{suggested_args}>"); debug!("sugg: {:?}", sugg); err.span_suggestion_verbose( @@ -682,7 +682,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let sugg_suffix = if is_first && !self.gen_args.bindings.is_empty() { ", " } else { "" }; - let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix); + let sugg = format!("{sugg_prefix}{suggested_args}{sugg_suffix}"); debug!("sugg: {:?}", sugg); err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders); @@ -1024,7 +1024,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .collect::<Vec<_>>() .join(", "); - format!(": {}", params) + format!(": {params}") }; format!( diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs index 3b286bb9c93..ed03c5da26f 100644 --- a/compiler/rustc_hir_analysis/src/variance/terms.rs +++ b/compiler/rustc_hir_analysis/src/variance/terms.rs @@ -32,8 +32,8 @@ pub enum VarianceTerm<'a> { impl<'a> fmt::Debug for VarianceTerm<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ConstantTerm(c1) => write!(f, "{:?}", c1), - TransformTerm(v1, v2) => write!(f, "({:?} \u{00D7} {:?})", v1, v2), + ConstantTerm(c1) => write!(f, "{c1:?}"), + TransformTerm(v1, v2) => write!(f, "({v1:?} \u{00D7} {v2:?})"), InferredTerm(id) => write!(f, "[{}]", { let InferredIndex(i) = id; i diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a699cd6c942..2d8b956771b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -420,12 +420,13 @@ impl<'a> State<'a> { fn print_associated_const( &mut self, ident: Ident, + generics: &hir::Generics<'_>, ty: &hir::Ty<'_>, default: Option<hir::BodyId>, ) { - self.head(""); 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 { @@ -433,6 +434,7 @@ impl<'a> State<'a> { self.word_space("="); self.ann.nested(self, Nested::Body(expr)); } + self.print_where_clause(generics); self.word(";") } @@ -532,9 +534,10 @@ impl<'a> State<'a> { self.word(";"); self.end(); // end the outer cbox } - hir::ItemKind::Const(ty, expr) => { + hir::ItemKind::Const(ty, generics, expr) => { self.head("const"); self.print_ident(item.ident); + self.print_generic_params(generics.params); self.word_space(":"); self.print_type(ty); self.space(); @@ -542,6 +545,7 @@ impl<'a> State<'a> { self.word_space("="); self.ann.nested(self, Nested::Body(expr)); + self.print_where_clause(generics); self.word(";"); self.end(); // end the outer cbox } @@ -836,7 +840,7 @@ impl<'a> State<'a> { self.print_outer_attributes(self.attrs(ti.hir_id())); match ti.kind { hir::TraitItemKind::Const(ty, default) => { - self.print_associated_const(ti.ident, ty, default); + self.print_associated_const(ti.ident, ti.generics, ty, default); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => { self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None); @@ -865,7 +869,7 @@ impl<'a> State<'a> { match ii.kind { hir::ImplItemKind::Const(ty, expr) => { - self.print_associated_const(ii.ident, ty, Some(expr)); + self.print_associated_const(ii.ident, ii.generics, ty, Some(expr)); } hir::ImplItemKind::Fn(ref sig, body) => { self.head(""); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 3d012a15a67..2281343e250 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -77,6 +77,10 @@ hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters +hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expected_ty}` to `{$expr_ty}` +hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}` +hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}` + hir_typeck_return_stmt_outside_of_fn_body = {$statement_kind} statement outside of function body .encl_body_label = the {$statement_kind} is part of this body... diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index a1fd09d4050..c68f2d94f35 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -402,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .sess .struct_span_err( callee_expr.span, - format!("evaluate({:?}) = {:?}", predicate, result), + format!("evaluate({predicate:?}) = {result:?}"), ) .span_label(predicate_span, "predicate") .emit(); @@ -531,8 +531,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let up_to_rcvr_span = segment.ident.span.until(callee_expr.span); - let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); + let Some(callee_expr_span) = callee_expr.span.find_ancestor_inside(call_expr.span) + else { + return; + }; + let up_to_rcvr_span = segment.ident.span.until(callee_expr_span); + let rest_span = callee_expr_span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); let rest_snippet = if let Some(first) = rest.first() { self.tcx .sess diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index af8afcc0f0b..5bc0e2ee86c 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let reported = self .tcx .sess - .delay_span_bug(span, format!("`{:?}` should be sized but is not?", t)); + .delay_span_bug(span, format!("`{t:?}` should be sized but is not?")); return Err(reported); } }) @@ -644,12 +644,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.span_suggestion( self.cast_span, "try casting to a reference instead", - format!("&{}{}", mtstr, s), + format!("&{mtstr}{s}"), Applicability::MachineApplicable, ); } Err(_) => { - let msg = format!("did you mean `&{}{}`?", mtstr, tstr); + let msg = format!("did you mean `&{mtstr}{tstr}`?"); err.span_help(self.cast_span, msg); } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index affeee55e79..ca3b595d238 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); - let mut fcx = FnCtxt::new(self, self.param_env.without_const(), closure.def_id); + let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id); let generator_types = check_fn( &mut fcx, liberated_sig, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 56e485a4a3c..4fdfc51bc86 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1797,8 +1797,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.span_note( sp, format!( - "return type inferred to be `{}` here", - expected + "return type inferred to be `{expected}` here" ), ); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 05906a4b9f5..36096aa35d4 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -252,6 +252,45 @@ impl HelpUseLatestEdition { } } +#[derive(Subdiagnostic)] +pub enum OptionResultRefMismatch<'tcx> { + #[suggestion( + hir_typeck_option_result_copied, + code = ".copied()", + style = "verbose", + applicability = "machine-applicable" + )] + Copied { + #[primary_span] + span: Span, + def_path: String, + }, + #[suggestion( + hir_typeck_option_result_cloned, + code = ".cloned()", + style = "verbose", + applicability = "machine-applicable" + )] + Cloned { + #[primary_span] + span: Span, + def_path: String, + }, + #[suggestion( + hir_typeck_option_result_asref, + code = ".as_ref()", + style = "verbose", + applicability = "machine-applicable" + )] + AsRef { + #[primary_span] + span: Span, + def_path: String, + expected_ty: Ty<'tcx>, + expr_ty: Ty<'tcx>, + }, +} + #[derive(Diagnostic)] #[diag(hir_typeck_const_select_must_be_const)] #[help] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 29488c9011a..8f5737dd4ad 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1334,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { t_cast, t.span, expr.span, - self.param_env.constness(), + hir::Constness::NotConst, ) { Ok(cast_check) => { debug!( @@ -1394,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(( _, hir::Node::Local(hir::Local { ty: Some(ty), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }), + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }), )) = parent_node else { return; @@ -1428,7 +1428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a new function context. let def_id = block.def_id; - let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id); + let fcx = FnCtxt::new(self, self.param_env, def_id); crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(&body.value, expected); @@ -1890,7 +1890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut truncated_fields_error = String::new(); let remaining_fields_names = match &displayable_field_names[..] { - [field1] => format!("`{}`", field1), + [field1] => format!("`{field1}`"), [field1, field2] => format!("`{field1}` and `{field2}`"), [field1, field2, field3] => format!("`{field1}`, `{field2}` and `{field3}`"), _ => { @@ -2117,16 +2117,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty)); + err.span_label(variant_ident_span, format!("`{ty}` defined here")); err.span_label(field.ident.span, "field does not exist"); err.span_suggestion_verbose( expr_span, - format!( - "`{adt}` is a tuple {kind_name}, use the appropriate syntax", - adt = ty, - kind_name = kind_name, - ), - format!("{adt}(/* fields */)", adt = ty), + format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",), + format!("{ty}(/* fields */)"), Applicability::HasPlaceholders, ); } @@ -2243,7 +2239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // dynamic limit, to never omit just one field let limit = if names.len() == 6 { 6 } else { 5 }; let mut display = - names.iter().take(limit).map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", "); + names.iter().take(limit).map(|n| format!("`{n}`")).collect::<Vec<_>>().join(", "); if names.len() > limit { display = format!("{} ... and {} others", display, names.len() - limit); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index fa1056e724a..ecafb50f420 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - let msg = format!("unreachable {}", kind); + let msg = format!("unreachable {kind}"); self.tcx().struct_span_lint_hir( lint::builtin::UNREACHABLE_CODE, id, @@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn tag(&self) -> String { - format!("{:p}", self) + format!("{self:p}") } pub fn local_ty(&self, span: Span, nid: hir::HirId) -> Ty<'tcx> { @@ -1412,9 +1412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess.delay_span_bug( span, format!( - "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty, + "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", ), ); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a9610009db1..e102c51c7ee 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -45,12 +45,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); for cast in deferred_cast_checks.drain(..) { - let prev_env = self.param_env; - self.param_env = self.param_env.with_constness(cast.constness); - cast.check(self); - - self.param_env = prev_env; } *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; @@ -689,7 +684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label( full_call_span, - format!("arguments to this {} are incorrect", call_name), + format!("arguments to this {call_name} are incorrect"), ); } else { err = tcx.sess.struct_span_err_with_code( @@ -796,10 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, None, ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); + err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind && provided_idx.as_usize() == expected_idx.as_usize() @@ -874,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if ty.is_unit() { "()".to_string() } else if ty.is_suggestable(tcx, false) { - format!("/* {} */", ty) + format!("/* {ty} */") } else if let Some(fn_def_id) = fn_def_id && self.tcx.def_kind(fn_def_id).is_fn_like() && let self_implicit = @@ -931,12 +923,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { // FIXME: not suggestable, use something else - format!(" of type `{}`", provided_ty) + format!(" of type `{provided_ty}`") } else { "".to_string() }; - labels - .push((provided_span, format!("unexpected argument{}", provided_ty_name))); + labels.push((provided_span, format!("unexpected argument{provided_ty_name}"))); let mut span = provided_span; if span.can_be_used_for_suggestions() { if arg_idx.index() > 0 @@ -1009,11 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args_span }; let rendered = if !has_error_or_infer([input_ty]) { - format!(" of type `{}`", input_ty) + format!(" of type `{input_ty}`") } else { "".to_string() }; - labels.push((span, format!("an argument{} is missing", rendered))); + labels.push((span, format!("an argument{rendered} is missing"))); suggestion_text = match suggestion_text { SuggestionText::None => SuggestionText::Provide(false), SuggestionText::Provide(_) => SuggestionText::Provide(true), @@ -1034,13 +1025,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rendered = if !has_error_or_infer([first_expected_ty, second_expected_ty]) { format!( - " of type `{}` and `{}`", - first_expected_ty, second_expected_ty + " of type `{first_expected_ty}` and `{second_expected_ty}`" ) } else { "".to_string() }; - labels.push((span, format!("two arguments{} are missing", rendered))); + labels.push((span, format!("two arguments{rendered} are missing"))); suggestion_text = match suggestion_text { SuggestionText::None | SuggestionText::Provide(_) => { SuggestionText::Provide(true) @@ -1066,13 +1056,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { third_expected_ty, ]) { format!( - " of type `{}`, `{}`, and `{}`", - first_expected_ty, second_expected_ty, third_expected_ty + " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`" ) } else { "".to_string() }; - labels.push((span, format!("three arguments{} are missing", rendered))); + labels.push((span, format!("three arguments{rendered} are missing"))); suggestion_text = match suggestion_text { SuggestionText::None | SuggestionText::Provide(_) => { SuggestionText::Provide(true) @@ -1113,25 +1102,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { - format!(", found `{}`", first_provided_ty) + format!(", found `{first_provided_ty}`") } else { String::new() }; labels.push(( first_span, - format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), + format!("expected `{first_expected_ty}`{first_provided_ty_name}"), )); let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { - format!(", found `{}`", second_provided_ty) + format!(", found `{second_provided_ty}`") } else { String::new() }; labels.push(( second_span, - format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), + format!("expected `{second_expected_ty}`{second_provided_ty_name}"), )); suggestion_text = match suggestion_text { @@ -1144,13 +1133,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; let (provided_ty, provided_span) = provided_arg_tys[dest_input]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { - format!(", found `{}`", provided_ty) + format!(", found `{provided_ty}`") } else { String::new() }; labels.push(( provided_span, - format!("expected `{}`{}", expected_ty, provided_ty_name), + format!("expected `{expected_ty}`{provided_ty_name}"), )); } @@ -2031,7 +2020,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ("closure", self.tcx.def_span(def_id)) }; - err.span_note(span, format!("{} defined here", kind)); + err.span_note(span, format!("{kind} defined here")); } else { err.span_note( self.tcx.def_span(def_id), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 4a1cbaceaf7..c49e4381897 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,8 +1,6 @@ use super::FnCtxt; -use crate::errors::{ - AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod, -}; +use crate::errors; use crate::fluent_generated as fluent; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; @@ -397,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let struct_pat_shorthand_field = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr); if let Some(name) = struct_pat_shorthand_field { - sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); + sugg.insert(0, (expr.span.shrink_to_lo(), format!("{name}: "))); } Some(sugg) }) @@ -434,7 +432,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, // but those checks need to be a bit more delicate and the benefit is diminishing. if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { - err.subdiagnostic(SuggestConvertViaMethod { + err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), sugg: ".as_ref()", expected, @@ -447,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, deref_ty, peeled) && error_tys_equate_as_ref { - err.subdiagnostic(SuggestConvertViaMethod { + err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), sugg: ".as_deref()", expected, @@ -521,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.can_coerce(Ty::new_box(self.tcx, found), expected) { let suggest_boxing = match found.kind() { ty::Tuple(tuple) if tuple.is_empty() => { - SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } + errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span } } ty::Generator(def_id, ..) if matches!( @@ -529,9 +527,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) ) => { - SuggestBoxing::AsyncBody + errors::SuggestBoxing::AsyncBody } - _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() }, + _ => errors::SuggestBoxing::Other { + start: span.shrink_to_lo(), + end: span.shrink_to_hi(), + }, }; err.subdiagnostic(suggest_boxing); @@ -558,7 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .take(4) .map(|(var_hir_id, upvar)| { let var_name = self.tcx.hir().name(*var_hir_id).to_string(); - let msg = format!("`{}` captured here", var_name); + let msg = format!("`{var_name}` captured here"); (upvar.span, msg) }) .collect::<Vec<_>>(); @@ -756,23 +757,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &fn_decl.output { &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); return true; } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { if let Some(found) = found.make_suggestable(self.tcx, false) { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); return true; } else if let ty::Closure(_, args) = found.kind() // FIXME(compiler-errors): Get better at printing binders... && let closure = args.as_closure() && closure.sig().is_suggestable(self.tcx, false) { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. - err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); return true } } @@ -794,10 +795,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?found); if found.is_suggestable(self.tcx, false) { if term.span.is_empty() { - err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); return true; } else { - err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); } } } @@ -813,7 +814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.normalize(span, ty); let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { - err.subdiagnostic(ExpectedReturnTypeLabel::Other { span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span, expected }); self.try_suggest_return_impl_trait(err, expected, ty, fn_id); return true; } @@ -931,7 +932,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( fn_return.span(), "consider using an impl return type", - format!("impl {}", all_bounds_str), + format!("impl {all_bounds_str}"), Applicability::MaybeIncorrect, ); } @@ -1070,7 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .must_apply_modulo_regions() { let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!(": {}.clone()", ident), + Some(ident) => format!(": {ident}.clone()"), None => ".clone()".to_string() }; @@ -1103,65 +1104,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let mut suggest_copied_cloned_or_as_ref = || { + if Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Result) + && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1)) + || Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Option) + { let expr_inner_ty = args.type_at(0); let expected_inner_ty = expected_args.type_at(0); - if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() - && self.can_eq(self.param_env, ty, expected_inner_ty) - { - let def_path = self.tcx.def_path_str(adt_def.did()); - if self.type_is_copy_modulo_regions(self.param_env, ty) { - diag.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `{def_path}::copied` to copy the value inside the `{def_path}`" - ), - ".copied()", - Applicability::MachineApplicable, - ); - return true; - } else if let Some(expected_ty_expr) = expected_ty_expr { - diag.span_suggestion_verbose( - expected_ty_expr.span.shrink_to_hi(), - format!( - "use `{def_path}::as_ref()` to convert `{expected_ty}` to `{expr_ty}`" - ), - ".as_ref()", - Applicability::MachineApplicable, - ); - return true; - } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() - && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( - self, - self.param_env, - ty, - clone_did, - ) + if let &ty::Ref(_, ty, mutability) = expr_inner_ty.kind() + && self.can_eq(self.param_env, ty, expected_inner_ty) { - diag.span_suggestion_verbose( - expr.span.shrink_to_hi(), - format!( - "use `{def_path}::cloned` to clone the value inside the `{def_path}`" - ), - ".cloned()", - Applicability::MachineApplicable, - ); + let def_path = self.tcx.def_path_str(adt_def.did()); + let span = expr.span.shrink_to_hi(); + let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { + errors::OptionResultRefMismatch::Copied { + span, def_path + } + } else if let Some(expected_ty_expr) = expected_ty_expr + // FIXME: suggest changes to both expressions to convert both to + // Option/Result<&T> + && mutability.is_not() + { + errors::OptionResultRefMismatch::AsRef { + span: expected_ty_expr.span.shrink_to_hi(), expected_ty, expr_ty, def_path + } + } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() + && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + self, + self.param_env, + ty, + clone_did, + ) + { + errors::OptionResultRefMismatch::Cloned { + span, def_path + } + } else { + return false; + }; + diag.subdiagnostic(subdiag); return true; } - } - false - }; - - if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result) - && adt_def.did() == result_did - // Check that the error types are equal - && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1)) - { - return suggest_copied_cloned_or_as_ref(); - } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option) - && adt_def.did() == option_did - { - return suggest_copied_cloned_or_as_ref(); } false @@ -1259,7 +1241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!(": {}.is_some()", ident), + Some(ident) => format!(": {ident}.is_some()"), None => ".is_some()".to_string(), }; diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index e01dcf83a38..e563bd40b65 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -125,8 +125,8 @@ impl Debug for TrackedValue { write!(f, "{}", tcx.hir().node_to_string(self.hir_id())) } else { match self { - Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id), - Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id), + Self::Variable(hir_id) => write!(f, "Variable({hir_id:?})"), + Self::Temporary(hir_id) => write!(f, "Temporary({hir_id:?})"), } } }) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 86ea092bc40..6a817122491 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.fcx .tcx .sess - .delay_span_bug(span, format!("Encountered var {:?}", unresolved_term)); + .delay_span_bug(span, format!("Encountered var {unresolved_term:?}")); } else { let note = format!( "the type is part of the {} because of this {}", diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 2d85451c9e1..4e65182f158 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), Ok(SizeSkeleton::Known(size)) => { if let Some(v) = u128::from(size.bytes()).checked_mul(8) { - format!("{} bits", v) + format!("{v} bits") } else { // `u128` should definitely be able to hold the size of different architectures // larger sizes should be reported as error `are too big for the current architecture` @@ -122,14 +122,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); - let mut should_delay_as_bug = false; - if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() { - should_delay_as_bug = true; - } - if let Err(LayoutError::Unknown(bad_to)) = sk_to && bad_to.references_error() { - should_delay_as_bug = true; - } - if should_delay_as_bug { + if let Err(LayoutError::ReferencesError(_)) = sk_from { + err.delay_as_bug(); + } else if let Err(LayoutError::ReferencesError(_)) = sk_to { err.delay_as_bug(); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 28e7f290737..c4d3cbc9faa 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -71,7 +71,7 @@ use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::{sym, Span}; +use rustc_span::Span; fluent_messages! { "../messages.ftl" } @@ -101,7 +101,7 @@ fn primary_body_of( ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { match node { Node::Item(item) => match item.kind { - hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { + hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => { Some((body, Some(ty), None)) } hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), @@ -182,11 +182,7 @@ fn typeck_with_fallback<'tcx>( let body = tcx.hir().body(body_id); let param_env = tcx.param_env(def_id); - let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) { - param_env.without_const() - } else { - param_env - }; + let inh = Inherited::new(tcx, def_id); let mut fcx = FnCtxt::new(&inh, param_env, def_id); @@ -263,11 +259,7 @@ fn typeck_with_fallback<'tcx>( // Closure and generator analysis may run after fallback // because they don't constrain other type variables. - // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now) - let prev_constness = fcx.param_env.constness(); - fcx.param_env = fcx.param_env.without_const(); fcx.closure_analyze(body); - fcx.param_env = fcx.param_env.with_constness(prev_constness); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); // Before the generator analysis, temporary scopes shall be marked to provide more // precise information on types to be captured. diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6835782b5bd..7c73f6a89cd 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -225,7 +225,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert!(mutbl.is_mut()); Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) } - other => panic!("Cannot adjust receiver type {:?} to const ptr", other), + other => panic!("Cannot adjust receiver type {other:?} to const ptr"), }; adjustments.push(Adjustment { @@ -262,8 +262,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let impl_def_id = pick.item.container_id(self.tcx); assert!( self.tcx.impl_trait_ref(impl_def_id).is_none(), - "impl {:?} is not an inherent impl", - impl_def_id + "impl {impl_def_id:?} is not an inherent impl" ); self.fresh_args_for_item(self.span, impl_def_id) } diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 4efe95c4dc5..5b19a4c525f 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -97,28 +97,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}{} as *const _", derefs, self_expr) + format!("{derefs}{self_expr} as *const _") } else { - format!("{}{}{}", autoref, derefs, self_expr) + format!("{autoref}{derefs}{self_expr}") }; lint.span_suggestion( sp, "disambiguate the method call", - format!("({})", self_adjusted), + format!("({self_adjusted})"), Applicability::MachineApplicable, ); } else { let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}(...) as *const _", derefs) + format!("{derefs}(...) as *const _") } else { - format!("{}{}...", autoref, derefs) + format!("{autoref}{derefs}...") }; lint.span_help( sp, - format!("disambiguate the method call with `({})`", self_adjusted,), + format!("disambiguate the method call with `({self_adjusted})`",), ); } @@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .ok()) { // Keep turbofish. - format!("::{}", args) + format!("::{args}") } else { String::new() }, @@ -347,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Glob import, so just use its name. return None; } else { - return Some(format!("{}", any_id)); + return Some(format!("{any_id}")); } } @@ -396,9 +396,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { - format!("{}{} as *const _", derefs, expr_text) + format!("{derefs}{expr_text} as *const _") } else { - format!("{}{}{}", autoref, derefs, expr_text) + format!("{autoref}{derefs}{expr_text}") }; (adjusted_text, precise) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3d7187cb16f..f6c07931023 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0034, "multiple applicable items in scope" ); - err.span_label(item_name.span, format!("multiple `{}` found", item_name)); + err.span_label(item_name.span, format!("multiple `{item_name}` found")); self.note_candidates_on_method_error( rcvr_ty, @@ -177,13 +177,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind, item_name ); - err.span_label(item_name.span, format!("private {}", kind)); + err.span_label(item_name.span, format!("private {kind}")); let sp = self .tcx .hir() .span_if_local(def_id) .unwrap_or_else(|| self.tcx.def_span(def_id)); - err.span_label(sp, format!("private {} defined here", kind)); + err.span_label(sp, format!("private {kind} defined here")); self.suggest_valid_traits(&mut err, out_of_scope_traits); err.emit(); } @@ -218,7 +218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, ); - let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty); + let msg = format!("you need `{trait_type}` instead of `{rcvr_ty}`"); let mut kind = &self_expr.kind; while let hir::ExprKind::AddrOf(_, _, expr) | hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind @@ -637,7 +637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Point at the closure that couldn't satisfy the bound. ty::Closure(def_id, _) => bound_spans - .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), + .push((tcx.def_span(*def_id), format!("doesn't satisfy `{quiet}`"))), _ => {} } }; @@ -659,7 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let term = pred.skip_binder().term; - let obligation = format!("{} = {}", projection_ty, term); + let obligation = format!("{projection_ty} = {term}"); let quiet = with_forced_trimmed_paths!(format!( "{} = {}", quiet_projection_ty, term @@ -672,7 +672,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); - let obligation = format!("{}: {}", self_ty, path); + let obligation = format!("{self_ty}: {path}"); let quiet = with_forced_trimmed_paths!(format!("_: {}", path)); bound_span_label(self_ty, &obligation, &quiet); Some((obligation, self_ty)) @@ -825,12 +825,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut preds: Vec<_> = predicates .iter() .filter_map(|pred| format_pred(**pred)) - .map(|(p, _)| format!("`{}`", p)) + .map(|(p, _)| format!("`{p}`")) .collect(); preds.sort(); preds.dedup(); let msg = if let [pred] = &preds[..] { - format!("trait bound {} was not satisfied", pred) + format!("trait bound {pred} was not satisfied") } else { format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),) }; @@ -875,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggested_bounds.insert(pred); } } - format!("`{}`\nwhich is required by `{}`", p, parent_p) + format!("`{p}`\nwhich is required by `{parent_p}`") } }, }, @@ -1034,8 +1034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "".to_string() }; err.note(format!( - "the {item_kind} was found for\n{}{}", - type_candidates, additional_types + "the {item_kind} was found for\n{type_candidates}{additional_types}" )); } else { 'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) { @@ -1249,8 +1248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { ( format!( - "the candidate is defined in an impl{} for the type `{}`", - insertion, impl_ty, + "the candidate is defined in an impl{insertion} for the type `{impl_ty}`", ), None, ) @@ -1452,11 +1450,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( sugg_span, "use associated function syntax instead", - format!("{}::{}{}", ty_str, item_name, args), + format!("{ty_str}::{item_name}{args}"), applicability, ); } else { - err.help(format!("try with `{}::{}`", ty_str, item_name,)); + err.help(format!("try with `{ty_str}::{item_name}`",)); } } @@ -1491,9 +1489,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_span = expr.span.to(item_name.span); err.multipart_suggestion( format!( - "to call the function stored in `{}`, \ + "to call the function stored in `{item_name}`, \ surround the field access with parentheses", - item_name, ), vec![ (expr_span.shrink_to_lo(), '('.to_string()), @@ -1516,7 +1513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let field_kind = if is_accessible { "field" } else { "private field" }; - err.span_label(item_name.span, format!("{}, not a method", field_kind)); + err.span_label(item_name.span, format!("{field_kind}, not a method")); return true; } false @@ -1669,8 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lit.span, format!( "you must specify a concrete type for this numeric value, \ - like `{}`", - concrete_type + like `{concrete_type}`" ), format!("{snippet}_{concrete_type}"), Applicability::MaybeIncorrect, @@ -1685,8 +1681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_node = self.tcx.hir().get_parent(hir_id); let msg = format!( - "you must specify a type for this binding, like `{}`", - concrete_type, + "you must specify a type for this binding, like `{concrete_type}`", ); match (filename, parent_node) { @@ -2194,7 +2189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut() { if last_self_name == &self_name { - last_trait_names.push_str(format!(", {}", trait_name).as_str()); + last_trait_names.push_str(format!(", {trait_name}").as_str()); continue; } } @@ -2226,8 +2221,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (self_name, self_span, traits) in &derives_grouped { err.span_suggestion_verbose( self_span.shrink_to_lo(), - format!("consider annotating `{}` with `#[derive({})]`", self_name, traits), - format!("#[derive({})]\n", traits), + format!("consider annotating `{self_name}` with `#[derive({traits})]`"), + format!("#[derive({traits})]\n"), Applicability::MaybeIncorrect, ); } @@ -2475,7 +2470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pick.autoderefs == 0 && !skip { err.span_label( pick.item.ident(self.tcx).span, - format!("the method is available for `{}` here", rcvr_ty), + format!("the method is available for `{rcvr_ty}` here"), ); } break; @@ -2521,13 +2516,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if pick.autoderefs == 0 && !skip { err.span_label( pick.item.ident(self.tcx).span, - format!("the method is available for `{}` here", new_rcvr_t), + format!("the method is available for `{new_rcvr_t}` here"), ); err.multipart_suggestion( "consider wrapping the receiver expression with the \ appropriate type", vec![ - (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), + (rcvr.span.shrink_to_lo(), format!("{pre}({post}")), (rcvr.span.shrink_to_hi(), ")".to_string()), ], Applicability::MaybeIncorrect, @@ -2767,7 +2762,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; err.span_suggestions( sp, - message(format!("add {} supertrait for", article)), + message(format!("add {article} supertrait for")), candidates.iter().map(|t| { format!("{} {}", sep, self.tcx.def_path_str(t.def_id),) }), @@ -2836,7 +2831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_infos => { let mut msg = message(param_type.map_or_else( || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. - |param| format!("restrict type parameter `{}` with", param), + |param| format!("restrict type parameter `{param}` with"), )); for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( @@ -2860,8 +2855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } trait_infos => { let mut msg = format!( - "the following traits define an item `{}`, but are explicitly unimplemented:", - item_name + "the following traits define an item `{item_name}`, but are explicitly unimplemented:" ); for trait_info in trait_infos { msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id))); @@ -3027,13 +3021,13 @@ fn print_disambiguation_help<'tcx>( .join(", "), ); let trait_name = if !fn_has_self_parameter { - format!("<{} as {}>", rcvr_ty, trait_name) + format!("<{rcvr_ty} as {trait_name}>") } else { trait_name }; - (span, format!("{}::{}{}", trait_name, item_name, args)) + (span, format!("{trait_name}::{item_name}{args}")) } else { - (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name)) + (span.with_hi(item_name.span.lo()), format!("<{rcvr_ty} as {trait_name}>::")) }; err.span_suggestion_verbose( span, @@ -3041,7 +3035,7 @@ fn print_disambiguation_help<'tcx>( "disambiguate the {} for {}", def_kind_descr, if let Some(candidate) = candidate { - format!("candidate #{}", candidate) + format!("candidate #{candidate}") } else { "the candidate".to_string() }, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8bf95d4bf9a..4d236a86dda 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -516,7 +516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) { if !ty.references_error() { - err.span_label(span, format!("this is of type `{}`", ty)); + err.span_label(span, format!("this is of type `{ty}`")); } } @@ -540,7 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let msg = |ty| { let ty = self.resolve_vars_if_possible(ty); - format!("this is of type `{}` but it should be `char` or numeric", ty) + format!("this is of type `{ty}` but it should be `char` or numeric") }; let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, msg(first_ty)); @@ -653,7 +653,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); let pre = if in_match { "in the same arm, " } else { "" }; - err.note(format!("{}a binding must have the same type in all alternatives", pre)); + err.note(format!("{pre}a binding must have the same type in all alternatives")); self.suggest_adding_missing_ref_or_removing_ref( &mut err, span, @@ -924,7 +924,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match opt_def_id { Some(def_id) => match self.tcx.hir().get_if_local(def_id) { Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, body_id), .. + kind: hir::ItemKind::Const(_, _, body_id), + .. })) => match self.tcx.hir().get(body_id.hir_id) { hir::Node::Expr(expr) => { if hir::is_range_literal(expr) { @@ -1710,7 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), "use the tuple variant pattern syntax instead", - format!("({})", sugg), + format!("({sugg})"), appl, ); return Some(err); @@ -1812,7 +1813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { const LIMIT: usize = 3; match witnesses { [] => bug!(), - [witness] => format!("`{}`", witness), + [witness] => format!("`{witness}`"), [head @ .., tail] if head.len() < LIMIT => { let head: Vec<_> = head.iter().map(<_>::to_string).collect(); format!("`{}` and `{}`", head.join("`, `"), tail) @@ -1834,8 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ensure that all fields are mentioned explicitly by adding the suggested fields", ); lint.note(format!( - "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", - ty, + "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", )); lint @@ -1864,10 +1864,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let fields = unmentioned_fields .iter() - .map(|(_, name)| format!("`{}`", name)) + .map(|(_, name)| format!("`{name}`")) .collect::<Vec<String>>() .join(", "); - format!("fields {}{}", fields, inaccessible) + format!("fields {fields}{inaccessible}") }; let mut err = struct_span_err!( self.tcx.sess, @@ -1876,7 +1876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "pattern does not mention {}", field_names ); - err.span_label(pat.span, format!("missing {}", field_names)); + err.span_label(pat.span, format!("missing {field_names}")); let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { @@ -1909,11 +1909,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|(_, name)| { let field_name = name.to_string(); - if is_number(&field_name) { - format!("{}: _", field_name) - } else { - field_name - } + if is_number(&field_name) { format!("{field_name}: _") } else { field_name } }) .collect::<Vec<_>>() .join(", "), @@ -1930,7 +1926,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { s = pluralize!(len), them = if len == 1 { "it" } else { "them" }, ), - format!("{}..{}", prefix, postfix), + format!("{prefix}..{postfix}"), Applicability::MachineApplicable, ); err diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 22fe823acb7..be939560c45 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -109,11 +109,11 @@ impl MigrationWarningReason { fn migration_message(&self) -> String { let base = "changes to closure capture in Rust 2021 will affect"; if !self.auto_traits.is_empty() && self.drop_order { - format!("{} drop order and which traits the closure implements", base) + format!("{base} drop order and which traits the closure implements") } else if self.drop_order { - format!("{} drop order", base) + format!("{base} drop order") } else { - format!("{} which traits the closure implements", base) + format!("{base} which traits the closure implements") } } } @@ -824,8 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>"); let diagnostic_msg = format!( - "add a dummy let to cause {} to be fully captured", - migrated_variables_concat + "add a dummy let to cause {migrated_variables_concat} to be fully captured" ); let closure_span = self.tcx.hir().span_with_body(closure_hir_id); @@ -1943,7 +1942,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String let mut projections_str = String::new(); for (i, item) in place.projections.iter().enumerate() { let proj = match item.kind { - ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b), + ProjectionKind::Field(a, b) => format!("({a:?}, {b:?})"), ProjectionKind::Deref => String::from("Deref"), ProjectionKind::Index => String::from("Index"), ProjectionKind::Subslice => String::from("Subslice"), @@ -1966,7 +1965,7 @@ fn construct_capture_kind_reason_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), + ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} captured as {capture_kind_str} here") @@ -1987,7 +1986,7 @@ fn construct_capture_info_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), + ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} -> {capture_kind_str}") } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 2329a1f63ce..6f47623ec43 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -217,7 +217,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been // emitted, so we delay an ICE if none have. (#64638) - self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base)); + self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{base:?}`")); } if let Some(base_ty) = base_ty && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() @@ -231,7 +231,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { Ty::new_error_with_message( self.fcx.tcx, e.span, - format!("bad index {:?} for base: `{:?}`", index, base), + format!("bad index {index:?} for base: `{base:?}`"), ) }); if self.is_builtin_index(e, base_ty_inner, index_ty) { @@ -488,10 +488,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let span = self.tcx().hir().span(hir_id); // We need to buffer the errors in order to guarantee a consistent // order when emitting them. - let err = self - .tcx() - .sess - .struct_span_err(span, format!("user args: {:?}", user_args)); + let err = + self.tcx().sess.struct_span_err(span, format!("user args: {user_args:?}")); err.buffer(&mut errors_buffer); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d3978e242a8..c000f988aa2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2068,7 +2068,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { visitor.visit_body(body); visitor.result.map(|r| &r.peel_refs().kind) } - Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => { Some(&ty.peel_refs().kind) } _ => None, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 7144084c78e..8cd1b82130b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -243,12 +243,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { let mut err = self.report_concrete_failure(*parent, sub, sup); - let trait_item_span = self.tcx.def_span(trait_item_def_id); - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label( - trait_item_span, - format!("definition of `{}` from trait", item_name), - ); + + // Don't mention the item name if it's an RPITIT, since that'll just confuse + // folks. + if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) { + let trait_item_span = self.tcx.def_span(trait_item_def_id); + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label( + trait_item_span, + format!("definition of `{}` from trait", item_name), + ); + } + self.suggest_copy_trait_method_bounds( trait_item_def_id, impl_item_def_id, diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 626dd9359a1..a9da6104b38 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -79,7 +79,6 @@ impl<'tcx> PredicateObligation<'tcx> { } pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> { - self.param_env = self.param_env.without_const(); if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() { self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const())))); } @@ -88,14 +87,6 @@ impl<'tcx> PredicateObligation<'tcx> { } impl<'tcx> PolyTraitObligation<'tcx> { - /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. - pub fn is_const(&self) -> bool { - matches!( - (self.predicate.skip_binder().constness, self.param_env.constness()), - (ty::BoundConstness::ConstIfConst, hir::Constness::Const) - ) - } - pub fn derived_cause( &self, variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 7826d42dcb2..2c7438ed9db 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [lib] [dependencies] -atty = "0.2.13" libloading = "0.7.1" tracing = "0.1" rustc-rayon-core = { version = "0.5.0", optional = true } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 12d33f06309..ad35dbbc8f9 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -519,7 +519,8 @@ fn multiple_output_types_to_stdout( output_types: &OutputTypes, single_output_file_is_stdout: bool, ) -> bool { - if atty::is(atty::Stream::Stdout) { + use std::io::IsTerminal; + if std::io::stdout().is_terminal() { // If stdout is a tty, check if multiple text output types are // specified by `--emit foo=- --emit bar=-` or `-o - --emit foo,bar` let named_text_types = output_types diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 252177932e4..16e17fc9d6a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -155,8 +155,6 @@ lint_builtin_unused_doc_comment = unused doc comment lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` -lint_cast_ref_to_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} lint_check_name_unknown = unknown lint: `{$lint_name}` @@ -320,6 +318,8 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable +lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead @@ -410,8 +410,8 @@ lint_non_upper_case_global = {$sort} `{$name}` should have an upper case name .label = should have an UPPER_CASE name lint_noop_method_call = call to `.{$method}()` on a reference in this situation does nothing - .label = unnecessary method call - .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed + .suggestion = remove this redundant call + .note = the type `{$orig_ty}` does not implement `{$trait_}`, so calling `{$method}` on `&{$orig_ty}` copies the reference, which does not do anything and can be removed lint_only_cast_u8_to_char = only `u8` can be cast into `char` .suggestion = use a `char` literal instead diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 84aca80b0de..ba05622bf37 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1529,9 +1529,10 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { match it.kind { - hir::ItemKind::Const(_, body_id) => { + hir::ItemKind::Const(_, _, body_id) => { let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); // trigger the query once for all constants since that will already report the errors + // FIXME(generic_const_items): Does this work properly with generic const items? cx.tcx.ensure().const_eval_poly(def_id); } hir::ItemKind::Static(_, _, body_id) => { @@ -1716,7 +1717,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { let end = expr_to_string(&end); let replace = match start { Some(start) => format!("&({}..={})", expr_to_string(&start), end), - None => format!("&(..={})", end), + None => format!("&(..={end})"), }; if join.edition() >= Edition::Edition2021 { cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7c701fd4fe1..f7e56b30553 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -411,7 +411,7 @@ impl LintStore { } let complete_name = if let Some(tool_name) = tool_name { - format!("{}::{}", tool_name, lint_name) + format!("{tool_name}::{lint_name}") } else { lint_name.to_string() }; @@ -424,7 +424,7 @@ impl LintStore { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>()); - let tool_prefix = format!("{}::", tool_name); + let tool_prefix = format!("{tool_name}::"); return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name) } else { @@ -445,11 +445,11 @@ impl LintStore { } match self.by_name.get(&complete_name) { Some(Renamed(new_name, _)) => CheckLintNameResult::Warning( - format!("lint `{}` has been renamed to `{}`", complete_name, new_name), + format!("lint `{complete_name}` has been renamed to `{new_name}`"), Some(new_name.to_owned()), ), Some(Removed(reason)) => CheckLintNameResult::Warning( - format!("lint `{}` has been removed: {}", complete_name, reason), + format!("lint `{complete_name}` has been removed: {reason}"), None, ), None => match self.lint_groups.get(&*complete_name) { @@ -503,7 +503,7 @@ impl LintStore { lint_name: &str, tool_name: &str, ) -> CheckLintNameResult<'_> { - let complete_name = format!("{}::{}", tool_name, lint_name); + let complete_name = format!("{tool_name}::{lint_name}"); match self.by_name.get(&complete_name) { None => match self.lint_groups.get(&*complete_name) { // Now we are sure, that this lint exists nowhere @@ -618,12 +618,10 @@ pub trait LintContext: Sized { _ => ("", "s"), }; db.span_label(span, format!( - "this comment contains {}invisible unicode text flow control codepoint{}", - an, - s, + "this comment contains {an}invisible unicode text flow control codepoint{s}", )); for (c, span) in &spans { - db.span_label(*span, format!("{:?}", c)); + db.span_label(*span, format!("{c:?}")); } db.note( "these kind of unicode codepoints change the way text flows on \ @@ -648,7 +646,7 @@ pub trait LintContext: Sized { let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; - (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) + (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) } Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders), }; @@ -704,7 +702,7 @@ pub trait LintContext: Sized { let introduced = if is_imported { "imported" } else { "defined" }; db.span_label( span, - format!("the item `{}` is already {} here", ident, introduced), + format!("the item `{ident}` is already {introduced} here"), ); } } @@ -908,7 +906,7 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => { db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string"); if let Some(positional_arg_for_msg) = position_sp_for_msg { - let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name); + let msg = format!("this formatting argument uses named argument `{named_arg_name}` by position"); db.span_label(positional_arg_for_msg, msg); } @@ -948,12 +946,15 @@ pub trait LintContext: Sized { Applicability::MachineApplicable, ); } + BuiltinLintDiagnostics::AmbiguousGlobImports { diag } => { + rustc_errors::report_ambiguity_error(db, diag); + } BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => { - db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); - db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); + db.span_label(first_reexport_span, format!("the name `{name}` in the {namespace} namespace is first re-exported here")); + db.span_label(duplicate_reexport_span, format!("but the name `{name}` in the {namespace} namespace is also re-exported here")); } BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => { - db.span_note(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace)); + db.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here")); db.span_note(private_item_span, "but the private item here shadows it".to_owned()); } BuiltinLintDiagnostics::UnusedQualifications { removal_span } => { @@ -1281,8 +1282,8 @@ impl<'tcx> LateContext<'tcx> { // This shouldn't ever be needed, but just in case: with_no_trimmed_paths!({ Ok(vec![match trait_ref { - Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), - None => Symbol::intern(&format!("<{}>", self_ty)), + Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")), + None => Symbol::intern(&format!("<{self_ty}>")), }]) }) } @@ -1306,7 +1307,7 @@ impl<'tcx> LateContext<'tcx> { ))) } None => { - with_no_trimmed_paths!(Symbol::intern(&format!("<impl {}>", self_ty))) + with_no_trimmed_paths!(Symbol::intern(&format!("<impl {self_ty}>"))) } }); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 0c80141a756..fb407be1f02 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -945,7 +945,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { ); } } else { - panic!("renamed lint does not exist: {}", new_name); + panic!("renamed lint does not exist: {new_name}"); } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index beb38dbb94c..53089294fe2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -50,7 +50,6 @@ extern crate tracing; mod array_into_iter; pub mod builtin; -mod cast_ref_to_mut; mod context; mod deref_into_dyn_supertrait; mod drop_forget_useless; @@ -78,6 +77,7 @@ mod opaque_hidden_inferred_bound; mod pass_by_value; mod passes; mod redundant_semicolon; +mod reference_casting; mod traits; mod types; mod unused; @@ -99,7 +99,6 @@ use rustc_span::Span; use array_into_iter::ArrayIntoIter; use builtin::*; -use cast_ref_to_mut::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; @@ -119,6 +118,7 @@ use noop_method_call::*; use opaque_hidden_inferred_bound::*; use pass_by_value::*; use redundant_semicolon::*; +use reference_casting::*; use traits::*; use types::*; use unused::*; @@ -218,7 +218,7 @@ late_lint_methods!( BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, - CastRefToMut: CastRefToMut, + InvalidReferenceCasting: InvalidReferenceCasting, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, NonUpperCaseGlobals: NonUpperCaseGlobals, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1dea758bb29..968172693a9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -743,10 +743,10 @@ pub enum InvalidFromUtf8Diag { }, } -// cast_ref_to_mut.rs +// reference_casting.rs #[derive(LintDiagnostic)] -#[diag(lint_cast_ref_to_mut)] -pub struct CastRefToMutDiag; +#[diag(lint_invalid_reference_casting)] +pub struct InvalidReferenceCastingDiag; // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] @@ -776,7 +776,7 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { ) -> rustc_errors::SubdiagnosticMessage, { for (c, span) in self.spans { - diag.span_label(span, format!("{:?}", c)); + diag.span_label(span, format!("{c:?}")); } } } @@ -808,7 +808,7 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { spans .into_iter() .map(|(c, span)| { - let c = format!("{:?}", c); + let c = format!("{c:?}"); (span, c[1..c.len() - 1].to_string()) }) .collect(), @@ -823,7 +823,7 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { "escaped", spans .into_iter() - .map(|(c, _)| format!("{:?}", c)) + .map(|(c, _)| format!("{c:?}")) .collect::<Vec<String>>() .join(", "), ); @@ -1231,8 +1231,9 @@ pub enum NonUpperCaseGlobalSub { #[note] pub struct NoopMethodCallDiag<'a> { pub method: Symbol, - pub receiver_ty: Ty<'a>, - #[label] + pub orig_ty: Ty<'a>, + pub trait_: Symbol, + #[suggestion(code = "", applicability = "machine-applicable")] pub label: Span, } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 13f650c2008..bc0b9d6d818 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -18,7 +18,6 @@ declare_lint! { /// /// ```rust /// # #![allow(unused)] - /// #![warn(noop_method_call)] /// struct Foo; /// let foo = &Foo; /// let clone: &Foo = foo.clone(); @@ -34,7 +33,7 @@ declare_lint! { /// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything /// as references are copy. This lint detects these calls and warns the user about them. pub NOOP_METHOD_CALL, - Allow, + Warn, "detects the use of well-known noop methods" } @@ -86,10 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let Some(trait_id) = cx.tcx.trait_of_item(did) else { return }; - if !matches!( - cx.tcx.get_diagnostic_name(trait_id), - Some(sym::Borrow | sym::Clone | sym::Deref) - ) { + let Some(trait_) = cx.tcx.get_diagnostic_name(trait_id) else { return }; + + if !matches!(trait_, sym::Borrow | sym::Clone | sym::Deref) { return; }; @@ -114,11 +112,13 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let expr_span = expr.span; let span = expr_span.with_lo(receiver.span.hi()); + let orig_ty = expr_ty.peel_refs(); + if receiver_ty == expr_ty { cx.emit_spanned_lint( NOOP_METHOD_CALL, span, - NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span }, + NoopMethodCallDiag { method: call.ident.name, orig_ty, trait_, label: span }, ); } else { match name { diff --git a/compiler/rustc_lint/src/cast_ref_to_mut.rs b/compiler/rustc_lint/src/reference_casting.rs index 82bb70bc9e7..d343aaf35d5 100644 --- a/compiler/rustc_lint/src/cast_ref_to_mut.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -3,15 +3,16 @@ use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp}; use rustc_middle::ty; use rustc_span::sym; -use crate::{lints::CastRefToMutDiag, LateContext, LateLintPass, LintContext}; +use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext}; declare_lint! { - /// The `cast_ref_to_mut` lint checks for casts of `&T` to `&mut T` + /// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T` /// without using interior mutability. /// /// ### Example /// /// ```rust,compile_fail + /// # #![deny(invalid_reference_casting)] /// fn x(r: &i32) { /// unsafe { /// *(r as *const i32 as *mut i32) += 1; @@ -28,14 +29,14 @@ declare_lint! { /// /// `UnsafeCell` is the only way to obtain aliasable data that is considered /// mutable. - CAST_REF_TO_MUT, - Deny, + INVALID_REFERENCE_CASTING, + Allow, "casts of `&T` to `&mut T` without interior mutability" } -declare_lint_pass!(CastRefToMut => [CAST_REF_TO_MUT]); +declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]); -impl<'tcx> LateLintPass<'tcx> for CastRefToMut { +impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else { return; @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for CastRefToMut { let e = e.peel_blocks(); if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() { - cx.emit_spanned_lint(CAST_REF_TO_MUT, expr.span, CastRefToMutDiag); + cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag); } } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index f78da284a3a..a3c5ca4cda1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -414,7 +414,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { match path { MustUsePath::Suppressed => {} MustUsePath::Boxed(path) => { - let descr_pre = &format!("{}boxed ", descr_pre); + let descr_pre = &format!("{descr_pre}boxed "); emit_must_use_untranslated( cx, path, @@ -426,7 +426,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Opaque(path) => { - let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); + let descr_pre = &format!("{descr_pre}implementer{plural_suffix} of "); emit_must_use_untranslated( cx, path, @@ -438,7 +438,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::TraitObject(path) => { - let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); + let descr_post = &format!(" trait object{plural_suffix}{descr_post}"); emit_must_use_untranslated( cx, path, @@ -451,7 +451,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } MustUsePath::TupleElement(elems) => { for (index, path) in elems { - let descr_post = &format!(" in tuple element {}", index); + let descr_post = &format!(" in tuple element {index}"); emit_must_use_untranslated( cx, path, @@ -464,7 +464,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } } MustUsePath::Array(path, len) => { - let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix); + let descr_pre = &format!("{descr_pre}array{plural_suffix} of "); emit_must_use_untranslated( cx, path, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a0f2e9aed81..7e3b6e9e218 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3316,6 +3316,7 @@ declare_lint_pass! { // tidy-alphabetical-start ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, + AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, ARITHMETIC_OVERFLOW, ASM_SUB_REGISTER, @@ -3400,6 +3401,7 @@ declare_lint_pass! { UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, UNKNOWN_CRATE_TYPES, + UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNKNOWN_LINTS, UNNAMEABLE_TYPES, UNREACHABLE_CODE, @@ -4052,12 +4054,12 @@ declare_lint! { /// /// The compiler disables the automatic implementation if an explicit one /// exists for given type constructor. The exact rules governing this - /// are currently unsound, quite subtle, and will be modified in the future. - /// This change will cause the automatic implementation to be disabled in more + /// were previously unsound, quite subtle, and have been recently modified. + /// This change caused the automatic implementation to be disabled in more /// cases, potentially breaking some code. pub SUSPICIOUS_AUTO_TRAIT_IMPLS, Warn, - "the rules governing auto traits will change in the future", + "the rules governing auto traits have recently changed resulting in potential breakage", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>", @@ -4380,3 +4382,70 @@ declare_lint! { "effective visibility of a type is larger than the area in which it can be named", @feature_gate = sym::type_privacy_lints; } + +declare_lint! { + /// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes. + /// + /// ### Example + /// + /// ```rust + /// #![feature(diagnostic_namespace)] + /// #[diagnostic::does_not_exist] + /// struct Foo; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify a diagnostic attribute that does not exist. Check + /// the spelling, and check the diagnostic attribute listing for the correct name. Also + /// consider if you are using an old version of the compiler, and the attribute + /// is only available in a newer version. + pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + Warn, + "unrecognized diagnostic attribute" +} + +declare_lint! { + /// The `ambiguous_glob_imports` lint detects glob imports that should report ambiguity + /// errors, but previously didn't do that due to rustc bugs. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// + /// #![deny(ambiguous_glob_imports)] + /// pub fn foo() -> u32 { + /// use sub::*; + /// C + /// } + /// + /// mod sub { + /// mod mod1 { pub const C: u32 = 1; } + /// mod mod2 { pub const C: u32 = 2; } + /// + /// pub use mod1::*; + /// pub use mod2::*; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust compile it successfully because it + /// had lost the ambiguity error when resolve `use sub::mod2::*`. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub AMBIGUOUS_GLOB_IMPORTS, + Warn, + "detects certain glob imports that require reporting an ambiguity error", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseError, + reference: "issue #114095 <https://github.com/rust-lang/rust/issues/114095>", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 10ebe29dfce..f350957f72f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -467,6 +467,21 @@ impl<HCX> ToStableHashKey<HCX> for LintId { } } +#[derive(Debug)] +pub struct AmbiguityErrorDiag { + pub msg: String, + pub span: Span, + pub label_span: Span, + pub label_msg: String, + pub note_msg: String, + pub b1_span: Span, + pub b1_note_msg: String, + pub b1_help_msgs: Vec<String>, + pub b2_span: Span, + pub b2_note_msg: String, + pub b2_help_msgs: Vec<String>, +} + // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(Debug)] @@ -530,6 +545,9 @@ pub enum BuiltinLintDiagnostics { vis_span: Span, ident_span: Span, }, + AmbiguousGlobImports { + diag: AmbiguityErrorDiag, + }, AmbiguousGlobReexports { /// The name for which collision(s) have occurred. name: String, diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index af6f4d5eaf9..ea045462845 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -92,10 +92,8 @@ enum LLVMRustAttribute { NoCfCheck = 35, ShadowCallStack = 36, AllocSize = 37, -#if LLVM_VERSION_GE(15, 0) AllocatedPointer = 38, AllocAlign = 39, -#endif SanitizeSafeStack = 40, }; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 71df17c9ce7..ebf8a50ae8b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -801,9 +801,6 @@ LLVMRustOptimize( OptimizerLastEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { auto CompileKernel = SanitizerOptions->SanitizeKernelAddress; -#if LLVM_VERSION_LT(15, 0) - MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); -#endif AddressSanitizerOptions opts = AddressSanitizerOptions{ CompileKernel, SanitizerOptions->SanitizeAddressRecover diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 870a2e02cba..f509e2911f3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -277,12 +277,10 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::ShadowCallStack; case AllocSize: return Attribute::AllocSize; -#if LLVM_VERSION_GE(15, 0) case AllocatedPointer: return Attribute::AllocatedPointer; case AllocAlign: return Attribute::AllocAlign; -#endif case SanitizeSafeStack: return Attribute::SafeStack; } @@ -340,20 +338,12 @@ extern "C" LLVMAttributeRef LLVMRustCreateStructRetAttr(LLVMContextRef C, LLVMTy } extern "C" LLVMAttributeRef LLVMRustCreateElementTypeAttr(LLVMContextRef C, LLVMTypeRef Ty) { -#if LLVM_VERSION_GE(15, 0) return wrap(Attribute::get(*unwrap(C), Attribute::ElementType, unwrap(Ty))); -#else - report_fatal_error("Should not be needed on LLVM < 15"); -#endif } extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Async) { -#if LLVM_VERSION_LT(15, 0) - return wrap(Attribute::get(*unwrap(C), Attribute::UWTable)); -#else return wrap(Attribute::getWithUWTableKind( *unwrap(C), Async ? UWTableKind::Async : UWTableKind::Sync)); -#endif } extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) { @@ -366,8 +356,6 @@ extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32 )); } -#if LLVM_VERSION_GE(15, 0) - // These values **must** match ffi::AllocKindFlags. // It _happens_ to match the LLVM values of llvm::AllocFnKind, // but that's happenstance and we do explicit conversions before @@ -411,16 +399,10 @@ static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) { } return AFK; } -#endif extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) { -#if LLVM_VERSION_GE(15, 0) return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind, static_cast<uint64_t>(allocKindFromRust(static_cast<LLVMRustAllocKindFlags>(AllocKindArg))))); -#else - report_fatal_error( - "allockind attributes are new in LLVM 15 and should not be used on older LLVMs"); -#endif } // Simplified representation of `MemoryEffects` across the FFI boundary. @@ -517,14 +499,9 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, size_t ConstraintsLen) { -#if LLVM_VERSION_LT(15, 0) - return InlineAsm::Verify(unwrap<FunctionType>(Ty), - StringRef(Constraints, ConstraintsLen)); -#else // llvm::Error converts to true if it is an error. return !llvm::errorToBool(InlineAsm::verify( unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen))); -#endif } typedef DIBuilder *LLVMRustDIBuilderRef; @@ -1649,19 +1626,11 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *hig auto C = unwrap<llvm::ConstantInt>(CV); if (C->getBitWidth() > 128) { return false; } APInt AP; -#if LLVM_VERSION_GE(15, 0) if (sext) { AP = C->getValue().sext(128); } else { AP = C->getValue().zext(128); } -#else - if (sext) { - AP = C->getValue().sextOrSelf(128); - } else { - AP = C->getValue().zextOrSelf(128); - } -#endif *low = AP.getLoBits(64).getZExtValue(); *high = AP.getHiBits(64).getZExtValue(); return true; @@ -2037,16 +2006,7 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { Mangler().getNameWithPrefix(OS, GV, true); } -// LLVMGetAggregateElement was added in LLVM 15. For earlier LLVM versions just -// use its implementation. -#if LLVM_VERSION_LT(15, 0) -extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) { - return wrap(unwrap<Constant>(C)->getAggregateElement(Idx)); -} -#endif - extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { -#if LLVM_VERSION_GE(15, 0) auto *CB = unwrap<CallBase>(CallSite); switch (CB->getIntrinsicID()) { case Intrinsic::arm_ldrex: @@ -2054,7 +2014,6 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { case Intrinsic::arm_strex: return 1; } -#endif return -1; } diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 16c4a850012..17651ce9598 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -8,7 +8,6 @@ proc-macro = true [dependencies] synstructure = "0.13.0" -# FIXME(Nilstrieb): Updating this causes changes in the diagnostics output. -syn = { version = "=2.0.8", features = ["full"] } +syn = { version = "2.0.9", features = ["full"] } proc-macro2 = "1" quote = "1" diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a8815ee0908..7dbfe0e0cb0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -246,6 +246,7 @@ provide! { tcx, def_id, other, cdata, debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) } + assumed_wf_types_for_rpitit => { table } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata .root diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8f065dd6b58..0025dc9033c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1560,6 +1560,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let Some(rpitit_info) = item.opt_rpitit_info { record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info); + if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) { + record_array!( + self.tables.assumed_wf_types_for_rpitit[def_id] + <- self.tcx.assumed_wf_types_for_rpitit(def_id) + ); + } } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0bc16fc64ff..09e21fd4455 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -457,6 +457,7 @@ define_tables! { trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>, doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>, doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>, + assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index bb7147ac80f..108a10b506b 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -52,6 +52,9 @@ middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} .note = overflowed on {$overflow_ty} +middle_layout_references_error = + the type has an unknown layout + middle_limit_invalid = `limit` must be a non-negative integer .label = {$error_str} diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 57b2de84b47..b346cd45391 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -132,6 +132,9 @@ pub enum LayoutError<'tcx> { #[diag(middle_cycle)] Cycle, + + #[diag(middle_layout_references_error)] + ReferencesError, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1fd68dc5cb2..b167364f680 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -24,7 +24,7 @@ pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { match node { Node::Item(Item { owner_id, - kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), + kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), .. }) | Node::TraitItem(TraitItem { diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 5baeb1ee0cf..1913421f54c 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -178,7 +178,12 @@ impl EffectiveVisibilities { // All effective visibilities except `reachable_through_impl_trait` are limited to // nominal visibility. For some items nominal visibility doesn't make sense so we // don't check this condition for them. - if !matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) { + let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. }); + let is_associated_item_in_trait_impl = tcx + .impl_of_method(def_id.to_def_id()) + .and_then(|impl_id| tcx.trait_id_of_impl(impl_id)) + .is_some(); + if !is_impl && !is_associated_item_in_trait_impl { let nominal_vis = tcx.visibility(def_id); if !nominal_vis.is_at_least(ev.reachable, tcx) { span_bug!( @@ -186,7 +191,7 @@ impl EffectiveVisibilities { "{:?}: reachable {:?} > nominal {:?}", def_id, ev.reachable, - nominal_vis + nominal_vis, ); } } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index c9db0e7c11d..fc659ce18a4 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -139,7 +139,6 @@ impl<'tcx> TyCtxt<'tcx> { cid: GlobalId<'tcx>, span: Option<Span>, ) -> EvalToConstValueResult<'tcx> { - let param_env = param_env.with_const(); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(param_env.and(cid)); @@ -158,8 +157,6 @@ impl<'tcx> TyCtxt<'tcx> { cid: GlobalId<'tcx>, span: Option<Span>, ) -> EvalToValTreeResult<'tcx> { - let param_env = param_env.with_const(); - debug!(?param_env); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(param_env.and(cid)); @@ -204,7 +201,6 @@ impl<'tcx> TyCtxtAt<'tcx> { gid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - let param_env = param_env.with_const(); trace!("eval_to_allocation: Need to compute {:?}", gid); let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) @@ -224,8 +220,7 @@ impl<'tcx> TyCtxtEnsure<'tcx> { let args = GenericArgs::identity_for_item(self.tcx, def_id); let instance = ty::Instance::new(def_id, args); let cid = GlobalId { instance, promoted: None }; - let param_env = - self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx).with_const(); + let param_env = self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.tcx.erase_regions(param_env.and(cid)); @@ -238,7 +233,7 @@ impl<'tcx> TyCtxtEnsure<'tcx> { assert!(self.tcx.is_static(def_id)); let instance = ty::Instance::mono(self.tcx, def_id); let gid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all().with_const(); + let param_env = ty::ParamEnv::reveal_all(); trace!("eval_to_allocation: Need to compute {:?}", gid); self.eval_to_allocation_raw(param_env.and(gid)) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fb796587352..0cdb7714729 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -885,6 +885,13 @@ rustc_queries! { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } } + /// We need to store the assumed_wf_types for an RPITIT so that impls of foreign + /// traits with return-position impl trait in traits can inherit the right wf types. + query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] { + desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } + separate_provide_extern + } + /// Computes the signature of the function. query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b4f4f9bef8e..7c05deae90a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -168,7 +168,6 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> { fn encode(&self, e: &mut E) { self.caller_bounds().encode(e); self.reveal().encode(e); - self.constness().encode(e); } } @@ -306,8 +305,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ParamEnv<'tcx> { fn decode(d: &mut D) -> Self { let caller_bounds = Decodable::decode(d); let reveal = Decodable::decode(d); - let constness = Decodable::decode(d); - ty::ParamEnv::new(caller_bounds, reveal, constness) + ty::ParamEnv::new(caller_bounds, reveal) } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 81e7dc3728a..93dabb973e3 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -10,7 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_session::config::OptLevel; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; @@ -212,6 +212,7 @@ pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), SizeOverflow(Ty<'tcx>), NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), + ReferencesError(ErrorGuaranteed), Cycle, } @@ -224,6 +225,7 @@ impl<'tcx> LayoutError<'tcx> { SizeOverflow(_) => middle_values_too_big, NormalizationFailure(_, _) => middle_cannot_be_normalized, Cycle => middle_cycle, + ReferencesError(_) => middle_layout_references_error, } } @@ -237,6 +239,7 @@ impl<'tcx> LayoutError<'tcx> { E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } } Cycle => E::Cycle, + ReferencesError(_) => E::ReferencesError, } } } @@ -257,6 +260,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { e.get_type_for_failure() ), LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"), + LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"), } } } @@ -323,7 +327,8 @@ impl<'tcx> SizeSkeleton<'tcx> { Err( e @ LayoutError::Cycle | e @ LayoutError::SizeOverflow(_) - | e @ LayoutError::NormalizationFailure(..), + | e @ LayoutError::NormalizationFailure(..) + | e @ LayoutError::ReferencesError(_), ) => return Err(e), }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0411890ab51..f9c0fbb23c3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -867,20 +867,6 @@ pub struct TraitPredicate<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; impl<'tcx> TraitPredicate<'tcx> { - pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) { - *param_env = param_env.with_constness(self.constness.and(param_env.constness())) - } - - /// Remap the constness of this predicate before emitting it for diagnostics. - pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { - // this is different to `remap_constness` that callees want to print this predicate - // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the - // param_env is not const because it is always satisfied in non-const contexts. - if let hir::Constness::NotConst = param_env.constness() { - self.constness = ty::BoundConstness::NotConst; - } - } - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self } } @@ -922,14 +908,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> { self.map_bound(|trait_ref| trait_ref.self_ty()) } - /// Remap the constness of this predicate before emitting it for diagnostics. - pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) { - *self = self.map_bound(|mut p| { - p.remap_constness_diag(param_env); - p - }); - } - #[inline] pub fn is_const_if_const(self) -> bool { self.skip_binder().is_const_if_const() @@ -1700,15 +1678,12 @@ pub struct ParamEnv<'tcx> { #[derive(Copy, Clone)] struct ParamTag { reveal: traits::Reveal, - constness: hir::Constness, } impl_tag! { impl Tag for ParamTag; - ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, - ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, - ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, - ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const }, + ParamTag { reveal: traits::Reveal::UserFacing }, + ParamTag { reveal: traits::Reveal::All }, } impl<'tcx> fmt::Debug for ParamEnv<'tcx> { @@ -1716,7 +1691,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) - .field("constness", &self.constness()) .finish() } } @@ -1725,7 +1699,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.caller_bounds().hash_stable(hcx, hasher); self.reveal().hash_stable(hcx, hasher); - self.constness().hash_stable(hcx, hasher); } } @@ -1737,7 +1710,6 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ParamEnv<'tcx> { Ok(ParamEnv::new( self.caller_bounds().try_fold_with(folder)?, self.reveal().try_fold_with(folder)?, - self.constness(), )) } } @@ -1756,7 +1728,7 @@ impl<'tcx> ParamEnv<'tcx> { /// type-checking. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst) + Self::new(List::empty(), Reveal::UserFacing) } #[inline] @@ -1769,16 +1741,6 @@ impl<'tcx> ParamEnv<'tcx> { self.packed.tag().reveal } - #[inline] - pub fn constness(self) -> hir::Constness { - self.packed.tag().constness - } - - #[inline] - pub fn is_const(self) -> bool { - self.packed.tag().constness == hir::Constness::Const - } - /// Construct a trait environment with no where-clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck @@ -1788,17 +1750,13 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All, hir::Constness::NotConst) + Self::new(List::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new( - caller_bounds: &'tcx List<Clause<'tcx>>, - reveal: Reveal, - constness: hir::Constness, - ) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) } + pub fn new(caller_bounds: &'tcx List<Clause<'tcx>>, reveal: Reveal) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) } } pub fn with_user_facing(mut self) -> Self { @@ -1806,29 +1764,6 @@ impl<'tcx> ParamEnv<'tcx> { self } - #[inline] - pub fn with_constness(mut self, constness: hir::Constness) -> Self { - self.packed.set_tag(ParamTag { constness, ..self.packed.tag() }); - self - } - - #[inline] - pub fn with_const(mut self) -> Self { - self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() }); - self - } - - #[inline] - pub fn without_const(mut self) -> Self { - self.packed.set_tag(ParamTag { constness: hir::Constness::NotConst, ..self.packed.tag() }); - self - } - - #[inline] - pub fn remap_constness_with(&mut self, mut constness: ty::BoundConstness) { - *self = self.with_constness(constness.and(self.constness())) - } - /// Returns a new parameter environment with the same clauses, but /// which "reveals" the true results of projections in all cases /// (even for associated types that are specializable). This is @@ -1843,17 +1778,13 @@ impl<'tcx> ParamEnv<'tcx> { return self; } - ParamEnv::new( - tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), - Reveal::All, - self.constness(), - ) + ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All) } /// Returns this same environment but with no caller bounds. #[inline] pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal(), self.constness()) + Self::new(List::empty(), self.reveal()) } /// Creates a suitable environment in which to perform trait diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9d380a58d9f..50bf9afa531 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -602,7 +602,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { tcx.lift(self.caller_bounds()) - .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.constness())) + .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal())) } } diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index c494929cbff..60c4a041696 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -74,7 +74,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { kind @ StmtKind::Let { pattern, .. } => { return Err(ParseError { span: pattern.span, - item_description: format!("{:?}", kind), + item_description: format!("{kind:?}"), expected: "expression".to_string(), }); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 7817c3d0d80..3220a184d49 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -774,8 +774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Not in a closure debug_assert!( local == ty::CAPTURE_STRUCT_LOCAL, - "Expected local to be Local(1), found {:?}", - local + "Expected local to be Local(1), found {local:?}" ); // Not in a closure debug_assert!( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6f14891cb78..ed3ac7cb3ec 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1627,9 +1627,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // at least the first candidate ought to be tested assert!( total_candidate_count > candidates.len(), - "{}, {:#?}", - total_candidate_count, - candidates + "{total_candidate_count}, {candidates:#?}" ); debug!("tested_candidates: {}", total_candidate_count - candidates.len()); debug!("untested_candidates: {}", candidates.len()); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 275878a3919..484e8490919 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -175,16 +175,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert_ne!( target_blocks[idx.index()], otherwise_block, - "no candidates for tested discriminant: {:?}", - discr, + "no candidates for tested discriminant: {discr:?}", ); Some((discr.val, target_blocks[idx.index()])) } else { debug_assert_eq!( target_blocks[idx.index()], otherwise_block, - "found candidates for untested discriminant: {:?}", - discr, + "found candidates for untested discriminant: {discr:?}", ); None } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 17295fe1d34..c66eba5520e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -94,8 +94,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { || body.basic_blocks.has_free_regions() || body.var_debug_info.has_free_regions() || body.yield_ty().has_free_regions()), - "Unexpected free regions in MIR: {:?}", - body, + "Unexpected free regions in MIR: {body:?}", ); body @@ -571,7 +570,7 @@ fn construct_const<'a, 'tcx>( // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir().get(hir_id) { Node::Item(hir::Item { - kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _), + kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _), span, .. }) @@ -977,9 +976,9 @@ pub(crate) fn parse_float_into_scalar( match float_ty { ty::FloatTy::F32 => { let Ok(rust_f) = num.parse::<f32>() else { return None }; - let mut f = num.parse::<Single>().unwrap_or_else(|e| { - panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) - }); + let mut f = num + .parse::<Single>() + .unwrap_or_else(|e| panic!("apfloat::ieee::Single failed to parse `{num}`: {e:?}")); assert!( u128::from(rust_f.to_bits()) == f.to_bits(), @@ -1000,9 +999,9 @@ pub(crate) fn parse_float_into_scalar( } ty::FloatTy::F64 => { let Ok(rust_f) = num.parse::<f64>() else { return None }; - let mut f = num.parse::<Double>().unwrap_or_else(|e| { - panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) - }); + let mut f = num + .parse::<Double>() + .unwrap_or_else(|e| panic!("apfloat::ieee::Double failed to parse `{num}`: {e:?}")); assert!( u128::from(rust_f.to_bits()) == f.to_bits(), diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 820ab93851e..3ff3387a781 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -454,17 +454,13 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { if self.span.eq_ctxt(self.expr_span) { // Get the span for the empty match body `{}`. let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) { - (format!("\n{}", snippet), " ") + (format!("\n{snippet}"), " ") } else { (" ".to_string(), "") }; suggestion = Some(( self.span.shrink_to_hi().with_hi(self.expr_span.hi()), - format!( - " {{{indentation}{more}_ => todo!(),{indentation}}}", - indentation = indentation, - more = more, - ), + format!(" {{{indentation}{more}_ => todo!(),{indentation}}}",), )); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 711a9126c04..ff4620948fa 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -229,9 +229,7 @@ impl<'tcx> Cx<'tcx> { let param_env_ty = self.param_env.and(discr_ty); let size = tcx .layout_of(param_env_ty) - .unwrap_or_else(|e| { - panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) - }) + .unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}")) .size; let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 38c866c50a2..a786e659664 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -691,7 +691,7 @@ fn non_exhaustive_match<'p, 'tcx>( err = create_e0004( cx.tcx.sess, sp, - format!("non-exhaustive patterns: {} not covered", joined_patterns), + format!("non-exhaustive patterns: {joined_patterns} not covered"), ); err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); patterns_len = witnesses.len(); @@ -721,15 +721,13 @@ fn non_exhaustive_match<'p, 'tcx>( && matches!(witnesses[0].ctor(), Constructor::NonExhaustive) { err.note(format!( - "`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \ + "`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \ exhaustively", - scrut_ty, )); if cx.tcx.sess.is_nightly_build() { err.help(format!( "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \ - enable precise `{}` matching", - scrut_ty, + enable precise `{scrut_ty}` matching", )); } } @@ -745,18 +743,13 @@ fn non_exhaustive_match<'p, 'tcx>( [] if sp.eq_ctxt(expr_span) => { // Get the span for the empty match body `{}`. let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) { - (format!("\n{}", snippet), " ") + (format!("\n{snippet}"), " ") } else { (" ".to_string(), "") }; suggestion = Some(( sp.shrink_to_hi().with_hi(expr_span.hi()), - format!( - " {{{indentation}{more}{pattern} => todo!(),{indentation}}}", - indentation = indentation, - more = more, - pattern = pattern, - ), + format!(" {{{indentation}{more}{pattern} => todo!(),{indentation}}}",), )); } [only] => { @@ -765,7 +758,7 @@ fn non_exhaustive_match<'p, 'tcx>( && let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',') && sm.is_multiline(with_trailing) { - (format!("\n{}", snippet), true) + (format!("\n{snippet}"), true) } else { (" ".to_string(), false) }; @@ -780,7 +773,7 @@ fn non_exhaustive_match<'p, 'tcx>( }; suggestion = Some(( only.span.shrink_to_hi(), - format!("{}{}{} => todo!()", comma, pre_indentation, pattern), + format!("{comma}{pre_indentation}{pattern} => todo!()"), )); } [.., prev, last] => { @@ -803,7 +796,7 @@ fn non_exhaustive_match<'p, 'tcx>( if let Some(spacing) = spacing { suggestion = Some(( last.span.shrink_to_hi(), - format!("{}{}{} => todo!()", comma, spacing, pattern), + format!("{comma}{spacing}{pattern} => todo!()"), )); } } @@ -900,7 +893,7 @@ fn adt_defined_here<'p, 'tcx>( for pat in spans { span.push_span_label(pat, "not covered"); } - err.span_note(span, format!("`{}` defined here", ty)); + err.span_note(span, format!("`{ty}` defined here")); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 4228597cdc9..bee1c4e4614 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -306,9 +306,9 @@ impl fmt::Debug for IntRange { let (lo, hi) = self.boundaries(); let bias = self.bias; let (lo, hi) = (lo ^ bias, hi ^ bias); - write!(f, "{}", lo)?; + write!(f, "{lo}")?; write!(f, "{}", RangeEnd::Included)?; - write!(f, "{}", hi) + write!(f, "{hi}") } } @@ -1619,7 +1619,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { // of `std`). So this branch is only reachable when the feature is enabled and // the pattern is a box pattern. let subpattern = self.iter_fields().next().unwrap(); - write!(f, "box {:?}", subpattern) + write!(f, "box {subpattern:?}") } ty::Adt(..) | ty::Tuple(..) => { let variant = match self.ty.kind() { @@ -1638,7 +1638,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { write!(f, "(")?; for p in self.iter_fields() { write!(f, "{}", start_or_comma())?; - write!(f, "{:?}", p)?; + write!(f, "{p:?}")?; } write!(f, ")") } @@ -1674,11 +1674,11 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { write!(f, "]") } &FloatRange(lo, hi, end) => { - write!(f, "{}", lo)?; - write!(f, "{}", end)?; - write!(f, "{}", hi) + write!(f, "{lo}")?; + write!(f, "{end}")?; + write!(f, "{hi}") } - IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0` + IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0` Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty), Or => { for pat in self.iter_fields() { @@ -1686,7 +1686,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { } Ok(()) } - Str(value) => write!(f, "{}", value), + Str(value) => write!(f, "{value}"), Opaque => write!(f, "<constant pattern>"), } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index e5b63506906..08cfe98bb68 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -459,7 +459,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "+")?; for pat in self.iter() { - write!(f, " {:?} +", pat)?; + write!(f, " {pat:?} +")?; } Ok(()) } @@ -530,7 +530,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec<Vec<String>> = - m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); + m.iter().map(|row| row.iter().map(|pat| format!("{pat:?}")).collect()).collect(); let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0); assert!(m.iter().all(|row| row.len() == column_count)); diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 658e01d9310..e9c5f856d35 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -282,7 +282,7 @@ impl<'a> BcbCounters<'a> { branching_counter_operand, Op::Subtract, sumup_counter_operand, - || Some(format!("{:?}", expression_branch)), + || Some(format!("{expression_branch:?}")), ); debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression)); let bcb = expression_branch.target_bcb; @@ -324,7 +324,7 @@ impl<'a> BcbCounters<'a> { // program results in a tight infinite loop, but it should still compile. let one_path_to_target = self.bcb_has_one_path_to_target(bcb); if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { - let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb))); + let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{bcb:?}"))); if one_path_to_target { debug!( "{}{:?} gets a new counter: {}", @@ -392,7 +392,7 @@ impl<'a> BcbCounters<'a> { first_edge_counter_operand, Op::Add, some_sumup_edge_counter_operand.unwrap(), - || Some(format!("{:?}", bcb)), + || Some(format!("{bcb:?}")), ); debug!( "{}{:?} gets a new counter (sum of predecessor counters): {}", @@ -449,7 +449,7 @@ impl<'a> BcbCounters<'a> { // Make a new counter to count this edge. let counter_kind = - self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb))); + self.coverage_counters.make_counter(|| Some(format!("{from_bcb:?}->{to_bcb:?}"))); debug!( "{}Edge {:?}->{:?} gets a new counter: {}", NESTED_INDENT.repeat(debug_indent_level), diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 7ad98144159..c9914eb9f82 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -630,7 +630,7 @@ pub(super) fn dump_coverage_spanview<'tcx>( .expect("Unexpected error creating MIR spanview HTML file"); let crate_name = tcx.crate_name(def_id.krate); let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate(); - let title = format!("{}.{} - Coverage Spans", crate_name, item_name); + let title = format!("{crate_name}.{item_name} - Coverage Spans"); spanview::write_document(tcx, body_span, span_viewables, &title, &mut file) .expect("Unexpected IO error dumping coverage spans as HTML"); } @@ -779,7 +779,7 @@ fn bcb_to_string_sections<'tcx>( )); } if let Some(counter_kind) = &bcb_data.counter_kind { - sections.push(format!("{:?}", counter_kind)); + sections.push(format!("{counter_kind:?}")); } let non_term_blocks = bcb_data.basic_blocks[0..len - 1] .iter() diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index d2a854b2675..5d843f4ade0 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -360,8 +360,7 @@ impl BasicCoverageBlockData { if let Some(replaced) = self.counter_kind.replace(counter_kind) { Error::from_string(format!( "attempt to set a BasicCoverageBlock coverage counter more than once; \ - {:?} already had counter {:?}", - self, replaced, + {self:?} already had counter {replaced:?}", )) } else { Ok(operand) @@ -389,9 +388,8 @@ impl BasicCoverageBlockData { // `BasicCoverageBlock`). if self.counter_kind.as_ref().is_some_and(|c| !c.is_expression()) { return Error::from_string(format!( - "attempt to add an incoming edge counter from {:?} when the target BCB already \ - has a `Counter`", - from_bcb + "attempt to add an incoming edge counter from {from_bcb:?} when the target BCB already \ + has a `Counter`" )); } } @@ -401,8 +399,7 @@ impl BasicCoverageBlockData { { Error::from_string(format!( "attempt to set an edge counter more than once; from_bcb: \ - {:?} already had counter {:?}", - from_bcb, replaced, + {from_bcb:?} already had counter {replaced:?}", )) } else { Ok(operand) @@ -612,7 +609,7 @@ impl TraverseCoverageGraphWithLoops { the {}", successor_to_add, if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {:?}", loop_header) + format!("worklist for the loop headed by {loop_header:?}") } else { String::from("non-loop worklist") }, @@ -623,7 +620,7 @@ impl TraverseCoverageGraphWithLoops { "{:?} successor is non-branching. Defer it to the end of the {}", successor_to_add, if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {:?}", loop_header) + format!("worklist for the loop headed by {loop_header:?}") } else { String::from("non-loop worklist") }, diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 35cf9ea5f91..deebf5345ba 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map::original_sp; use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; -use std::cell::RefCell; +use std::cell::OnceCell; use std::cmp::Ordering; #[derive(Debug, Copy, Clone)] @@ -67,7 +67,7 @@ impl CoverageStatement { pub(super) struct CoverageSpan { pub span: Span, pub expn_span: Span, - pub current_macro_or_none: RefCell<Option<Option<Symbol>>>, + pub current_macro_or_none: OnceCell<Option<Symbol>>, pub bcb: BasicCoverageBlock, pub coverage_statements: Vec<CoverageStatement>, pub is_closure: bool, @@ -175,8 +175,7 @@ impl CoverageSpan { /// If the span is part of a macro, returns the macro name symbol. pub fn current_macro(&self) -> Option<Symbol> { self.current_macro_or_none - .borrow_mut() - .get_or_insert_with(|| { + .get_or_init(|| { if let ExpnKind::Macro(MacroKind::Bang, current_macro) = self.expn_span.ctxt().outer_expn_data().kind { diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index d5664e2b40a..43757a9ea35 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -358,8 +358,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.tcx.sess.delay_span_bug( terminator.source_info.span, format!( - "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", - bb, place, path + "drop of untracked, uninitialized value {bb:?}, place {place:?} ({path:?})" ), ); } @@ -424,7 +423,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { if !replace { self.tcx.sess.delay_span_bug( terminator.source_info.span, - format!("drop of untracked value {:?}", bb), + format!("drop of untracked value {bb:?}"), ); } // A drop and replace behind a pointer/array/whatever. diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index fdf6ab33c82..a42eacbf22b 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -168,15 +168,15 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { } }; let ident = self.tcx.item_name(fn_id).to_ident_string(); - let ty_params = fn_args.types().map(|ty| format!("{}", ty)); - let const_params = fn_args.consts().map(|c| format!("{}", c)); + let ty_params = fn_args.types().map(|ty| format!("{ty}")); + let const_params = fn_args.consts().map(|c| format!("{c}")); let params = ty_params.chain(const_params).join(", "); let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; let sugg = format!( "{} as {}{}fn({}{}){}", - if params.is_empty() { ident.clone() } else { format!("{}::<{}>", ident, params) }, + if params.is_empty() { ident.clone() } else { format!("{ident}::<{params}>") }, unsafety, abi, vec!["_"; num_args].join(", "), diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index eaeaff69cf3..669135f80bc 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1477,7 +1477,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { ) } _ => { - tcx.sess.delay_span_bug(body.span, format!("unexpected generator type {}", gen_ty)); + tcx.sess.delay_span_bug(body.span, format!("unexpected generator type {gen_ty}")); return; } }; diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index a430f8da35c..8b0a0903d18 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -57,7 +57,7 @@ struct InstSimplifyContext<'tcx, 'a> { impl<'tcx> InstSimplifyContext<'tcx, '_> { fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool { self.tcx.consider_optimizing(|| { - format!("InstSimplify - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info) + format!("InstSimplify - Rvalue: {rvalue:?} SourceInfo: {source_info:?}") }) } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d419329f2d6..734321e97d8 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -615,7 +615,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { // computes and caches its result. Some(hir::ConstContext::ConstFn) => tcx.ensure_with_value().mir_for_ctfe(did), None => {} - Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), + Some(other) => panic!("do not use `optimized_mir` for constants: {other:?}"), } debug!("about to call mir_drops_elaborated..."); let body = tcx.mir_drops_elaborated_and_const_checked(did).steal(); diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 6eb48498274..bc29fb8ded1 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -51,7 +51,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { let bbs = body.basic_blocks.as_mut(); let mut should_cleanup = false; 'outer: for bb_idx in bbs.indices() { - if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { + if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) { continue; } diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index 3957cd92c4e..c97d034544a 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -27,7 +27,7 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } for bb in bbs { - if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) { + if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {def_id:?} ")) { break; } diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index 5ce96012b90..e1298b0654f 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -45,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { return; }; - if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) { + if !tcx.consider_optimizing(|| format!("RenameReturnPlace {def_id:?}")) { return; } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 710eed3ed38..057f5fe8293 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -118,7 +118,7 @@ fn run_passes_inner<'tcx>( dump_mir_for_pass(tcx, body, &name, false); } if validate { - validate_body(tcx, body, format!("before pass {}", name)); + validate_body(tcx, body, format!("before pass {name}")); } tcx.sess.time(name, || pass.run_pass(tcx, body)); @@ -127,7 +127,7 @@ fn run_passes_inner<'tcx>( dump_mir_for_pass(tcx, body, &name, true); } if validate { - validate_body(tcx, body, format!("after pass {}", name)); + validate_body(tcx, body, format!("after pass {name}")); } body.pass_count += 1; diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 84ccf6e1f61..08b2a6537e9 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -27,7 +27,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { if ty.ty.needs_drop(tcx, param_env) { continue; } - if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) { + if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {did:?} ")) { continue; } debug!("SUCCESS: replacing `drop` with goto({:?})", target); diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 1ba9ad87537..9c6c55b0811 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -102,7 +102,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { let op_ty = operand.ty(self.local_decls, self.tcx); if self.known_to_be_zst(op_ty) && self.tcx.consider_optimizing(|| { - format!("RemoveZsts - Operand: {:?} Location: {:?}", operand, loc) + format!("RemoveZsts - Operand: {operand:?} Location: {loc:?}") }) { *operand = Operand::Constant(Box::new(self.make_zst(op_ty))) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index c34c2c248fe..de6db8ae6ae 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -394,7 +394,7 @@ fn merge_codegen_units<'tcx>( && codegen_units.iter().any(|cgu| cgu.size_estimate() < NON_INCR_MIN_CGU_SIZE) { // Sort small cgus to the back. - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + codegen_units.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9787d98c1a4..6a9a5a239e4 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -270,6 +270,8 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}` parse_function_body_equals_expr = function body cannot be `= expression;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` +parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax + parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets .suggestion = surround the type parameters with angle brackets @@ -690,6 +692,8 @@ parse_single_colon_import_path = expected `::`, found `:` parse_single_colon_struct_type = found single colon in a struct field type path .suggestion = write a path separator here +parse_static_with_generics = static items may not have generic parameters + parse_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block @@ -722,6 +726,10 @@ parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses parse_switch_mut_let_order = switch the order of `mut` and `let` + +parse_ternary_operator = Rust has no ternary operator + .help = use an `if-else` expression instead + parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator @@ -847,6 +855,12 @@ parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by a .label = the visibility .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}` +parse_where_clause_before_const_body = where clauses are not allowed before const item bodies + .label = unexpected where clause + .name_label = while parsing this const item + .body_label = the item body + .suggestion = move the body before the where clause + parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies .label = unexpected where clause .name_label = while parsing this tuple struct diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 96e1c0e3c6d..3184ca777ce 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -365,6 +365,14 @@ pub(crate) enum IfExpressionMissingThenBlockSub { AddThenBlock(#[primary_span] Span), } +#[derive(Diagnostic)] +#[diag(parse_ternary_operator)] +#[help] +pub struct TernaryOperator { + #[primary_span] + pub span: Span, +} + #[derive(Subdiagnostic)] #[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")] pub(crate) struct IfExpressionLetSomeSub { @@ -2692,3 +2700,48 @@ pub(crate) struct ExpectedBuiltinIdent { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_static_with_generics)] +pub(crate) struct StaticWithGenerics { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_where_clause_before_const_body)] +pub(crate) struct WhereClauseBeforeConstBody { + #[primary_span] + #[label] + pub span: Span, + #[label(parse_name_label)] + pub name: Span, + #[label(parse_body_label)] + pub body: Span, + #[subdiagnostic] + pub sugg: Option<WhereClauseBeforeConstBodySugg>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct WhereClauseBeforeConstBodySugg { + #[suggestion_part(code = "= {snippet} ")] + pub left: Span, + pub snippet: String, + #[suggestion_part(code = "")] + pub right: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_generic_args_in_pat_require_turbofish_syntax)] +pub(crate) struct GenericArgsInPatRequireTurbofishSyntax { + #[primary_span] + pub span: Span, + #[suggestion( + parse_sugg_turbofish_syntax, + style = "verbose", + code = "::", + applicability = "maybe-incorrect" + )] + pub suggest_turbofish: Span, +} diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index b579da098d8..4cc03664b47 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -107,7 +107,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { let tokens = std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) .chain((0..self.num_calls).map(|_| { - let token = cursor_snapshot.next(cursor_snapshot.desugar_doc_comments); + let token = cursor_snapshot.next(); (FlatToken::Token(token.0), token.1) })) .take(self.num_calls); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c3cf6437afa..00ffa7de2ff 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -14,7 +14,7 @@ use crate::errors::{ PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -500,6 +500,10 @@ impl<'a> Parser<'a> { // Special-case "expected `;`" errors if expected.contains(&TokenType::Token(token::Semi)) { + if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() { + return Ok(true); + } + if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { // Likely inside a macro, can't provide meaningful suggestions. } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { @@ -1330,6 +1334,45 @@ impl<'a> Parser<'a> { } } + /// Rust has no ternary operator (`cond ? then : else`). Parse it and try + /// to recover from it if `then` and `else` are valid expressions. Returns + /// whether it was a ternary operator. + pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool { + if self.prev_token != token::Question { + return false; + } + + let lo = self.prev_token.span.lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + + if match self.parse_expr() { + Ok(_) => true, + Err(err) => { + err.cancel(); + // The colon can sometimes be mistaken for type + // ascription. Catch when this happens and continue. + self.token == token::Colon + } + } { + if self.eat_noexpect(&token::Colon) { + match self.parse_expr() { + Ok(_) => { + self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) }); + return true; + } + Err(err) => { + err.cancel(); + self.restore_snapshot(snapshot); + } + }; + } + } else { + self.restore_snapshot(snapshot); + }; + + false + } + pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !self.token.is_like_plus() { @@ -2057,7 +2100,7 @@ impl<'a> Parser<'a> { } pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> { - let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName))?; + let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -2111,7 +2154,7 @@ impl<'a> Parser<'a> { } _ => ( self.token.span, - format!("expected expression, found {}", super::token_descr(&self.token),), + format!("expected expression, found {}", super::token_descr(&self.token)), ), }; let mut err = self.struct_span_err(span, msg); @@ -2465,7 +2508,7 @@ impl<'a> Parser<'a> { // Skip the `:`. snapshot_pat.bump(); snapshot_type.bump(); - match snapshot_pat.parse_pat_no_top_alt(expected) { + match snapshot_pat.parse_pat_no_top_alt(expected, None) { Err(inner_err) => { inner_err.cancel(); } @@ -2729,7 +2772,7 @@ impl<'a> Parser<'a> { /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { while !self.check(&token::CloseDelim(Delimiter::Parenthesis)) { - self.parse_pat_no_top_alt(None)?; + self.parse_pat_no_top_alt(None, None)?; if !self.eat(&token::Comma) { return Ok(()); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b54cb8c5a0c..0e19a67a841 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2338,7 +2338,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName))?; + let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?; let ty = if this.eat(&token::Colon) { this.parse_ty()? } else { @@ -2781,7 +2781,7 @@ impl<'a> Parser<'a> { return None; } let pre_pat_snapshot = self.create_snapshot_for_diagnostic(); - match self.parse_pat_no_top_alt(None) { + match self.parse_pat_no_top_alt(None, None) { Ok(_pat) => { if self.token.kind == token::FatArrow { // Reached arm end. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1470180dea7..1301ed3e388 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -226,9 +226,9 @@ impl<'a> Parser<'a> { } else if self.is_static_global() { // STATIC ITEM self.bump(); // `static` - let m = self.parse_mutability(); - let (ident, ty, expr) = self.parse_item_global(Some(m))?; - (ident, ItemKind::Static(Box::new(StaticItem { ty, mutability: m, expr }))) + let mutability = self.parse_mutability(); + let (ident, item) = self.parse_static_item(mutability)?; + (ident, ItemKind::Static(Box::new(item))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -236,8 +236,16 @@ impl<'a> Parser<'a> { self.recover_const_impl(const_span, attrs, def_())? } else { self.recover_const_mut(const_span); - let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr }))) + let (ident, generics, ty, expr) = self.parse_const_item()?; + ( + ident, + ItemKind::Const(Box::new(ConstItem { + defaultness: def_(), + generics, + ty, + expr, + })), + ) } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -878,6 +886,7 @@ impl<'a> Parser<'a> { self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, + generics: Generics::default(), ty, expr, })) @@ -892,7 +901,7 @@ impl<'a> Parser<'a> { /// Parses a `type` alias with the following grammar: /// ```ebnf - /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; + /// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ; /// ``` /// The `"type"` has already been eaten. fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> { @@ -1220,33 +1229,132 @@ impl<'a> Parser<'a> { Ok(impl_info) } - /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with - /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. + /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in `mutability`. /// - /// When `m` is `"const"`, `$ident` may also be `"_"`. - fn parse_item_global( - &mut self, - m: Option<Mutability>, - ) -> PResult<'a, (Ident, P<Ty>, Option<P<ast::Expr>>)> { - let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; + /// ```ebnf + /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; + /// ``` + fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> { + let ident = self.parse_ident()?; + + if self.token.kind == TokenKind::Lt && self.may_recover() { + let generics = self.parse_generics()?; + self.sess.emit_err(errors::StaticWithGenerics { span: generics.span }); + } - // Parse the type of a `const` or `static mut?` item. - // That is, the `":" $ty` fragment. + // Parse the type of a static item. That is, the `":" $ty` fragment. + // FIXME: This could maybe benefit from `.may_recover()`? let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi)) { - // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type. (true, false) => self.parse_ty()?, - (colon, _) => self.recover_missing_const_type(colon, m), + // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing type. + (colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)), + }; + + let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; + + self.expect_semi()?; + + Ok((ident, StaticItem { ty, mutability, expr })) + } + + /// Parse a constant item with the prefix `"const"` already parsed. + /// + /// ```ebnf + /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ; + /// ``` + fn parse_const_item(&mut self) -> PResult<'a, (Ident, Generics, P<Ty>, Option<P<ast::Expr>>)> { + let ident = self.parse_ident_or_underscore()?; + + let mut generics = self.parse_generics()?; + + // Check the span for emptiness instead of the list of parameters in order to correctly + // recognize and subsequently flag empty parameter lists (`<>`) as unstable. + if !generics.span.is_empty() { + self.sess.gated_spans.gate(sym::generic_const_items, generics.span); + } + + // Parse the type of a constant item. That is, the `":" $ty` fragment. + // FIXME: This could maybe benefit from `.may_recover()`? + let ty = match ( + self.eat(&token::Colon), + self.check(&token::Eq) | self.check(&token::Semi) | self.check_keyword(kw::Where), + ) { + (true, false) => self.parse_ty()?, + // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type. + (colon, _) => self.recover_missing_global_item_type(colon, None), }; + // Proactively parse a where-clause to be able to provide a good error message in case we + // encounter the item body following it. + let before_where_clause = + if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() }; + let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; + + let after_where_clause = self.parse_where_clause()?; + + // Provide a nice error message if the user placed a where-clause before the item body. + // 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 { + self.sess.emit_err(errors::WhereClauseBeforeConstBody { + span: before_where_clause.span, + name: ident.span, + body: expr.span, + sugg: if !after_where_clause.has_where_token { + self.sess.source_map().span_to_snippet(expr.span).ok().map(|body| { + errors::WhereClauseBeforeConstBodySugg { + left: before_where_clause.span.shrink_to_lo(), + snippet: body, + right: before_where_clause.span.shrink_to_hi().to(expr.span), + } + }) + } else { + // FIXME(generic_const_items): Provide a structured suggestion to merge the first + // where-clause into the second one. + None + }, + }); + } + + // Merge the predicates of both where-clauses since either one can be relevant. + // If we didn't parse a body (which is valid for associated consts in traits) and we were + // allowed to recover, `before_where_clause` contains the predicates, otherwise they are + // in `after_where_clause`. Further, both of them might contain predicates iff two + // where-clauses were provided which is syntactically ill-formed but we want to recover from + // it and treat them as one large where-clause. + let mut predicates = before_where_clause.predicates; + predicates.extend(after_where_clause.predicates); + let where_clause = WhereClause { + has_where_token: before_where_clause.has_where_token + || after_where_clause.has_where_token, + predicates, + span: if after_where_clause.has_where_token { + after_where_clause.span + } else { + before_where_clause.span + }, + }; + + if where_clause.has_where_token { + self.sess.gated_spans.gate(sym::generic_const_items, where_clause.span); + } + + generics.where_clause = where_clause; + self.expect_semi()?; - Ok((id, ty, expr)) + + Ok((ident, generics, ty, expr)) } /// We were supposed to parse `":" $ty` but the `:` or the type was missing. /// This means that the type is missing. - fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> { + fn recover_missing_global_item_type( + &mut self, + colon_present: bool, + m: Option<Mutability>, + ) -> P<Ty> { // Construct the error and stash it away with the hope // that typeck will later enrich the error with a type. let kind = match m { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2e1a61e634e..37b4c371c94 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -138,7 +138,6 @@ pub struct Parser<'a> { // Important: This must only be advanced from `bump` to ensure that // `token_cursor.num_next_calls` is updated properly. token_cursor: TokenCursor, - desugar_doc_comments: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. @@ -225,6 +224,9 @@ struct TokenCursor { // because it's the outermost token stream which never has delimiters. stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>, + // We need to desugar doc comments from `/// foo` form into `#[doc = + // r"foo"]` form when parsing declarative macro inputs in `parse_tt`, + // because some declarative macros look for `doc` attributes. desugar_doc_comments: bool, // Counts the number of calls to `{,inlined_}next`. @@ -255,33 +257,38 @@ struct TokenCursor { } impl TokenCursor { - fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) { - self.inlined_next(desugar_doc_comments) + fn next(&mut self) -> (Token, Spacing) { + self.inlined_next() } /// This always-inlined version should only be used on hot code paths. #[inline(always)] - fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) { + fn inlined_next(&mut self) -> (Token, Spacing) { loop { // FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will // need to, whereupon the `delim != Delimiter::Invisible` conditions below can be // removed. if let Some(tree) = self.tree_cursor.next_ref() { match tree { - &TokenTree::Token(ref token, spacing) => match (desugar_doc_comments, token) { - (true, &Token { kind: token::DocComment(_, attr_style, data), span }) => { - let desugared = self.desugar(attr_style, data, span); - self.tree_cursor.replace_prev_and_rewind(desugared); - // Continue to get the first token of the desugared doc comment. - } - _ => { - debug_assert!(!matches!( - token.kind, - token::OpenDelim(_) | token::CloseDelim(_) - )); - return (token.clone(), spacing); + &TokenTree::Token(ref token, spacing) => { + match (self.desugar_doc_comments, token) { + ( + true, + &Token { kind: token::DocComment(_, attr_style, data), span }, + ) => { + let desugared = self.desugar(attr_style, data, span); + self.tree_cursor.replace_prev_and_rewind(desugared); + // Continue to get the first token of the desugared doc comment. + } + _ => { + debug_assert!(!matches!( + token.kind, + token::OpenDelim(_) | token::CloseDelim(_) + )); + return (token.clone(), spacing); + } } - }, + } &TokenTree::Delimited(sp, delim, ref tts) => { let trees = tts.clone().into_trees(); self.stack.push((mem::replace(&mut self.tree_cursor, trees), delim, sp)); @@ -463,7 +470,6 @@ impl<'a> Parser<'a> { desugar_doc_comments, break_last_token: false, }, - desugar_doc_comments, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, last_unexpected_token_span: None, @@ -1107,7 +1113,7 @@ impl<'a> Parser<'a> { pub fn bump(&mut self) { // Note: destructuring here would give nicer code, but it was found in #96210 to be slower // than `.0`/`.1` access. - let mut next = self.token_cursor.inlined_next(self.desugar_doc_comments); + let mut next = self.token_cursor.inlined_next(); self.token_cursor.num_next_calls += 1; // We've retrieved an token from the underlying // cursor, so we no longer need to worry about @@ -1157,7 +1163,7 @@ impl<'a> Parser<'a> { let mut i = 0; let mut token = Token::dummy(); while i < dist { - token = cursor.next(/* desugar_doc_comments */ false).0; + token = cursor.next().0; if matches!( token.kind, token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index adb0d372a40..f5681532b3a 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -131,7 +131,7 @@ impl<'a> Parser<'a> { }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None), + NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None), NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt( None, RecoverComma::No, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 14891c45d81..8d68a3a50ac 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -2,10 +2,11 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, - ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, - InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, - RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, + ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, + InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, + PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, + TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, + UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -80,7 +81,8 @@ enum EatOrResult { } /// The syntax location of a given pattern. Used for diagnostics. -pub(super) enum PatternLocation { +#[derive(Clone, Copy)] +pub enum PatternLocation { LetBinding, FunctionParameter, } @@ -91,8 +93,12 @@ impl<'a> Parser<'a> { /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns /// at the top level. Used when parsing the parameters of lambda expressions, /// functions, function pointers, and `pat` macro fragments. - pub fn parse_pat_no_top_alt(&mut self, expected: Option<Expected>) -> PResult<'a, P<Pat>> { - self.parse_pat_with_range_pat(true, expected) + pub fn parse_pat_no_top_alt( + &mut self, + expected: Option<Expected>, + syntax_loc: Option<PatternLocation>, + ) -> PResult<'a, P<Pat>> { + self.parse_pat_with_range_pat(true, expected, syntax_loc) } /// Parses a pattern. @@ -110,7 +116,7 @@ impl<'a> Parser<'a> { ra: RecoverColon, rt: CommaRecoveryMode, ) -> PResult<'a, P<Pat>> { - self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt).map(|(pat, _)| pat) + self.parse_pat_allow_top_alt_inner(expected, rc, ra, rt, None).map(|(pat, _)| pat) } /// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true = @@ -121,6 +127,7 @@ impl<'a> Parser<'a> { rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, + syntax_loc: Option<PatternLocation>, ) -> PResult<'a, (P<Pat>, bool)> { // Keep track of whether we recovered from a trailing vert so that we can avoid duplicated // suggestions (which bothers rustfix). @@ -133,7 +140,7 @@ impl<'a> Parser<'a> { }; // Parse the first pattern (`p_0`). - let mut first_pat = self.parse_pat_no_top_alt(expected)?; + let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?; if rc == RecoverComma::Yes { self.maybe_recover_unexpected_comma(first_pat.span, rt)?; } @@ -172,7 +179,7 @@ impl<'a> Parser<'a> { break; } } - let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| { + let pat = self.parse_pat_no_top_alt(expected, syntax_loc).map_err(|mut err| { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; @@ -208,6 +215,7 @@ impl<'a> Parser<'a> { rc, RecoverColon::No, CommaRecoveryMode::LikelyTuple, + Some(syntax_loc), )?; let colon = self.eat(&token::Colon); @@ -319,6 +327,7 @@ impl<'a> Parser<'a> { &mut self, allow_range_pat: bool, expected: Option<Expected>, + syntax_loc: Option<PatternLocation>, ) -> PResult<'a, P<Pat>> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -358,11 +367,11 @@ impl<'a> Parser<'a> { // Parse _ PatKind::Wild } else if self.eat_keyword(kw::Mut) { - self.parse_pat_ident_mut()? + self.parse_pat_ident_mut(syntax_loc)? } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))? + self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)? } else if self.eat_keyword(kw::Box) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -384,7 +393,7 @@ impl<'a> Parser<'a> { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. - self.parse_pat_ident(BindingAnnotation::NONE)? + self.parse_pat_ident(BindingAnnotation::NONE, syntax_loc)? } else if self.is_start_of_pat_with_path() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { @@ -485,7 +494,7 @@ impl<'a> Parser<'a> { // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` - let mut rhs = self.parse_pat_no_top_alt(None)?; + let mut rhs = self.parse_pat_no_top_alt(None, None)?; let whole_span = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind { @@ -541,7 +550,7 @@ impl<'a> Parser<'a> { } let mutbl = self.parse_mutability(); - let subpat = self.parse_pat_with_range_pat(false, expected)?; + let subpat = self.parse_pat_with_range_pat(false, expected, None)?; Ok(PatKind::Ref(subpat, mutbl)) } @@ -566,12 +575,12 @@ impl<'a> Parser<'a> { } /// Parse a mutable binding with the `mut` token already eaten. - fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { + fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResult<'a, PatKind> { let mut_span = self.prev_token.span; if self.eat_keyword(kw::Ref) { self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) }); - return self.parse_pat_ident(BindingAnnotation::REF_MUT); + return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc); } self.recover_additional_muts(); @@ -584,7 +593,7 @@ impl<'a> Parser<'a> { } // Parse the pattern we hope to be an identifier. - let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?; + let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?; // If we don't have `mut $ident (@ pat)?`, error. if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind @@ -810,10 +819,25 @@ impl<'a> Parser<'a> { /// Parses `ident` or `ident @ pat`. /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. - fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> { + fn parse_pat_ident( + &mut self, + binding_annotation: BindingAnnotation, + syntax_loc: Option<PatternLocation>, + ) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; + + if !matches!(syntax_loc, Some(PatternLocation::FunctionParameter)) + && self.check_noexpect(&token::Lt) + && self.look_ahead(1, |t| t.can_begin_type()) + { + return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax { + span: self.token.span, + suggest_turbofish: self.token.span.shrink_to_lo(), + })); + } + let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?) } else { None }; @@ -902,14 +926,14 @@ impl<'a> Parser<'a> { // We cannot use `parse_pat_ident()` since it will complain `box` // is not an identifier. let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?) } else { None }; Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub)) } else { - let pat = self.parse_pat_with_range_pat(false, None)?; + let pat = self.parse_pat_with_range_pat(false, None, None)?; self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span)); Ok(PatKind::Box(pat)) } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index fc437c429fb..e70817d7b7c 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -157,10 +157,8 @@ impl<'tcx> CheckConstVisitor<'tcx> { // is a pretty narrow case, however. if tcx.sess.is_nightly_build() { for gate in missing_secondary { - let note = format!( - "add `#![feature({})]` to the crate attributes to enable", - gate, - ); + let note = + format!("add `#![feature({gate})]` to the crate attributes to enable",); err.help(note); } } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 363e1743677..f825363ae39 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -89,9 +89,8 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { self.error(|| { format!( - "ItemLocalIds not assigned densely in {}. \ - Max ItemLocalId = {}, missing IDs = {:#?}; seen IDs = {:#?}", - pretty_owner, max, missing_items, seen_items + "ItemLocalIds not assigned densely in {pretty_owner}. \ + Max ItemLocalId = {max}, missing IDs = {missing_items:#?}; seen IDs = {seen_items:#?}" ) }); } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 6c748147abe..5aa8aef6a85 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -126,12 +126,12 @@ impl<'k> StatCollector<'k> { let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum(); - eprintln!("{} {}", prefix, title); + eprintln!("{prefix} {title}"); eprintln!( "{} {:<18}{:>18}{:>14}{:>14}", prefix, "Name", "Accumulated Size", "Count", "Item Size" ); - eprintln!("{} ----------------------------------------------------------------", prefix); + eprintln!("{prefix} ----------------------------------------------------------------"); let percent = |m, n| (m * 100) as f64 / n as f64; @@ -163,9 +163,9 @@ impl<'k> StatCollector<'k> { } } } - eprintln!("{} ----------------------------------------------------------------", prefix); + eprintln!("{prefix} ----------------------------------------------------------------"); eprintln!("{} {:<18}{:>10}", prefix, "Total", to_readable_str(total_size)); - eprintln!("{}", prefix); + eprintln!("{prefix}"); } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 89c6704e416..15757a0f1ad 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -605,7 +605,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for var_idx in 0..self.ir.var_kinds.len() { let var = Variable::from(var_idx); if test(var) { - write!(wr, " {:?}", var)?; + write!(wr, " {var:?}")?; } } Ok(()) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 160528e4074..7dec5b0acc8 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -236,7 +236,7 @@ impl<'tcx> ReachableContext<'tcx> { // Reachable constants will be inlined into other crates // unconditionally, so we need to make sure that their // contents are also reachable. - hir::ItemKind::Const(_, init) | hir::ItemKind::Static(_, _, init) => { + hir::ItemKind::Const(_, _, init) | hir::ItemKind::Static(_, _, init) => { self.visit_nested_body(init); } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ff63e4e33cb..5814e3d6c13 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,6 +41,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Module(self.0), ambiguity: None, + warn_ambiguity: false, vis: self.1.to_def_id(), span: self.2, expansion: self.3, @@ -53,6 +54,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(self.0), ambiguity: None, + warn_ambiguity: false, vis: self.1.to_def_id(), span: self.2, expansion: self.3, @@ -69,7 +71,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { let binding = def.to_name_binding(self.arenas); let key = self.new_disambiguated_key(ident, ns); - if let Err(old_binding) = self.try_define(parent, key, binding) { + if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 73cd596c076..97ac6891d82 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,10 +5,8 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; -use rustc_errors::{struct_span_err, SuggestionStyle}; +use rustc_errors::{pluralize, report_ambiguity_error, struct_span_err, SuggestionStyle}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; @@ -17,8 +15,9 @@ use rustc_hir::PrimTy; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE; +use rustc_session::lint::builtin::AMBIGUOUS_GLOB_IMPORTS; use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiagnostics}; use rustc_session::Session; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; @@ -135,7 +134,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } for ambiguity_error in &self.ambiguity_errors { - self.report_ambiguity_error(ambiguity_error); + let diag = self.ambiguity_diagnostics(ambiguity_error); + if ambiguity_error.warning { + let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { + unreachable!() + }; + self.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_IMPORTS, + import.root_id, + ambiguity_error.ident.span, + diag.msg.to_string(), + BuiltinLintDiagnostics::AmbiguousGlobImports { diag }, + ); + } else { + let mut err = struct_span_err!(self.tcx.sess, diag.span, E0659, "{}", &diag.msg); + report_ambiguity_error(&mut err, diag); + err.emit(); + } } let mut reported_spans = FxHashSet::default(); @@ -1540,20 +1555,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) { - let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error; + fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag { + let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. (b2, b1, misc2, misc1, true) } else { (b1, b2, misc1, misc2, false) }; - - let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous"); - err.span_label(ident.span, "ambiguous name"); - err.note(format!("ambiguous because of {}", kind.descr())); - - let mut could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { + let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -1579,16 +1589,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {} } - err.span_note(b.span, note_msg); - for (i, help_msg) in help_msgs.iter().enumerate() { - let or = if i == 0 { "" } else { "or " }; - err.help(format!("{}{}", or, help_msg)); - } + ( + b.span, + note_msg, + help_msgs + .iter() + .enumerate() + .map(|(i, help_msg)| { + let or = if i == 0 { "" } else { "or " }; + format!("{}{}", or, help_msg) + }) + .collect::<Vec<_>>(), + ) }; - - could_refer_to(b1, misc1, ""); - could_refer_to(b2, misc2, " also"); - err.emit(); + let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, ""); + let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + + AmbiguityErrorDiag { + msg: format!("`{ident}` is ambiguous"), + span: ident.span, + label_span: ident.span, + label_msg: "ambiguous name".to_string(), + note_msg: format!("ambiguous because of {}", kind.descr()), + b1_span, + b1_note_msg, + b1_help_msgs, + b2_span, + b2_note_msg, + b2_help_msgs, + } } /// If the binding refers to a tuple struct constructor with fields, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index de431444769..00282df700b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -677,6 +677,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident: orig_ident, b1: innermost_binding, b2: binding, + warning: false, misc1: misc(innermost_flags), misc2: misc(flags), }); @@ -905,6 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ident, b1: binding, b2: shadowed_glob, + warning: false, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, }); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f3cf61c5b93..e1dae57d34f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -284,6 +284,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Import { binding, import, used: Cell::new(false) }, ambiguity: None, + warn_ambiguity: false, span: import.span, vis, expansion: import.parent_scope.expansion, @@ -291,16 +292,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } /// Define the name or return the existing binding if there is a collision. + /// `update` indicates if the definition is a redefinition of an existing binding. pub(crate) fn try_define( &mut self, module: Module<'a>, key: BindingKey, binding: NameBinding<'a>, + warn_ambiguity: bool, ) -> Result<(), NameBinding<'a>> { let res = binding.res(); self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); - self.update_resolution(module, key, |this, resolution| { + self.update_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_binding) = resolution.binding { if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. @@ -308,15 +311,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { - if res != old_binding.res() { - resolution.binding = Some(this.ambiguity( - AmbiguityKind::GlobVsGlob, - old_binding, - binding, - )); + // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity. + if !binding.is_ambiguity() + && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind + && let NameBindingKind::Import { import, .. } = binding.kind + && old_import == import { + // We should replace the `old_binding` with `binding` regardless + // of whether they has same resolution or not when they are + // imported from the same glob-import statement. + // However we currently using `Some(old_binding)` for back compact + // purposes. + // This case can be removed after once `Undetermined` is prepared + // for glob-imports. + } else if res != old_binding.res() { + let binding = if warn_ambiguity { + this.warn_ambiguity( + AmbiguityKind::GlobVsGlob, + old_binding, + binding, + ) + } else { + this.ambiguity( + AmbiguityKind::GlobVsGlob, + old_binding, + binding, + ) + }; + resolution.binding = Some(binding); } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); + } else if binding.is_ambiguity() { + resolution.binding = + Some(self.arenas.alloc_name_binding(NameBindingData { + warn_ambiguity: true, + ..(*binding).clone() + })); } } (old_glob @ true, false) | (old_glob @ false, true) => { @@ -374,29 +404,52 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }) } + fn warn_ambiguity( + &self, + kind: AmbiguityKind, + primary_binding: NameBinding<'a>, + secondary_binding: NameBinding<'a>, + ) -> NameBinding<'a> { + self.arenas.alloc_name_binding(NameBindingData { + ambiguity: Some((secondary_binding, kind)), + warn_ambiguity: true, + ..(*primary_binding).clone() + }) + } + // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. - fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T + fn update_resolution<T, F>( + &mut self, + module: Module<'a>, + key: BindingKey, + warn_ambiguity: bool, + f: F, + ) -> T where F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T, { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. - let (binding, t) = { + let (binding, t, warn_ambiguity) = { let resolution = &mut *self.resolution(module, key).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); - if old_binding.is_none() && let Some(binding) = resolution.binding() { - (binding, t) + if let Some(binding) = resolution.binding() && old_binding != Some(binding) { + (binding, t, warn_ambiguity || old_binding.is_some()) } else { return t; } }; - // Define `binding` in `module`s glob importers. - for import in module.glob_importers.borrow_mut().iter() { + let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else { + return t; + }; + + // Define or update `binding` in `module`s glob importers. + for import in glob_importers.iter() { let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), @@ -406,7 +459,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, *import); let key = BindingKey { ident, ..key }; - let _ = self.try_define(import.parent_scope.module, key, imported_binding); + let _ = self.try_define( + import.parent_scope.module, + key, + imported_binding, + warn_ambiguity, + ); } } @@ -425,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { let key = BindingKey::new(target, ns); - let _ = this.try_define(import.parent_scope.module, key, dummy_binding); + let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); }); self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { @@ -700,7 +758,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Segment::names_to_string(&import.module_path), module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()), ); - let module = if let Some(module) = import.imported_module.get() { module } else { @@ -773,7 +830,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .emit(); } let key = BindingKey::new(target, ns); - this.update_resolution(parent, key, |_, resolution| { + this.update_resolution(parent, key, false, |_, resolution| { resolution.single_imports.remove(&import); }); } @@ -989,7 +1046,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { initial_binding.res() }); let res = binding.res(); - if res == Res::Err || !this.ambiguity_errors.is_empty() { + let has_ambiguity_error = this + .ambiguity_errors + .iter() + .filter(|error| !error.warning) + .next() + .is_some(); + if res == Res::Err || has_ambiguity_error { this.tcx .sess .delay_span_bug(import.span, "some error happened for an import"); @@ -1338,7 +1401,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; if self.is_accessible_from(binding.vis, scope) { let imported_binding = self.import(binding, import); - let _ = self.try_define(import.parent_scope.module, key, imported_binding); + let warn_ambiguity = self + .resolution(import.parent_scope.module, key) + .borrow() + .binding() + .is_some_and(|binding| binding.is_warn_ambiguity()); + let _ = self.try_define( + import.parent_scope.module, + key, + imported_binding, + warn_ambiguity, + ); } } @@ -1357,7 +1430,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module.for_each_child(self, |this, ident, _, binding| { let res = binding.res().expect_non_local(); - if res != def::Res::Err && !binding.is_ambiguity() { + let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity; + if res != def::Res::Err && !error_ambiguity { let mut reexport_chain = SmallVec::new(); let mut next_binding = binding; while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index aab71494fd3..6872b1b24a9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -337,6 +337,7 @@ enum LifetimeBinderKind { PolyTrait, WhereBound, Item, + ConstItem, Function, Closure, ImplBlock, @@ -349,7 +350,7 @@ impl LifetimeBinderKind { BareFnType => "type", PolyTrait => "bound", WhereBound => "bound", - Item => "item", + Item | ConstItem => "item", ImplBlock => "impl block", Function => "function", Closure => "closure", @@ -2404,30 +2405,44 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) - | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); - this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + 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((item.ident, ConstantItemKind::Static))); + } + }); + } + + ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span)), + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::ConstItem, + span: generics.span, + }, + |this| { + this.visit_generics(generics); + + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Static), + |this| this.visit_ty(ty), + ); + if let Some(expr) = expr { - let constant_item_kind = match item.kind { - ItemKind::Const(..) => ConstantItemKind::Const, - ItemKind::Static(..) => ConstantItemKind::Static, - _ => unreachable!(), - }; - // We already forbid generic params because of the above item rib, - // so it doesn't matter whether this is a trivial constant. - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - Some((item.ident, constant_item_kind)), - |this| this.visit_expr(expr), + this.resolve_const_body( + expr, + Some((item.ident, ConstantItemKind::Const)), ); } - }); - }); + }, + ); } ItemKind::Use(ref use_tree) => { @@ -2700,28 +2715,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { - self.visit_ty(ty); - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = expr { - // 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. - self.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), - |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }, - ); - } + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::ConstItem, + }, + |this| { + this.visit_generics(generics); + this.visit_ty(ty); + + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = expr { + // 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); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); @@ -2876,36 +2894,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { debug!("resolve_implementation AssocItemKind::Const"); - // If this is a trait impl, ensure the const - // exists in trait - self.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); - self.visit_ty(ty); - if let Some(expr) = expr { - // 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. - self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }); - } + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::ConstItem, + }, + |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); + + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // 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); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -3063,6 +3087,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } + fn resolve_const_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) + }); + }) + } + fn resolve_params(&mut self, params: &'ast [Param]) { let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { @@ -4448,6 +4480,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { fn visit_item(&mut self, item: &'ast Item) { match &item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) + | ItemKind::Const(box ConstItem { ref generics, .. }) | ItemKind::Fn(box Fn { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) @@ -4467,7 +4500,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { ItemKind::Mod(..) | ItemKind::ForeignMod(..) | ItemKind::Static(..) - | ItemKind::Const(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 753a1adc66d..072fa864f4e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2348,6 +2348,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut should_continue = true; match rib.kind { LifetimeRibKind::Generics { binder: _, span, kind } => { + // Avoid suggesting placing lifetime parameters on constant items unless the relevant + // feature is enabled. Suggest the parent item as a possible location if applicable. + if let LifetimeBinderKind::ConstItem = kind + && !self.r.tcx().features().generic_const_items + { + continue; + } + if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index faa672db59c..91d89f44dbf 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -658,6 +658,7 @@ impl<'a> fmt::Debug for Module<'a> { struct NameBindingData<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>, + warn_ambiguity: bool, expansion: LocalExpnId, span: Span, vis: ty::Visibility<DefId>, @@ -767,6 +768,7 @@ struct AmbiguityError<'a> { b2: NameBinding<'a>, misc1: AmbiguityErrorMisc, misc2: AmbiguityErrorMisc, + warning: bool, } impl<'a> NameBindingData<'a> { @@ -794,6 +796,14 @@ impl<'a> NameBindingData<'a> { } } + fn is_warn_ambiguity(&self) -> bool { + self.warn_ambiguity + || match self.kind { + NameBindingKind::Import { binding, .. } => binding.is_warn_ambiguity(), + _ => false, + } + } + fn is_possibly_imported_variant(&self) -> bool { match self.kind { NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), @@ -1322,6 +1332,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { dummy_binding: arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(Res::Err), ambiguity: None, + warn_ambiguity: false, expansion: LocalExpnId::ROOT, span: DUMMY_SP, vis: ty::Visibility::Public, @@ -1685,6 +1696,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) { + self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity); + } + + fn record_use_inner( + &mut self, + ident: Ident, + used_binding: NameBinding<'a>, + is_lexical_scope: bool, + warn_ambiguity: bool, + ) { if let Some((b2, kind)) = used_binding.ambiguity { let ambiguity_error = AmbiguityError { kind, @@ -1693,9 +1714,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { b2, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, + warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { - // avoid duplicated span information to be emitt out + // avoid duplicated span information to be emit out self.ambiguity_errors.push(ambiguity_error); } } @@ -1715,7 +1737,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.used_imports.insert(id); } self.add_to_glob_map(import, ident); - self.record_use(ident, binding, false); + self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 266e37e4cef..d456cc9a9a0 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE}; +use rustc_session::lint::builtin::{ + LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, +}; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; @@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } } } - // We implicitly add `rustfmt` and `clippy` to known tools, + // We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools, // but it's not an error to register them explicitly. - let predefined_tools = [sym::clippy, sym::rustfmt]; + let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic]; registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); registered_tools } @@ -595,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) + && path.segments.len() >= 2 + && path.segments[0].ident.name == sym::diagnostic + { + self.tcx.sess.parse_sess.buffer_lint( + UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + path.segments[1].span(), + node_id, + "unknown diagnostic attribute", + ); + } + Ok((ext, res)) } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 1291d1454a6..e26d25d9a41 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [dependencies] -atty = "0.2.13" bitflags = "1.2.1" getopts = "0.2" rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 36b5c385ab1..88bbadefe26 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -834,9 +834,10 @@ impl OutFileName { } pub fn is_tty(&self) -> bool { + use std::io::IsTerminal; match *self { OutFileName::Real(_) => false, - OutFileName::Stdout => atty::is(atty::Stream::Stdout), + OutFileName::Stdout => std::io::stdout().is_terminal(), } } @@ -2151,6 +2152,12 @@ fn collect_print_requests( prints.extend(matches.opt_strs("print").into_iter().map(|req| { let (req, out) = split_out_file_name(&req); + if out.is_some() && !unstable_opts.unstable_options { + handler.early_error( + "the `-Z unstable-options` flag must also be passed to \ + enable the path print option", + ); + } let kind = match PRINT_KINDS.iter().find(|&&(name, _)| name == req) { Some((_, PrintKind::TargetSpec)) => { if unstable_opts.unstable_options { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index cefcab1e18f..0a33030c603 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -156,7 +156,9 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { ops.0.stable(tables), ops.1.stable(tables), ), - NullaryOp(_, _) => todo!(), + NullaryOp(null_op, ty) => { + stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), tables.intern_ty(*ty)) + } UnaryOp(un_op, op) => { stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables)) } diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 831eb6589e4..1b1871bcd2a 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -218,6 +218,9 @@ pub enum Rvalue { /// nature of this operation? ThreadLocalRef(stable_mir::CrateItem), + /// Computes a value as described by the operation. + NullaryOp(NullOp, Ty), + /// Exactly like `BinaryOp`, but less operands. /// /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 54eb7bef5f2..d3739733c1d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -620,6 +620,7 @@ symbols! { destruct, destructuring_assignment, diagnostic, + diagnostic_namespace, direct, discriminant_kind, discriminant_type, @@ -782,6 +783,7 @@ symbols! { generic_associated_types, generic_associated_types_extended, generic_const_exprs, + generic_const_items, generic_param_attrs, get_context, global_allocator, @@ -1369,9 +1371,13 @@ symbols! { simd_arith_offset, simd_as, simd_bitmask, + simd_bitreverse, + simd_bswap, simd_cast, simd_cast_ptr, simd_ceil, + simd_ctlz, + simd_cttz, simd_div, simd_eq, simd_expose_addr, diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 255620489ff..88771f90756 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -125,9 +125,8 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> { // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - // - // This algorithm runs in `O(nm)` where `n` is the number of different universe - // indices in the input and `m` is the number of canonical variables. - // This should be fine as both `n` and `m` are expected to be small. + // This algorithm runs in `O(n²)` where `n` is the number of different universe + // indices in the input. This should be fine as `n` is expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; let mut existential_in_new_uv = false; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); @@ -263,14 +262,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { ty::ReError(_) => return r, }; - let var = ty::BoundVar::from( - self.variables.iter().position(|&v| v == r.into()).unwrap_or_else(|| { - let var = self.variables.len(); - self.variables.push(r.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }), - ); + let existing_bound_var = match self.canonicalize_mode { + CanonicalizeMode::Input => None, + CanonicalizeMode::Response { .. } => { + self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) + } + }; + let var = existing_bound_var.unwrap_or_else(|| { + let var = ty::BoundVar::from(self.variables.len()); + self.variables.push(r.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }); let br = ty::BoundRegion { var, kind: BrAnon(None) }; ty::Region::new_late_bound(self.interner(), self.binder_index, br) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index f48a992d327..9e3b0bbc4fb 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(response) => response, }; - let has_changed = !canonical_response.value.var_values.is_identity() + let has_changed = !canonical_response.value.var_values.is_identity_modulo_regions() || !canonical_response.value.external_constraints.opaque_types.is_empty(); let (certainty, nested_goals) = match self.instantiate_and_apply_query_response( goal.param_env, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 24ea9b5ea12..40ce4a3b3e4 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -449,14 +449,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - if !goal.param_env.is_const() { - // `Destruct` is automatically implemented for every type in - // non-const environments. - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver - Err(NoSolution) - } + // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver + + // `Destruct` is automatically implemented for every type in + // non-const environments. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } fn consider_builtin_transmute_candidate( diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 27cd0f99f34..c26849d484e 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -347,14 +347,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { new_env = ty::ParamEnv::new( tcx.mk_clauses_from_iter(normalized_preds.filter_map(|p| p.as_clause())), param_env.reveal(), - param_env.constness(), ); } let final_user_env = ty::ParamEnv::new( tcx.mk_clauses_from_iter(user_computed_preds.into_iter().filter_map(|p| p.as_clause())), user_env.reveal(), - user_env.constness(), ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index c14839fe9be..cbd81cae989 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -687,9 +687,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); - let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - trait_predicate.remap_constness_diag(obligation.param_env); let predicate_is_const = ty::BoundConstness::ConstIfConst == trait_predicate.skip_binder().constness; @@ -3108,11 +3107,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span: Span, ) -> UnsatisfiedConst { let mut unsatisfied_const = UnsatisfiedConst(false); - if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { + if trait_predicate.is_const_if_const() { let non_const_predicate = trait_ref.without_const(); let non_const_obligation = Obligation { cause: obligation.cause.clone(), - param_env: obligation.param_env.without_const(), + param_env: obligation.param_env, predicate: non_const_predicate.to_predicate(self.tcx), recursion_depth: obligation.recursion_depth, }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 220b3576ddb..1eb4447ae4e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -41,7 +41,6 @@ use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::borrow::Cow; use std::iter; -use std::ops::Deref; use super::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; @@ -655,6 +654,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. @@ -720,6 +720,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. @@ -3136,7 +3137,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::ImplDerivedObligation(ref data) => { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); - parent_trait_pred.remap_constness_diag(param_env); let parent_def_id = parent_trait_pred.def_id(); let (self_ty, file) = self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); @@ -3576,7 +3576,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // to an associated type (as seen from `trait_pred`) in the predicate. Like in // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>` let mut type_diffs = vec![]; - if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref() + if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code && let Some(node_args) = typeck_results.node_args_opt(call_hir_id) && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args) && let Some(where_pred) = where_clauses.predicates.get(*idx) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 6bab87e5de5..593f669e9bb 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -328,11 +328,7 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new( - tcx.mk_clauses(&predicates), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ); + let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -376,11 +372,8 @@ pub fn normalize_param_env_or_error<'tcx>( // here. I believe they should not matter, because we are ignoring TypeOutlives param-env // predicates here anyway. Keeping them here anyway because it seems safer. let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned(); - let outlives_env = ty::ParamEnv::new( - tcx.mk_clauses_from_iter(outlives_env), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ); + let outlives_env = + ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env), unnormalized_env.reveal()); let Ok(outlives_predicates) = do_normalize_predicates(tcx, cause, outlives_env, outlives_predicates) else { @@ -393,11 +386,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.mk_clauses(&predicates), - unnormalized_env.reveal(), - unnormalized_env.constness(), - ) + ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } /// Normalize a type and process all resulting obligations, returning any errors. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 143e8412967..abb05be80e9 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -761,11 +761,7 @@ fn receiver_is_dispatchable<'tcx>( let caller_bounds = param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); - ty::ParamEnv::new( - tcx.mk_clauses_from_iter(caller_bounds), - param_env.reveal(), - param_env.constness(), - ) + ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds), param_env.reveal()) }; // Receiver: DispatchFromDyn<Receiver[Self => U]> diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a50644bb709..65f32b1c48a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,5 +1,4 @@ use rustc_infer::traits::{TraitEngine, TraitEngineExt}; -use rustc_middle::ty; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; @@ -66,17 +65,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { ) -> Result<EvaluationResult, OverflowError> { let mut _orig_values = OriginalQueryValues::default(); - let param_env = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - // we ignore the value set to it. - let mut _constness = pred.constness; - obligation - .param_env - .with_constness(_constness.and(obligation.param_env.constness())) - } - // constness has no effect on the given predicate. - _ => obligation.param_env.without_const(), - }; + let param_env = obligation.param_env; if self.next_trait_solver() { self.probe(|snapshot| { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 420d6326553..302b6016e5e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -82,7 +82,6 @@ fn relate_mir_and_user_args<'tcx>( def_id: DefId, user_args: UserArgs<'tcx>, ) -> Result<(), NoSolution> { - let param_env = param_env.without_const(); let UserArgs { user_self_ty, args } = user_args; let tcx = ocx.infcx.tcx; let cause = ObligationCause::dummy_with_span(span); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index aa195d70a9f..b9f31be25b1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -124,11 +124,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_projected_tys(obligation, &mut candidates); self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates); - } + self.assemble_candidates_from_auto_impls(obligation, &mut candidates); } debug!("candidate list size: {}", candidates.vec.len()); Ok(candidates) @@ -513,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // for an example of a test case that exercises // this path. } - ty::Infer(ty::TyVar(_)) => { + ty::Infer(ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_)) => { // The auto impl might apply; we don't know. candidates.ambiguous = true; } @@ -533,7 +529,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - _ => candidates.vec.push(AutoImplCandidate), + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!( + "asked to assemble auto trait candidates of unexpected type: {:?}", + self_ty + ); + } + + ty::Alias(_, _) + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) => + { + // We do not generate an auto impl candidate for `impl Trait`s which already + // reference our auto trait. + // + // For example during candidate assembly for `impl Send: Send`, we don't have + // to look at the constituent types for this opaque types to figure out that this + // trivially holds. + // + // Note that this is only sound as projection candidates of opaque types + // are always applicable for auto traits. + } + ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate), + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::Adt(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Closure(_, _) + | ty::Generator(..) + | ty::Never + | ty::Tuple(_) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) => { + // Only consider auto impls if there are no manual impls for the root of `self_ty`. + // + // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl + // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls + // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. + // + // Generally, we have to guarantee that for all `SimplifiedType`s the only crate + // which may define impls for that type is either the crate defining the type + // or the trait. This should be guaranteed by the orphan check. + let mut has_impl = false; + self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true); + if !has_impl { + candidates.vec.push(AutoImplCandidate) + } + } + ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now. } } } @@ -839,7 +891,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // If the predicate is `~const Destruct` in a non-const environment, we don't actually need // to check anything. We'll short-circuit checking any obligations in confirmation, too. - if !obligation.is_const() { + // FIXME(effects) + if true { candidates.vec.push(ConstDestructCandidate(None)); return; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 92b9364adfa..7140fedb74a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -13,8 +13,8 @@ use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::{ - self, Binder, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, - TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, + self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, + TraitPredicate, Ty, TyCtxt, TypeVisitableExt, }; use rustc_span::def_id::DefId; @@ -647,7 +647,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_fn_pointer_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - is_const: bool, + // FIXME(effects) + _is_const: bool, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!(?obligation, "confirm_fn_pointer_candidate"); @@ -674,16 +675,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; let cause = obligation.derived_cause(BuiltinDerivedObligation); - if obligation.is_const() && !is_const { - // function is a trait method - if let ty::FnDef(def_id, args) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) { - let trait_ref = TraitRef::from_method(tcx, trait_id, *args); - let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst); - let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred); - nested.push(obligation); - } - } - // Confirm the `type Output: Sized;` bound that is present on `FnOnce` let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output()); let output_ty = normalize_with_depth_to( @@ -1211,7 +1202,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: Option<DefId>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` - if !obligation.is_const() { + // FIXME(effects) + if true { return Ok(vec![]); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e086489b1bc..b4875ec0ea3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1000,13 +1000,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let stack = self.push_stack(previous_stack, &obligation); - let mut fresh_trait_pred = stack.fresh_trait_pred; - let mut param_env = obligation.param_env; - - fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { - pred.remap_constness(&mut param_env); - pred - }); + let fresh_trait_pred = stack.fresh_trait_pred; + let param_env = obligation.param_env; debug!(?fresh_trait_pred); @@ -1386,8 +1381,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (result, dep_node) } - /// filter_impls filters constant trait obligations and candidates that have a positive impl - /// for a negative goal and a negative impl for a positive goal + /// filter_impls filters candidates that have a positive impl for a negative + /// goal and a negative impl for a positive goal #[instrument(level = "debug", skip(self, candidates))] fn filter_impls( &mut self, @@ -1399,42 +1394,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut result = Vec::with_capacity(candidates.len()); for candidate in candidates { - // Respect const trait obligations - if obligation.is_const() { - match candidate { - // const impl - ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {} - // const param - ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} - // const projection - ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) - // auto trait impl - | AutoImplCandidate - // generator / future, this will raise error in other places - // or ignore error with const_async_blocks feature - | GeneratorCandidate - | FutureCandidate - // FnDef where the function is const - | FnPointerCandidate { is_const: true } - | ConstDestructCandidate(_) - | ClosureCandidate { is_const: true } => {} - - FnPointerCandidate { is_const: false } => { - if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() { - // Trait methods are not seen as const unless the trait is implemented as const. - // We do not filter that out in here, but nested obligations will be needed to confirm this. - } else { - continue - } - } - - _ => { - // reject all other types of candidates - continue; - } - } - } - if let ImplCandidate(def_id) = candidate { if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id) || obligation.polarity() == tcx.impl_polarity(def_id) @@ -1487,7 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative { + if !self.is_intercrate() { return Ok(()); } @@ -1528,7 +1487,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { // Neither the global nor local cache is aware of intercrate @@ -1539,8 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + let pred = cache_fresh_trait_pred.skip_binder(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { @@ -1586,15 +1544,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")] fn insert_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, dep_node: DepNodeIndex, candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) { let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - - pred.remap_constness(&mut param_env); + let pred = cache_fresh_trait_pred.skip_binder(); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); @@ -1827,6 +1783,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { /// candidates and prefer where-clause candidates. /// /// See the comment for "SelectionCandidate" for more details. + #[instrument(level = "debug", skip(self))] fn candidate_should_be_dropped_in_favor_of( &mut self, victim: &EvaluatedCandidate<'tcx>, @@ -1850,13 +1807,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. match (&other.candidate, &victim.candidate) { - (_, AutoImplCandidate) | (AutoImplCandidate, _) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // FIXME(@jswrenn): this should probably be more sophisticated (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, @@ -1898,6 +1848,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ParamCandidate(ref other_cand), ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1925,6 +1876,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ( ImplCandidate(_) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1958,6 +1910,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ObjectCandidate(_) | ProjectionCandidate(..), ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -1971,6 +1924,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ( ImplCandidate(..) + | AutoImplCandidate | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate @@ -2061,6 +2015,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + (AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => { + DropVictim::No + } + + (AutoImplCandidate, _) | (_, AutoImplCandidate) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other global candidates: {:?} {:?}", + other, + victim + ); + } + // Everything else is ambiguous ( ImplCandidate(_) diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 8bd26818256..e8ddb0a4396 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -195,7 +195,7 @@ pub(crate) mod rustc { impl<'tcx> From<&LayoutError<'tcx>> for Err { fn from(err: &LayoutError<'tcx>) -> Self { match err { - LayoutError::Unknown(..) => Self::UnknownLayout, + LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, err => unimplemented!("{:?}", err), } } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 4a544232174..780f7ea426f 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -346,8 +346,16 @@ fn associated_type_for_impl_trait_in_impl( ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn_def_id); - // FIXME fix the span, we probably want the def_id of the return type of the function - let span = tcx.def_span(impl_fn_def_id); + let decl = tcx + .hir() + .find_by_def_id(impl_fn_def_id) + .expect("expected item") + .fn_decl() + .expect("expected decl"); + let span = match decl.output { + hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), + hir::FnRetTy::Return(ty) => ty.span, + }; let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy); let local_def_id = impl_assoc_ty.def_id(); diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index fa1976510cf..7eb1042d2f8 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,13 +1,22 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use std::iter; pub fn provide(providers: &mut Providers) { - *providers = Providers { assumed_wf_types, ..*providers }; + *providers = Providers { + assumed_wf_types, + assumed_wf_types_for_rpitit: |tcx, def_id| { + assert!(tcx.is_impl_trait_in_trait(def_id.to_def_id())); + tcx.assumed_wf_types(def_id) + }, + ..*providers + }; } fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { @@ -42,6 +51,81 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' let mut impl_spans = impl_spans(tcx, def_id); tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap()))) } + DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => match data { + ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => { + let hir::OpaqueTy { lifetime_mapping, .. } = + *tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty(); + // We need to remap all of the late-bound lifetimes in theassumed wf types + // of the fn (which are represented as ReFree) to the early-bound lifetimes + // of the RPITIT (which are represented by ReEarlyBound owned by the opaque). + // Luckily, this is very easy to do because we already have that mapping + // stored in the HIR of this RPITIT. + // + // Side-note: We don't really need to do this remapping for early-bound + // lifetimes because they're already "linked" by the bidirectional outlives + // predicates we insert in the `explicit_predicates_of` query for RPITITs. + let mut mapping = FxHashMap::default(); + let generics = tcx.generics_of(def_id); + for &(lifetime, new_early_bound_def_id) in + lifetime_mapping.expect("expected lifetime mapping for RPITIT") + { + if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) = + tcx.named_bound_var(lifetime.hir_id) + { + let name = tcx.hir().name(lifetime.hir_id); + let index = generics + .param_def_id_to_index(tcx, new_early_bound_def_id.to_def_id()) + .unwrap(); + mapping.insert( + ty::Region::new_free( + tcx, + fn_def_id, + ty::BoundRegionKind::BrNamed(def_id, name), + ), + ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: new_early_bound_def_id.to_def_id(), + index, + name, + }, + ), + ); + } + } + // FIXME: This could use a real folder, I guess. + let remapped_wf_tys = tcx.fold_regions( + tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), + |region, _| { + // If `region` is a `ReFree` that is captured by the + // opaque, remap it to its corresponding the early- + // bound region. + if let Some(remapped_region) = mapping.get(®ion) { + *remapped_region + } else { + region + } + }, + ); + tcx.arena.alloc_from_iter(remapped_wf_tys) + } + // Assumed wf types for RPITITs in an impl just inherit (and instantiate) + // the assumed wf types of the trait's RPITIT GAT. + ty::ImplTraitInTraitData::Impl { .. } => { + let impl_def_id = tcx.local_parent(def_id); + let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap(); + let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto( + tcx, + impl_def_id.to_def_id(), + tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args, + ); + tcx.arena.alloc_from_iter( + ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id)) + .iter_instantiated_copied(tcx, args) + .chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()), + ) + } + }, DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { DefKind::TyAlias => ty::List::empty(), diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index b840ff184e0..3500c2cc370 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -96,6 +96,13 @@ fn layout_of_uncached<'tcx>( cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, ty: Ty<'tcx>, ) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> { + // Types that reference `ty::Error` pessimistically don't have a meaningful layout. + // The only side-effect of this is possibly worse diagnostics in case the layout + // was actually computable (like if the `ty::Error` showed up only in a `PhantomData`). + if let Err(guar) = ty.error_reported() { + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + let tcx = cx.tcx; let param_env = cx.param_env; let dl = cx.data_layout(); @@ -564,11 +571,15 @@ fn layout_of_uncached<'tcx>( return Err(error(cx, LayoutError::Unknown(ty))); } - ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => { + ty::Bound(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Infer(_) + | ty::Error(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => { + ty::Placeholder(..) | ty::Param(_) => { return Err(error(cx, LayoutError::Unknown(ty))); } }) diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 55b8857ed39..147b600f7ba 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -8,6 +8,7 @@ #![feature(assert_matches)] #![feature(iterator_try_collect)] #![feature(let_chains)] +#![feature(if_let_guard)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index e173bba49be..f89558a4599 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -133,7 +133,7 @@ where _ => { tcx.sess.delay_span_bug( tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), - format!("unexpected generator witness type {:?}", witness), + format!("unexpected generator witness type {witness:?}"), ); return Some(Err(AlwaysRequiresDrop)); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 505f78d0e5f..2055852eda0 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -144,85 +144,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } let local_did = def_id.as_local(); - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This isn't correct for - // RPITITs in const trait fn. - let hir_id = local_did.and_then(|def_id| tcx.opt_local_def_id_to_hir_id(def_id)); - - // FIXME(consts): This is not exactly in line with the constness query. - let constness = match hir_id { - Some(hir_id) => match tcx.hir().get(hir_id) { - hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) - if tcx.is_const_default_method(def_id) => - { - hir::Constness::Const - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const(..), .. - }) - | hir::Node::AnonConst(_) - | hir::Node::ConstBlock(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - header: hir::FnHeader { constness: hir::Constness::Const, .. }, - .. - }, - .., - ), - .. - }) => hir::Constness::Const, - - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), - .. - }) => { - let parent_hir_id = tcx.hir().parent_id(hir_id); - match tcx.hir().get(parent_hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - _ => span_bug!( - tcx.def_span(parent_hir_id.owner), - "impl item's parent node is not an impl", - ), - } - } - - hir::Node::Item(hir::Item { - kind: - hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, - .., - ), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - - _ => hir::Constness::NotConst, - }, - // FIXME(consts): It's suspicious that a param-env for a foreign item - // will always have NotConst param-env, though we don't typically use - // that param-env for anything meaningful right now, so it's likely - // not an issue. - None => hir::Constness::NotConst, - }; let unnormalized_env = - ty::ParamEnv::new(tcx.mk_clauses(&predicates), traits::Reveal::UserFacing, constness); + ty::ParamEnv::new(tcx.mk_clauses(&predicates), traits::Reveal::UserFacing); let body_id = local_did.unwrap_or(CRATE_DEF_ID); let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); |
