diff options
Diffstat (limited to 'compiler')
381 files changed, 6403 insertions, 6092 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 549927d5898..ea194e10def 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -16,7 +16,7 @@ use rustc_data_structures::stable_hasher::StableOrd; #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; #[cfg(feature = "nightly")] use std::iter::Step; @@ -30,7 +30,7 @@ pub use layout::LayoutCalculator; pub trait HashStableContext {} #[derive(Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct ReprFlags(u8); bitflags! { @@ -52,7 +52,7 @@ bitflags! { rustc_data_structures::external_bitflags_debug! { ReprFlags } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub enum IntegerType { /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g. /// `Pointer(true)` means `isize`. @@ -73,7 +73,7 @@ impl IntegerType { /// Represents the repr options provided by the user. #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct ReprOptions { pub int: Option<IntegerType>, pub align: Option<Align>, @@ -412,7 +412,7 @@ impl FromStr for Endian { /// Size of a type in bytes. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct Size { raw: u64, } @@ -636,7 +636,7 @@ impl Step for Size { /// Alignment of a type in bytes (always a power of two). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub struct Align { pow2: u8, } @@ -777,7 +777,7 @@ impl AbiAndPrefAlign { /// Integers, also used for enum discriminants. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] pub enum Integer { I8, I16, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1812cc335a4..e1e4e5fc567 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -20,6 +20,7 @@ pub use crate::format::*; pub use crate::util::parser::ExprPrecedence; +pub use rustc_span::AttrId; pub use GenericArgs::*; pub use UnsafeSource::*; @@ -30,7 +31,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; @@ -2682,22 +2682,6 @@ pub enum AttrStyle { Inner, } -rustc_index::newtype_index! { - #[orderable] - #[debug_format = "AttrId({})"] - pub struct AttrId {} -} - -impl<S: Encoder> Encodable<S> for AttrId { - fn encode(&self, _s: &mut S) {} -} - -impl<D: Decoder> Decodable<D> for AttrId { - default fn decode(_: &mut D) -> AttrId { - panic!("cannot decode `AttrId` with `{}`", std::any::type_name::<D>()); - } -} - /// A list of attributes. pub type AttrVec = ThinVec<Attribute>; diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 4c0c496584e..298c01a4567 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -21,12 +21,12 @@ use crate::AttrVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, Lrc}; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_serialize::{Decodable, Encodable}; +use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; -use std::{cmp, fmt, iter, mem}; +use std::{cmp, fmt, iter}; /// When the main Rust parser encounters a syntax-extension invocation, it /// parses the arguments to the invocation as a token tree. This is a very @@ -81,14 +81,6 @@ impl TokenTree { } } - /// Modify the `TokenTree`'s span in-place. - pub fn set_span(&mut self, span: Span) { - match self { - TokenTree::Token(token, _) => token.span = span, - TokenTree::Delimited(dspan, ..) => *dspan = DelimSpan::from_single(span), - } - } - /// Create a `TokenTree::Token` with alone spacing. pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree { TokenTree::Token(Token::new(kind, span), Spacing::Alone) @@ -158,14 +150,14 @@ impl fmt::Debug for LazyAttrTokenStream { } } -impl<S: Encoder> Encodable<S> for LazyAttrTokenStream { +impl<S: SpanEncoder> Encodable<S> for LazyAttrTokenStream { fn encode(&self, s: &mut S) { // Used by AST json printing. Encodable::encode(&self.to_attr_token_stream(), s); } } -impl<D: Decoder> Decodable<D> for LazyAttrTokenStream { +impl<D: SpanDecoder> Decodable<D> for LazyAttrTokenStream { fn decode(_d: &mut D) -> Self { panic!("Attempted to decode LazyAttrTokenStream"); } @@ -461,19 +453,6 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } - /// Applies the supplied function to each `TokenTree` and its index in `self`, returning a new `TokenStream` - /// - /// It is equivalent to `TokenStream::new(self.trees().cloned().enumerate().map(|(i, tt)| f(i, tt)).collect())`. - pub fn map_enumerated_owned( - mut self, - mut f: impl FnMut(usize, TokenTree) -> TokenTree, - ) -> TokenStream { - let owned = Lrc::make_mut(&mut self.0); // clone if necessary - // rely on vec's in-place optimizations to avoid another allocation - *owned = mem::take(owned).into_iter().enumerate().map(|(i, tree)| f(i, tree)).collect(); - self - } - /// Create a token stream containing a single token with alone spacing. The /// spacing used for the final token in a constructed stream doesn't matter /// because it's never used. In practice we arbitrarily use diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index fd94e7e9341..e7177402db1 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -35,7 +35,7 @@ ast_lowering_bad_return_type_notation_output = ast_lowering_base_expression_double_dot = base expression required after `..` - .label = add a base expression here + .suggestion = add a base expression here ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target @@ -106,7 +106,8 @@ ast_lowering_misplaced_double_dot = .note = only allowed in tuple, tuple struct, and slice patterns ast_lowering_misplaced_impl_trait = - `impl Trait` only allowed in function and inherent method argument and return types, not in {$position} + `impl Trait` is not allowed in {$position} + .note = `impl Trait` is only allowed in arguments and return types of functions and methods ast_lowering_misplaced_relax_trait_bound = `?Trait` bounds are only permitted at the point where a type parameter is declared diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 710690d0d86..2811fe104cd 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -90,6 +90,7 @@ pub enum AssocTyParenthesesSub { #[derive(Diagnostic)] #[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] +#[note] pub struct MisplacedImplTrait<'a> { #[primary_span] pub span: Span, @@ -113,10 +114,10 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_base_expression_double_dot)] +#[diag(ast_lowering_base_expression_double_dot, code = "E0797")] pub struct BaseExpressionDoubleDot { #[primary_span] - #[label] + #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] pub span: Span, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ba858d49acf..69704de105c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -546,20 +546,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); - let guard = arm.guard.as_ref().map(|cond| { - if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind { - hir::Guard::IfLet(self.arena.alloc(hir::Let { - hir_id: self.next_id(), - span: self.lower_span(*span), - pat: self.lower_pat(pat), - ty: None, - init: self.lower_expr(scrutinee), - is_recovered: *is_recovered, - })) - } else { - hir::Guard::If(self.lower_expr(cond)) - } - }); + let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); self.lower_attrs(hir_id, &arm.attrs); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c618953461c..d8de447e5b4 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -12,6 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident}; @@ -182,7 +183,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { - let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + let (ty, body_id) = + self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); hir::ItemKind::Static(ty, *m, body_id) } ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { @@ -191,7 +193,9 @@ impl<'hir> LoweringContext<'_, 'hir> { Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.lower_const_item(ty, span, expr.as_deref()), + |this| { + this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + }, ); hir::ItemKind::Const(ty, generics, body_id) } @@ -448,8 +452,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ty: &Ty, span: Span, body: Option<&Expr>, + impl_trait_position: ImplTraitPosition, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position)); (ty, self.lower_const_body(span, body)) } @@ -572,23 +577,25 @@ impl<'hir> LoweringContext<'_, 'hir> { // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - match parent_hir.node().expect_item().kind { + let generics = match parent_hir.node().expect_item().kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); + &impl_.generics } - hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => { - self.host_param_id = generics - .params - .iter() - .find(|param| { - matches!( - param.kind, - hir::GenericParamKind::Const { is_host_effect: true, .. } - ) - }) - .map(|param| param.def_id); + hir::ItemKind::Trait(_, _, generics, _, _) => generics, + kind => { + span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } - _ => {} + }; + + if self.tcx.features().effects { + self.host_param_id = generics + .params + .iter() + .find(|param| { + matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. }) + }) + .map(|param| param.def_id); } match ctxt { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c7c77bf56b7..dc23b1dce7b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -304,8 +304,6 @@ enum ImplTraitPosition { ClosureParam, PointerParam, FnTraitParam, - TraitParam, - ImplParam, ExternFnReturn, ClosureReturn, PointerReturn, @@ -324,29 +322,27 @@ impl std::fmt::Display for ImplTraitPosition { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name = match self { ImplTraitPosition::Path => "paths", - ImplTraitPosition::Variable => "variable bindings", + ImplTraitPosition::Variable => "the type of variable bindings", ImplTraitPosition::Trait => "traits", ImplTraitPosition::AsyncBlock => "async blocks", ImplTraitPosition::Bound => "bounds", ImplTraitPosition::Generic => "generics", - ImplTraitPosition::ExternFnParam => "`extern fn` params", - ImplTraitPosition::ClosureParam => "closure params", - ImplTraitPosition::PointerParam => "`fn` pointer params", - ImplTraitPosition::FnTraitParam => "`Fn` trait params", - ImplTraitPosition::TraitParam => "trait method params", - ImplTraitPosition::ImplParam => "`impl` method params", + ImplTraitPosition::ExternFnParam => "`extern fn` parameters", + ImplTraitPosition::ClosureParam => "closure parameters", + ImplTraitPosition::PointerParam => "`fn` pointer parameters", + ImplTraitPosition::FnTraitParam => "the parameters of `Fn` trait bounds", ImplTraitPosition::ExternFnReturn => "`extern fn` return types", ImplTraitPosition::ClosureReturn => "closure return types", ImplTraitPosition::PointerReturn => "`fn` pointer return types", - ImplTraitPosition::FnTraitReturn => "`Fn` trait return types", + ImplTraitPosition::FnTraitReturn => "the return type of `Fn` trait bounds", ImplTraitPosition::GenericDefault => "generic parameter defaults", ImplTraitPosition::ConstTy => "const types", ImplTraitPosition::StaticTy => "static types", ImplTraitPosition::AssocTy => "associated types", ImplTraitPosition::FieldTy => "field types", - ImplTraitPosition::Cast => "cast types", + ImplTraitPosition::Cast => "cast expression types", ImplTraitPosition::ImplSelf => "impl headers", - ImplTraitPosition::OffsetOf => "`offset_of!` params", + ImplTraitPosition::OffsetOf => "`offset_of!` parameters", }; write!(f, "{name}") @@ -364,19 +360,6 @@ enum FnDeclKind { Impl, } -impl FnDeclKind { - fn param_impl_trait_allowed(&self) -> bool { - matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait) - } - - fn return_impl_trait_allowed(&self) -> bool { - match self { - FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true, - _ => false, - } - } -} - #[derive(Copy, Clone)] enum AstOwner<'a> { NonOwner, @@ -1434,19 +1417,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { let bounds = this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound { - GenericBound::Trait( - ty, - TraitBoundModifiers { - polarity: BoundPolarity::Positive | BoundPolarity::Negative(_), - constness, - }, - ) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)), - // We can safely ignore constness here, since AST validation - // will take care of invalid modifier combinations. - GenericBound::Trait( - _, - TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }, - ) => None, + // We can safely ignore constness here since AST validation + // takes care of rejecting invalid modifier combinations and + // const trait bounds in trait object types. + GenericBound::Trait(ty, modifiers) => match modifiers.polarity { + BoundPolarity::Positive | BoundPolarity::Negative(_) => { + Some(this.lower_poly_trait_ref( + ty, + itctx, + // Still, don't pass along the constness here; we don't want to + // synthesize any host effect args, it'd only cause problems. + ast::BoundConstness::Never, + )) + } + BoundPolarity::Maybe(_) => None, + }, GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -1840,19 +1825,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { inputs = &inputs[..inputs.len() - 1]; } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { - let itctx = if kind.param_impl_trait_allowed() { - ImplTraitContext::Universal - } else { - ImplTraitContext::Disallowed(match kind { - FnDeclKind::Fn | FnDeclKind::Inherent => { - unreachable!("fn should allow APIT") - } - FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, - FnDeclKind::Closure => ImplTraitPosition::ClosureParam, - FnDeclKind::Pointer => ImplTraitPosition::PointerParam, - FnDeclKind::Trait => ImplTraitPosition::TraitParam, - FnDeclKind::Impl => ImplTraitPosition::ImplParam, - }) + let itctx = match kind { + FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => { + ImplTraitContext::Universal + } + FnDeclKind::ExternFn => { + ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnParam) + } + FnDeclKind::Closure => { + ImplTraitContext::Disallowed(ImplTraitPosition::ClosureParam) + } + FnDeclKind::Pointer => { + ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) + } }; self.lower_ty_direct(¶m.ty, &itctx) })); @@ -1864,26 +1849,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } None => match &decl.output { FnRetTy::Ty(ty) => { - let context = if kind.return_impl_trait_allowed() { - let fn_def_id = self.local_def_id(fn_node_id); - ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + let itctx = match kind { + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::Trait + | FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)), fn_kind: kind, + }, + FnDeclKind::ExternFn => { + ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn) + } + FnDeclKind::Closure => { + ImplTraitContext::Disallowed(ImplTraitPosition::ClosureReturn) + } + FnDeclKind::Pointer => { + ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } - } else { - ImplTraitContext::Disallowed(match kind { - FnDeclKind::Fn - | FnDeclKind::Inherent - | FnDeclKind::Trait - | FnDeclKind::Impl => { - unreachable!("fn should allow return-position impl trait in traits") - } - FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn, - FnDeclKind::Closure => ImplTraitPosition::ClosureReturn, - FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, - }) }; - hir::FnRetTy::Return(self.lower_ty(ty, &context)) + hir::FnRetTy::Return(self.lower_ty(ty, &itctx)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index feea02c679c..a10797626f1 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -188,6 +188,9 @@ ast_passes_module_nonascii = trying to load file for module `{$name}` with non-a ast_passes_negative_bound_not_supported = negative bounds are not supported +ast_passes_negative_bound_with_parenthetical_notation = + parenthetical notation may not be used for negative bounds + ast_passes_nested_impl_trait = nested `impl Trait` is not allowed .outer = outer `impl Trait` .inner = nested `impl Trait` here diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b69d4cccaf0..7f78f687055 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1312,13 +1312,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let GenericBound::Trait(trait_ref, modifiers) = bound && let BoundPolarity::Negative(_) = modifiers.polarity && let Some(segment) = trait_ref.trait_ref.path.segments.last() - && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref() { - for arg in &args.args { - if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx() - .emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); + match segment.args.as_deref() { + Some(ast::GenericArgs::AngleBracketed(args)) => { + for arg in &args.args { + if let ast::AngleBracketedArg::Constraint(constraint) = arg { + self.dcx().emit_err(errors::ConstraintOnNegativeBound { + span: constraint.span, + }); + } + } + } + // The lowered form of parenthesized generic args contains a type binding. + Some(ast::GenericArgs::Parenthesized(args)) => { + self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { + span: args.span, + }); } + None => {} } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 42ada39f515..fcf19ce52ec 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -725,8 +725,8 @@ impl AddToDiagnostic for StableFeature { rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage, { - diag.set_arg("name", self.name); - diag.set_arg("since", self.since); + diag.arg("name", self.name); + diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); } } @@ -764,6 +764,13 @@ pub struct ConstraintOnNegativeBound { } #[derive(Diagnostic)] +#[diag(ast_passes_negative_bound_with_parenthetical_notation)] +pub struct NegativeBoundWithParentheticalNotation { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_invalid_unnamed_field_ty)] pub struct InvalidUnnamedFieldTy { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2b746789a76..737e81eb6ec 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -23,7 +23,7 @@ macro_rules! gate { ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { feature_err(&$visitor.sess.parse_sess, sym::$feature, $span, $explain) - .help($help) + .with_help($help) .emit(); } }}; diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs index 9882f1d23ce..10590074282 100644 --- a/compiler/rustc_ast_passes/src/show_span.rs +++ b/compiler/rustc_ast_passes/src/show_span.rs @@ -38,21 +38,21 @@ struct ShowSpanVisitor<'a> { impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { if let Mode::Expression = self.mode { - self.dcx.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" }); + self.dcx.emit_warn(errors::ShowSpan { span: e.span, msg: "expression" }); } visit::walk_expr(self, e); } fn visit_pat(&mut self, p: &'a ast::Pat) { if let Mode::Pattern = self.mode { - self.dcx.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" }); + self.dcx.emit_warn(errors::ShowSpan { span: p.span, msg: "pattern" }); } visit::walk_pat(self, p); } fn visit_ty(&mut self, t: &'a ast::Ty) { if let Mode::Type = self.mode { - self.dcx.emit_warning(errors::ShowSpan { span: t.span, msg: "type" }); + self.dcx.emit_warn(errors::ShowSpan { span: t.span, msg: "type" }); } visit::walk_ty(self, t); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 77678dcaba9..b3f601b7595 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -621,7 +621,7 @@ pub fn eval_condition( } }; let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span }); + dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); return false; }; diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index fd2b0866867..89606b81a99 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -54,13 +54,12 @@ pub(crate) struct UnknownMetaItem<'a> { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnknownMetaItem<'_> { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); - let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item); - diag.set_span(self.span); - diag.code(error_code!(E0541)); - diag.set_arg("item", self.item); - diag.set_arg("expected", expected.join(", ")); - diag.span_label(self.span, fluent::attr_label); - diag + DiagnosticBuilder::new(dcx, level, fluent::attr_unknown_meta_item) + .with_span(self.span) + .with_code(error_code!(E0541)) + .with_arg("item", self.item) + .with_arg("expected", expected.join(", ")) + .with_span_label(self.span, fluent::attr_label) } } @@ -215,7 +214,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for UnsupportedLiteral { } }, ); - diag.set_span(self.span); + diag.span(self.span); diag.code(error_code!(E0565)); if self.is_bytestr { diag.span_suggestion( diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 900b7891019..351976cdaea 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{struct_span_err, DiagCtxt, DiagnosticBuilder}; +use rustc_errors::{struct_span_code_err, DiagCtxt, DiagnosticBuilder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -31,17 +31,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, borrow_desc: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0503, "cannot use {} because it was mutably borrowed", desc, - ); - - err.span_label(borrow_span, format!("{borrow_desc} is borrowed here")); - err.span_label(span, format!("use of borrowed {borrow_desc}")); - err + ) + .with_span_label(borrow_span, format!("{borrow_desc} is borrowed here")) + .with_span_label(span, format!("use of borrowed {borrow_desc}")) } pub(crate) fn cannot_mutably_borrow_multiply( @@ -54,7 +52,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'tcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), new_loan_span, E0499, @@ -100,7 +98,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_loan_span: Span, old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), new_loan_span, E0524, @@ -133,7 +131,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option<Span>, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), new_loan_span, E0500, @@ -165,7 +163,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { previous_end_span: Option<Span>, second_borrow_desc: &str, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), new_loan_span, E0501, @@ -198,7 +196,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_load_end_span: Option<Span>, ) -> DiagnosticBuilder<'cx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0502, @@ -238,17 +236,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, desc: &str, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0506, "cannot assign to {} because it is 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 + ) + .with_span_label(borrow_span, format!("{desc} is borrowed here")) + .with_span_label(span, format!("{desc} is assigned to here but it was already borrowed")) } pub(crate) fn cannot_reassign_immutable( @@ -258,11 +254,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { is_arg: bool, ) -> DiagnosticBuilder<'cx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; - struct_span_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) + struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) } pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> { - struct_span_err!(self.dcx(), span, E0594, "cannot assign to {}", desc) + struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc) } pub(crate) fn cannot_move_out_of( @@ -270,7 +266,13 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, move_from_desc: &str, ) -> DiagnosticBuilder<'cx> { - struct_span_err!(self.dcx(), move_from_span, E0507, "cannot move out of {}", move_from_desc) + struct_span_code_err!( + self.dcx(), + move_from_span, + E0507, + "cannot move out of {}", + move_from_desc + ) } /// Signal an error due to an attempt to move out of the interior @@ -287,16 +289,15 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { (&ty::Slice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), }; - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), move_from_span, E0508, "cannot move out of type `{}`, a non-copy {}", ty, type_name, - ); - err.span_label(move_from_span, "cannot move out of here"); - err + ) + .with_span_label(move_from_span, "cannot move out of here") } pub(crate) fn cannot_move_out_of_interior_of_drop( @@ -304,15 +305,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, container_ty: Ty<'_>, ) -> DiagnosticBuilder<'cx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), move_from_span, E0509, "cannot move out of type `{}`, which implements the `Drop` trait", container_ty, - ); - err.span_label(move_from_span, "cannot move out of here"); - err + ) + .with_span_label(move_from_span, "cannot move out of here") } pub(crate) fn cannot_act_on_moved_value( @@ -324,7 +324,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { ) -> DiagnosticBuilder<'tcx> { let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); - struct_span_err!( + struct_span_code_err!( self.dcx(), use_span, E0382, @@ -341,7 +341,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { path: &str, reason: &str, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!(self.dcx(), span, E0596, "cannot borrow {} as mutable{}", path, reason) + struct_span_code_err!( + self.dcx(), + span, + E0596, + "cannot borrow {} as mutable{}", + path, + reason + ) } pub(crate) fn cannot_mutate_in_immutable_section( @@ -352,7 +359,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { immutable_section: &str, action: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), mutate_span, E0510, @@ -360,10 +367,9 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { action, 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 + ) + .with_span_label(mutate_span, format!("cannot {action}")) + .with_span_label(immutable_span, format!("value is immutable in {immutable_section}")) } pub(crate) fn cannot_borrow_across_coroutine_yield( @@ -372,21 +378,20 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { yield_span: Span, ) -> DiagnosticBuilder<'tcx> { let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0626, "borrow may still be in use when {coroutine_kind:#} yields", - ); - err.span_label(yield_span, "possible yield occurs here"); - err + ) + .with_span_label(yield_span, "possible yield occurs here") } pub(crate) fn cannot_borrow_across_destructor( &self, borrow_span: Span, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!( + struct_span_code_err!( self.dcx(), borrow_span, E0713, @@ -399,7 +404,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, path: &str, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) + struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) } pub(crate) fn cannot_return_reference_to_local( @@ -409,7 +414,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { reference_desc: &str, path_desc: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0515, @@ -417,14 +422,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { RETURN = return_kind, REFERENCE = reference_desc, LOCAL = path_desc, - ); - - err.span_label( + ) + .with_span_label( span, format!("{return_kind}s a {reference_desc} data owned by the current function"), - ); - - err + ) } pub(crate) fn cannot_capture_in_long_lived_closure( @@ -435,23 +437,22 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { capture_span: Span, scope: &str, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), closure_span, E0373, "{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!("{borrowed_path} is borrowed here")) - .span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")); - err + ) + .with_span_label(capture_span, format!("{borrowed_path} is borrowed here")) + .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")) } pub(crate) fn thread_local_value_does_not_live_long_enough( &self, span: Span, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0712, @@ -463,7 +464,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, span: Span, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) + struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) } } @@ -472,7 +473,7 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>( escape_span: Span, escapes_from: &str, ) -> DiagnosticBuilder<'tcx> { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), escape_span, E0521, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index d824260f47c..b4a73574aa2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,7 +1,9 @@ +// ignore-tidy-filelength + use either::Either; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -550,8 +552,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; let used = desired_action.as_general_verb_in_past_tense(); - let mut err = - struct_span_err!(self.dcx(), span, E0381, "{used} binding {desc}{isnt_initialized}"); + let mut err = struct_span_code_err!( + self.dcx(), + span, + E0381, + "{used} binding {desc}{isnt_initialized}" + ); use_spans.var_path_only_subdiag(&mut err, desired_action); if let InitializationRequiringAction::PartialAssignment @@ -2218,15 +2224,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span, borrow_span ); - let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span); - - err.span_label( - borrow_span, - "thread-local variables cannot be borrowed beyond the end of the function", - ); - err.span_label(drop_span, "end of enclosing function is here"); - - err + self.thread_local_value_does_not_live_long_enough(borrow_span) + .with_span_label( + borrow_span, + "thread-local variables cannot be borrowed beyond the end of the function", + ) + .with_span_label(drop_span, "end of enclosing function is here") } #[instrument(level = "debug", skip(self))] @@ -3590,7 +3593,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { )); } else if let Some(guard) = &arm.guard { self.errors.push(( - arm.pat.span.to(guard.body().span), + arm.pat.span.to(guard.span), format!( "if this pattern and condition are matched, {} is not \ initialized", diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index f1e712d814a..6606be2f9f4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> { let mut failed = false; let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| { - if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) { + if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) { let default = tcx.object_lifetime_default(param.def_id); let re_static = tcx.lifetimes.re_static; @@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> { has_dyn = true; - Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into() + Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into() } else { arg } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index f3b21d22c1a..fb3525e8998 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -329,15 +329,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[local]; if decl.is_ref_for_guard() { - let mut err = self.cannot_move_out_of( - span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), - ); - err.note( - "variables bound in patterns cannot be moved from \ - until after the end of the pattern guard", - ); - return err; + return self + .cannot_move_out_of( + span, + &format!("`{}` in pattern guard", self.local_names[local].unwrap()), + ) + .with_note( + "variables bound in patterns cannot be moved from \ + until after the end of the pattern guard", + ); } else if decl.is_ref_to_static() { return self.report_cannot_move_from_static(move_place, span); } @@ -381,15 +381,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { closure_kind_ty, closure_kind, place_description, ); - let mut diag = self.cannot_move_out_of(span, &place_description); - - diag.span_label(upvar_span, "captured outer variable"); - diag.span_label( - self.infcx.tcx.def_span(def_id), - format!("captured by this `{closure_kind}` closure"), - ); - - diag + self.cannot_move_out_of(span, &place_description) + .with_span_label(upvar_span, "captured outer variable") + .with_span_label( + self.infcx.tcx.def_span(def_id), + format!("captured by this `{closure_kind}` closure"), + ) } _ => { let source = self.borrowed_content_source(deref_base); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b3450b09cdf..8c8ca1ead40 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use crate::borrowck_errors; use crate::session_diagnostics::{ @@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> { #[track_caller] pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) { let val = val.into(); - self.1.sess.dcx().span_delayed_bug(DUMMY_SP, format!("{val:?}")); + self.1.sess.dcx().delayed_bug(format!("{val:?}")); self.0.push(val); } pub fn is_empty(&self) -> bool { @@ -348,7 +348,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); - let mut diag = unexpected_hidden_region_diagnostic( + let diag = unexpected_hidden_region_diagnostic( self.infcx.tcx, span, named_ty, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 093017ecba2..462b5c8da42 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -421,7 +421,7 @@ fn check_opaque_type_parameter_valid( return Err(tcx .dcx() .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, format!("{descr} used multiple times")) + .with_span_note(spans, format!("{descr} used multiple times")) .emit()); } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 5bd7cc9514c..61b6bef3b87 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -94,31 +94,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - debug!( - "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}", - body.yield_ty(), - universal_regions.yield_ty - ); - - // We will not have a universal_regions.yield_ty if we yield (by accident) - // outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug - // because we don't want to panic in an assert here if we've already got errors. - if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() { - self.tcx().dcx().span_delayed_bug( - body.span, - format!( - "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})", - body.yield_ty(), - universal_regions.yield_ty, - ), + if let Some(mir_yield_ty) = body.yield_ty() { + let yield_span = body.local_decls[RETURN_PLACE].source_info.span; + self.equate_normalized_input_or_output( + universal_regions.yield_ty.unwrap(), + mir_yield_ty, + yield_span, ); } - if let (Some(mir_yield_ty), Some(ur_yield_ty)) = - (body.yield_ty(), universal_regions.yield_ty) - { + if let Some(mir_resume_ty) = body.resume_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; - self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span); + self.equate_normalized_input_or_output( + universal_regions.resume_ty.unwrap(), + mir_resume_ty, + yield_span, + ); } // Return types are a bit more complex. They may contain opaque `impl Trait` types. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index dc4695fd2b0..e137bc1be0a 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -183,6 +183,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> { match ty_context { TyContext::ReturnTy(SourceInfo { span, .. }) | TyContext::YieldTy(SourceInfo { span, .. }) + | TyContext::ResumeTy(SourceInfo { span, .. }) | TyContext::UserTy(span) | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => { span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 80575e30a8d..9c0f53ddb86 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1450,13 +1450,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } - TerminatorKind::Yield { value, .. } => { + TerminatorKind::Yield { value, resume_arg, .. } => { self.check_operand(value, term_location); - let value_ty = value.ty(body, tcx); match body.yield_ty() { None => span_mirbug!(self, term, "yield in non-coroutine"), Some(ty) => { + let value_ty = value.ty(body, tcx); if let Err(terr) = self.sub_types( value_ty, ty, @@ -1474,6 +1474,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + + match body.resume_ty() { + None => span_mirbug!(self, term, "yield in non-coroutine"), + Some(ty) => { + let resume_ty = resume_arg.ty(body, tcx); + if let Err(terr) = self.sub_types( + ty, + resume_ty.ty, + term_location.to_locations(), + ConstraintCategory::Yield, + ) { + span_mirbug!( + self, + term, + "type of resume place is {:?}, but the resume type is {:?}: {:?}", + resume_ty, + ty, + terr + ); + } + } + } } } } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index a02304a2f8b..addb41ff5fc 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -76,6 +76,8 @@ pub struct UniversalRegions<'tcx> { pub unnormalized_input_tys: &'tcx [Ty<'tcx>], pub yield_ty: Option<Ty<'tcx>>, + + pub resume_ty: Option<Ty<'tcx>>, } /// The "defining type" for this MIR. The key feature of the "defining @@ -525,9 +527,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!("build: extern regions = {}..{}", first_extern_index, first_local_index); debug!("build: local regions = {}..{}", first_local_index, num_universals); - let yield_ty = match defining_ty { - DefiningTy::Coroutine(_, args) => Some(args.as_coroutine().yield_ty()), - _ => None, + let (resume_ty, yield_ty) = match defining_ty { + DefiningTy::Coroutine(_, args) => { + let tys = args.as_coroutine(); + (Some(tys.resume_ty()), Some(tys.yield_ty())) + } + _ => (None, None), }; UniversalRegions { @@ -541,6 +546,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { unnormalized_output_ty: *unnormalized_output_ty, unnormalized_input_tys, yield_ty, + resume_ty, } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index b5801c1b0f1..0b2e63b403b 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -458,7 +458,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl match expr_to_spanned_string(ecx, template_expr, msg) { Ok(template_part) => template_part, Err(err) => { - if let Some((mut err, _)) = err { + if let Some((err, _)) = err { err.emit(); } return None; @@ -693,13 +693,14 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl 0 => {} 1 => { let (sp, msg) = unused_operands.into_iter().next().unwrap(); - let mut err = ecx.dcx().struct_span_err(sp, msg); - err.span_label(sp, msg); - err.help(format!( - "if this argument is intentionally unused, \ - consider using it in an asm comment: `\"/*{help_str} */\"`" - )); - err.emit(); + ecx.dcx() + .struct_span_err(sp, msg) + .with_span_label(sp, msg) + .with_help(format!( + "if this argument is intentionally unused, \ + consider using it in an asm comment: `\"/*{help_str} */\"`" + )) + .emit(); } _ => { let mut err = ecx.dcx().struct_span_err( @@ -747,7 +748,7 @@ pub(super) fn expand_asm<'cx>( }; MacEager::expr(expr) } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } @@ -779,7 +780,7 @@ pub(super) fn expand_global_asm<'cx>( DummyResult::any(sp) } } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 8fa3fe5b3e6..501d557f3ab 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -22,7 +22,7 @@ pub fn expand_assert<'cx>( ) -> Box<dyn MacResult + 'cx> { let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { Ok(assert) => assert, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(span); } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 48be680b619..1bc2512a7b0 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -28,7 +28,7 @@ pub fn expand_cfg( ); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index ca26b7ed827..cfa94b0e780 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -200,7 +200,7 @@ impl CfgEval<'_, '_> { parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, - Err(mut err) => { + Err(err) => { err.emit(); return Some(annotatable); } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 2803ddefba2..d956c096d24 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -18,7 +18,7 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) let start_span = parser.token.span; let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { Ok(ai) => ai, - Err(mut err) => { + Err(err) => { err.emit(); continue; } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index e07eb2e490b..d6dfd0efaf9 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -454,7 +454,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMe reason = "cannot translate user-provided messages" )] let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string()); - diag.set_span(self.span); + diag.span(self.span); diag } } @@ -618,7 +618,7 @@ impl AddToDiagnostic for FormatUnusedArg { rustc_errors::SubdiagnosticMessage, ) -> rustc_errors::SubdiagnosticMessage, { - diag.set_arg("named", self.named); + diag.arg("named", self.named); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); diag.span_label(self.span, msg); } @@ -803,24 +803,23 @@ pub(crate) struct AsmClobberNoReg { impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { - let mut diag = DiagnosticBuilder::new( - dcx, - level, - crate::fluent_generated::builtin_macros_asm_clobber_no_reg, - ); - diag.set_span(self.spans.clone()); // eager translation as `span_labels` takes `AsRef<str>` let lbl1 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_abi, [].into_iter(), ); - diag.span_labels(self.clobbers, &lbl1); let lbl2 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_outputs, [].into_iter(), ); - diag.span_labels(self.spans, &lbl2); - diag + DiagnosticBuilder::new( + dcx, + level, + crate::fluent_generated::builtin_macros_asm_clobber_no_reg, + ) + .with_span(self.spans.clone()) + .with_span_labels(self.clobbers, &lbl1) + .with_span_labels(self.spans, &lbl2) } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a668db438eb..93381b69fdc 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -99,7 +99,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< } match p.expect(&token::Comma) { - Err(mut err) => { + Err(err) => { match token::TokenKind::Comma.similar_tokens() { Some(tks) if tks.contains(&p.token.kind) => { // If a similar token is found, then it may be a typo. We @@ -630,8 +630,7 @@ fn report_missing_placeholders( .collect::<Vec<_>>(); if !placeholders.is_empty() { - if let Some(mut new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) - { + if let Some(new_diag) = report_redundant_format_arguments(ecx, args, used, placeholders) { diag.cancel(); new_diag.emit(); return; @@ -976,7 +975,7 @@ fn expand_format_args_impl<'cx>( MacEager::expr(DummyResult::raw_expr(sp, true)) } } - Err(mut err) => { + Err(err) => { err.emit(); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 4fddaa8ab6c..477e5c8bec5 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -194,7 +194,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { self.dcx .struct_span_err(attr.span, msg) - .span_label(prev_attr.span, "previous attribute here") + .with_span_label(prev_attr.span, "previous attribute here") .emit(); return; diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 30f80bb87dd..e7d7b4a7012 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -109,7 +109,7 @@ pub fn expand_include<'cx>( // The file will be added to the code map by the parser let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } @@ -146,7 +146,7 @@ pub fn expand_include<'cx>( let mut ret = SmallVec::new(); loop { match self.p.parse_item(ForceCollect::No) { - Err(mut err) => { + Err(err) => { err.emit(); break; } @@ -155,7 +155,7 @@ pub fn expand_include<'cx>( if self.p.token != token::Eof { let token = pprust::token_to_string(&self.p.token); let msg = format!("expected item, found `{token}`"); - self.p.dcx().struct_span_err(self.p.token.span, msg).emit(); + self.p.dcx().span_err(self.p.token.span, msg); } break; @@ -181,7 +181,7 @@ pub fn expand_include_str( }; let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } @@ -215,7 +215,7 @@ pub fn expand_include_bytes( }; let file = match resolve_path(&cx.sess.parse_sess, file.as_str(), sp) { Ok(f) => f, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(sp); } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 2af46f175d7..4d44e340ae1 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -394,11 +394,11 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) let level = match item.map(|i| &i.kind) { // These were a warning before #92959 and need to continue being that to avoid breaking // stable user code (#94508). - Some(ast::ItemKind::MacCall(_)) => Level::Warning(None), - _ => Level::Error { lint: false }, + Some(ast::ItemKind::MacCall(_)) => Level::Warning, + _ => Level::Error, }; let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg); - err.set_span(attr_sp); + err.span(attr_sp); if let Some(item) = item { err.span_label( item.span, @@ -409,8 +409,8 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) ), ); } - err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") - .span_suggestion(attr_sp, + err.with_span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions") + .with_span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect) @@ -480,7 +480,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { "argument must be of the form: \ `expected = \"error message\"`", ) - .note( + .with_note( "errors in this attribute were erroneously \ allowed and will become a hard error in a \ future release", diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs index 72b85af1486..564797012ae 100644 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs @@ -12,7 +12,7 @@ pub fn expand_type_ascribe( ) -> Box<dyn base::MacResult + 'static> { let (expr, ty) = match parse_ascribe(cx, tts) { Ok(parsed) => parsed, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(span); } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index a1cdf31c68a..2a7b1107ffc 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -111,6 +111,9 @@ fn start<T: Termination + 'static>( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; unsafe fn zeroed<T>() -> T { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 6230ca15d6e..d1b21d0a0b6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -68,15 +68,7 @@ impl DebugContext { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site (when the macro is // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - let span = if tcx.should_collapse_debuginfo(span) { - span - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - rustc_span::hygiene::walk_chain(span, function_span.ctxt()) - }; - + let span = tcx.collapsed_debuginfo(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { let line_pos = file.lines()[line]; diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index a8d8fb189e2..50d9f287e74 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -321,9 +321,10 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.dcx().struct_err(format!("Can't load static lib {}", name)); - err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - err.emit(); + sess.dcx() + .struct_err(format!("Can't load static lib {}", name)) + .note("rustc_codegen_cranelift can only load dylibs in JIT mode.") + .emit(); } Linkage::Dynamic => { dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 40a1ad22c0e..9827e299f2a 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -98,6 +98,9 @@ fn start<T: Termination + 'static>( } static mut NUM: u8 = 6 * 7; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index ddd67a994c9..78e8e32b972 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -634,6 +634,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { } InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Err => unreachable!(), } @@ -704,7 +705,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") }, - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::S390x( + S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr + ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::Err => unreachable!(), } diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 1b1ed0b411c..e9283b19894 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -119,12 +119,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl fluent::codegen_gcc_target_feature_disable_or_enable ); if let Some(span) = self.span { - diag.set_span(span); + diag.span(span); }; if let Some(missing_features) = self.missing_features { diag.subdiagnostic(missing_features); } - diag.set_arg("features", self.features.join(", ")); + diag.arg("features", self.features.join(", ")); diag } } diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index df917d527ce..4babe5bfb81 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -52,7 +52,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri Some(c @ ('+' | '-')) => c, Some(_) => { if diagnostics { - sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s }); + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); } return None; } @@ -79,7 +79,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri else { UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } }; - sess.dcx().emit_warning(unknown_feature); + sess.dcx().emit_warn(unknown_feature); } if diagnostics { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f69f850c1d4..03f8f43ff16 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -191,7 +191,7 @@ impl CodegenBackend for GccCodegenBackend { #[cfg(feature="master")] gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); if sess.lto() == Lto::Thin { - sess.dcx().emit_warning(LTONotSupported {}); + sess.dcx().emit_warn(LTONotSupported {}); } #[cfg(not(feature="master"))] diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 97dc401251c..0718bebb31b 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -6,7 +6,7 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use rustc_codegen_ssa::mir::operand::OperandValue; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::MemFlags; @@ -253,7 +253,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { bx.lifetime_end(llscratch, scratch_size); } } else { - OperandValue::Immediate(val).store(bx, dst); + OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst); } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 58b3aa438c5..ca376029735 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -134,7 +134,8 @@ fn create_wrapper_function( llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { - let uwtable = attributes::uwtable_attr(llcx); + let uwtable = + attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1323261ae92..a413466093b 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -690,6 +690,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w", InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", @@ -867,7 +868,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), - InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::S390x( + S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr, + ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index b3fa7b7cd44..0a7ea599431 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -95,11 +95,12 @@ pub fn sanitize_attrs<'ll>( /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. #[inline] -pub fn uwtable_attr(llcx: &llvm::Context) -> &Attribute { +pub fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>) -> &Attribute { // NOTE: We should determine if we even need async unwind tables, as they // take have more overhead and if we can use sync unwind tables we // probably should. - llvm::CreateUWTableAttr(llcx, true) + let async_unwind = !use_sync_unwind.unwrap_or(false); + llvm::CreateUWTableAttr(llcx, async_unwind) } pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { @@ -333,7 +334,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // You can also find more info on why Windows always requires uwtables here: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if cx.sess().must_emit_unwind_tables() { - to_add.push(uwtable_attr(cx.llcx)); + to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); } if cx.sess().opts.unstable_opts.profile_sample_use.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c607533a08e..a912ef9e755 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -245,12 +245,12 @@ pub fn target_machine_factory( match sess.opts.debuginfo_compression { rustc_session::config::DebugInfoCompression::Zlib => { if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } { - sess.dcx().emit_warning(UnknownCompression { algorithm: "zlib" }); + sess.dcx().emit_warn(UnknownCompression { algorithm: "zlib" }); } } rustc_session::config::DebugInfoCompression::Zstd => { if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } { - sess.dcx().emit_warning(UnknownCompression { algorithm: "zstd" }); + sess.dcx().emit_warn(UnknownCompression { algorithm: "zstd" }); } } rustc_session::config::DebugInfoCompression::None => {} @@ -416,8 +416,8 @@ fn report_inline_asm( cookie = 0; } let level = match level { - llvm::DiagnosticLevel::Error => Level::Error { lint: false }, - llvm::DiagnosticLevel::Warning => Level::Warning(None), + llvm::DiagnosticLevel::Error => Level::Error, + llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); @@ -457,7 +457,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); - dcx.emit_warning(FromLlvmDiag { message }); + dcx.emit_warn(FromLlvmDiag { message }); } llvm::diagnostic::Unsupported(diagnostic_ref) => { let message = llvm::build_string(|s| { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4e5fe290bb1..7ed27b33dce 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -558,10 +558,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { OperandValue::Immediate(self.to_immediate(llval, place.layout)) } else if let abi::Abi::ScalarPair(a, b) = place.layout.abi { let b_offset = a.size(self).align_to(b.align(self).abi); - let pair_ty = place.layout.llvm_type(self); let mut load = |i, scalar: abi::Scalar, layout, align, offset| { - let llptr = self.struct_gep(pair_ty, place.llval, i as u64); + let llptr = if i == 0 { + place.llval + } else { + self.inbounds_gep( + self.type_i8(), + place.llval, + &[self.const_usize(b_offset.bytes())], + ) + }; let llty = place.layout.scalar_pair_element_llvm_type(self, i, false); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar, layout, offset); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 8db97d577ca..697ce602298 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -105,10 +105,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_ let (message, _) = diag.messages().first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); - let mut diag = - DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config); - diag.set_arg("error", message); - diag + DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config) + .with_arg("error", message) } } @@ -130,12 +128,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl fluent::codegen_llvm_target_feature_disable_or_enable, ); if let Some(span) = self.span { - diag.set_span(span); + diag.span(span); }; if let Some(missing_features) = self.missing_features { diag.subdiagnostic(missing_features); } - diag.set_arg("features", self.features.join(", ")); + diag.arg("features", self.features.join(", ")); diag } } @@ -204,10 +202,10 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> { PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, }; - let mut diag = self.0.into_diagnostic(dcx, level); - diag.set_primary_message(msg_with_llvm_err); - diag.set_arg("llvm_err", self.1); - diag + self.0 + .into_diagnostic(dcx, level) + .with_primary_message(msg_with_llvm_err) + .with_arg("llvm_err", self.1) } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 6043a8ebded..a0f9d5cf7cd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -179,7 +179,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { unsafe { llvm::LLVMSetAlignment(load, align); } - self.to_immediate(load, self.layout_of(tp_ty)) + if !result.layout.is_zst() { + self.store(load, result.llval, result.align); + } + return; } sym::volatile_store => { let dst = args[0].deref(self.cx()); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 03b79a143cc..99f4488ac0f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -529,7 +529,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str Some(c @ ('+' | '-')) => c, Some(_) => { if diagnostics { - sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s }); + sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s }); } return None; } @@ -557,12 +557,12 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str } else { UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } }; - sess.dcx().emit_warning(unknown_feature); + sess.dcx().emit_warn(unknown_feature); } else if feature_state .is_some_and(|(_name, feature_gate)| !feature_gate.is_stable()) { // An unstable feature. Warn about using it. - sess.dcx().emit_warning(UnstableCTargetFeature { feature }); + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); } } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 57b46382c96..e88f4217c9d 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -26,16 +26,7 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - Abi::ScalarPair(..) => { - return cx.type_struct( - &[ - layout.scalar_pair_element_llvm_type(cx, 0, false), - layout.scalar_pair_element_llvm_type(cx, 1, false), - ], - false, - ); - } - Abi::Uninhabited | Abi::Aggregate { .. } => {} + Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {} } let name = match layout.ty.kind() { @@ -275,11 +266,25 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - if let Abi::Scalar(scalar) = self.abi { - if scalar.is_bool() { - return cx.type_i1(); + match self.abi { + Abi::Scalar(scalar) => { + if scalar.is_bool() { + return cx.type_i1(); + } } - } + Abi::ScalarPair(..) => { + // An immediate pair always contains just the two elements, without any padding + // filler, as it should never be stored to memory. + return cx.type_struct( + &[ + self.scalar_pair_element_llvm_type(cx, 0, true), + self.scalar_pair_element_llvm_type(cx, 1, true), + ], + false, + ); + } + _ => {} + }; self.llvm_type(cx) } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4ff497f2fdd..70fda982b01 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1016,7 +1016,7 @@ fn link_natively<'a>( if !prog.status.success() { let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); - sess.dcx().emit_warning(errors::ProcessingDymutilFailed { + sess.dcx().emit_warn(errors::ProcessingDymutilFailed { status: prog.status, output: escape_string(&output), }); @@ -1091,7 +1091,7 @@ fn strip_symbols_with_external_utility<'a>( if !prog.status.success() { let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); - sess.dcx().emit_warning(errors::StrippingDebugInfoFailed { + sess.dcx().emit_warn(errors::StrippingDebugInfoFailed { util, status: prog.status, output: escape_string(&output), @@ -1186,15 +1186,22 @@ mod win { } } -fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { - // On macOS the runtimes are distributed as dylibs which should be linked to - // both executables and dynamic shared objects. Everywhere else the runtimes - // are currently distributed as static libraries which should be linked to - // executables only. +fn add_sanitizer_libraries( + sess: &Session, + flavor: LinkerFlavor, + crate_type: CrateType, + linker: &mut dyn Linker, +) { + // On macOS and Windows using MSVC the runtimes are distributed as dylibs + // which should be linked to both executables and dynamic libraries. + // Everywhere else the runtimes are currently distributed as static + // libraries which should be linked to executables only. let needs_runtime = !sess.target.is_like_android && match crate_type { CrateType::Executable => true, - CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx, + CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => { + sess.target.is_like_osx || sess.target.is_like_msvc + } CrateType::Rlib | CrateType::Staticlib => false, }; @@ -1204,26 +1211,31 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d let sanitizer = sess.opts.unstable_opts.sanitizer; if sanitizer.contains(SanitizerSet::ADDRESS) { - link_sanitizer_runtime(sess, linker, "asan"); + link_sanitizer_runtime(sess, flavor, linker, "asan"); } if sanitizer.contains(SanitizerSet::LEAK) { - link_sanitizer_runtime(sess, linker, "lsan"); + link_sanitizer_runtime(sess, flavor, linker, "lsan"); } if sanitizer.contains(SanitizerSet::MEMORY) { - link_sanitizer_runtime(sess, linker, "msan"); + link_sanitizer_runtime(sess, flavor, linker, "msan"); } if sanitizer.contains(SanitizerSet::THREAD) { - link_sanitizer_runtime(sess, linker, "tsan"); + link_sanitizer_runtime(sess, flavor, linker, "tsan"); } if sanitizer.contains(SanitizerSet::HWADDRESS) { - link_sanitizer_runtime(sess, linker, "hwasan"); + link_sanitizer_runtime(sess, flavor, linker, "hwasan"); } if sanitizer.contains(SanitizerSet::SAFESTACK) { - link_sanitizer_runtime(sess, linker, "safestack"); + link_sanitizer_runtime(sess, flavor, linker, "safestack"); } } -fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { +fn link_sanitizer_runtime( + sess: &Session, + flavor: LinkerFlavor, + linker: &mut dyn Linker, + name: &str, +) { fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf { let session_tlib = filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple()); @@ -1254,6 +1266,10 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib(&filename, false, true); + } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" { + // MSVC provides the `/INFERASANLIBS` argument to automatically find the + // compatible ASAN library. + linker.arg("/INFERASANLIBS"); } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); @@ -2076,7 +2092,7 @@ fn linker_with_args<'a>( ); // Sanitizer libraries. - add_sanitizer_libraries(sess, crate_type, cmd); + add_sanitizer_libraries(sess, flavor, crate_type, cmd); // Object code from the current crate. // Take careful note of the ordering of the arguments we pass to the linker @@ -2390,7 +2406,7 @@ fn collect_natvis_visualizers( visualizer_paths.push(visualizer_out_file); } Err(error) => { - sess.dcx().emit_warning(errors::UnableToWriteDebuggerVisualizer { + sess.dcx().emit_warn(errors::UnableToWriteDebuggerVisualizer { path: visualizer_out_file, error, }); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 695aeb0b2fb..90f5027c264 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -446,11 +446,11 @@ impl<'a> Linker for GccLinker<'a> { // FIXME(81490): ld64 doesn't support these flags but macOS 11 // has -needed-l{} / -needed_library {} // but we have no way to detect that here. - self.sess.dcx().emit_warning(errors::Ld64UnimplementedModifier); + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } else if self.is_gnu && !self.sess.target.is_like_windows { self.linker_arg("--no-as-needed"); } else { - self.sess.dcx().emit_warning(errors::LinkerUnsupportedModifier); + self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); } } self.hint_dynamic(); @@ -504,7 +504,7 @@ impl<'a> Linker for GccLinker<'a> { // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework // flag but we have no way to detect that here. // self.cmd.arg("-needed_framework").arg(framework); - self.sess.dcx().emit_warning(errors::Ld64UnimplementedModifier); + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } self.cmd.arg("-framework").arg(framework); } @@ -950,7 +950,7 @@ impl<'a> Linker for MsvcLinker<'a> { } } Err(error) => { - self.sess.dcx().emit_warning(errors::NoNatvisDirectory { error }); + self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error }); } } } @@ -1501,7 +1501,7 @@ impl<'a> Linker for L4Bender<'a> { fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { // ToDo, not implemented, copy from GCC - self.sess.dcx().emit_warning(errors::L4BenderExportingSymbolsUnimplemented); + self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); return; } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 54b523cb6bd..94841ab7b33 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -3,7 +3,7 @@ use crate::base::allocator_kind_for_codegen; use std::collections::hash_map::Entry::*; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -393,10 +393,10 @@ fn exported_symbols_provider_local( fn upstream_monomorphizations_provider( tcx: TyCtxt<'_>, (): (), -) -> DefIdMap<FxHashMap<GenericArgsRef<'_>, CrateNum>> { +) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> { let cnums = tcx.crates(()); - let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default(); + let mut instances: DefIdMap<UnordMap<_, _>> = Default::default(); let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); @@ -445,7 +445,7 @@ fn upstream_monomorphizations_provider( fn upstream_monomorphizations_for_provider( tcx: TyCtxt<'_>, def_id: DefId, -) -> Option<&FxHashMap<GenericArgsRef<'_>, CrateNum>> { +) -> Option<&UnordMap<GenericArgsRef<'_>, CrateNum>> { debug_assert!(!def_id.is_local()); tcx.upstream_monomorphizations(()).get(&def_id) } @@ -656,7 +656,7 @@ fn maybe_emutls_symbol_name<'tcx>( } } -fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> { +fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<String> { // Build up a map from DefId to a `NativeLib` structure, where // `NativeLib` internally contains information about // `#[link(wasm_import_module = "...")]` for example. @@ -665,9 +665,9 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S let def_id_to_native_lib = native_libs .iter() .filter_map(|lib| lib.foreign_module.map(|id| (id, lib))) - .collect::<FxHashMap<_, _>>(); + .collect::<DefIdMap<_>>(); - let mut ret = FxHashMap::default(); + let mut ret = DefIdMap::default(); for (def_id, lib) in tcx.foreign_modules(cnum).iter() { let module = def_id_to_native_lib.get(def_id).and_then(|s| s.wasm_import_module()); let Some(module) = module else { continue }; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5a8db7bbf2d..8e835039970 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -573,11 +573,11 @@ fn produce_final_output_artifacts( if crate_output.outputs.contains_key(&output_type) { // 2) Multiple codegen units, with `--emit foo=some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warning(errors::IgnoringEmitPath { extension }); + sess.dcx().emit_warn(errors::IgnoringEmitPath { extension }); } else if crate_output.single_output_file.is_some() { // 3) Multiple codegen units, with `-o some_name`. We have // no good solution for this case, so warn the user. - sess.dcx().emit_warning(errors::IgnoringOutput { extension }); + sess.dcx().emit_warn(errors::IgnoringOutput { extension }); } else { // 4) Multiple codegen units, but no explicit name. We // just leave the `foo.0.x` files in place. @@ -1847,20 +1847,15 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); } Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { - let err_level = match level { - Level::Error { lint: false } => rustc_errors::Level::Error { lint: false }, - Level::Warning(_) => rustc_errors::Level::Warning(None), - Level::Note => rustc_errors::Level::Note, - _ => bug!("Invalid inline asm diagnostic level"), - }; + assert!(matches!(level, Level::Error | Level::Warning | Level::Note)); let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); - let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), err_level, msg); + let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, msg); // If the cookie is 0 then we don't have span information. if cookie != 0 { let pos = BytePos::from_u32(cookie); let span = Span::with_root_ctxt(pos, pos); - err.set_span(span); + err.span(span); }; // Point to the generated assembly if it is available. diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 63fd7b42f7b..36d7234a6ea 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,6 +1,6 @@ use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; @@ -216,7 +216,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Some(fn_sig) = fn_sig() && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0776, @@ -225,7 +225,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") + struct_span_code_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") .emit(); } codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY @@ -238,7 +238,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().abi() != abi::Abi::Rust { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0737, @@ -265,7 +265,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if s.as_str().contains('\0') { // `#[export_name = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0648, @@ -303,14 +303,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // This exception needs to be kept in sync with allowing // `#[target_feature]` on `main` and `start`. } else if !tcx.features().target_feature_11 { - let mut err = feature_err( + feature_err( &tcx.sess.parse_sess, sym::target_feature_11, attr.span, "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(did), "not an `unsafe` function"); - err.emit(); + ) + .with_span_label(tcx.def_span(did), "not an `unsafe` function") + .emit(); } else { check_target_feature_trait_unsafe(tcx, did, attr.span); } @@ -385,7 +385,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { match segments.as_slice() { [sym::arm, sym::a32] | [sym::arm, sym::t32] => { if !tcx.sess.target.has_thumb_interworking { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0779, @@ -402,7 +402,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } _ => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0779, @@ -414,7 +414,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } [] => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0778, @@ -424,7 +424,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { None } _ => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0779, @@ -442,7 +442,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { { rustc_attr::parse_alignment(&literal.kind) .map_err(|msg| { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0589, @@ -469,15 +469,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { Some(MetaItemKind::List(ref items)) => { inline_span = Some(attr.span); if items.len() != 1 { - struct_span_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); + struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument") + .emit(); InlineAttr::None } else if list_contains_name(items, sym::always) { InlineAttr::Always } else if list_contains_name(items, sym::never) { InlineAttr::Never } else { - struct_span_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .help("valid inline arguments are `always` and `never`") + struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") + .with_help("valid inline arguments are `always` and `never`") .emit(); InlineAttr::None @@ -492,7 +493,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if !attr.has_name(sym::optimize) { return ia; } - let err = |sp, s| struct_span_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); + let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); match attr.meta_kind() { Some(MetaItemKind::Word) => { err(attr.span, "expected one argument"); @@ -662,7 +663,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> { let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); tcx.dcx() .struct_span_err(attr.span, msg) - .note("the value may not exceed `u16::MAX`") + .with_note("the value may not exceed `u16::MAX`") .emit(); None } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 2b628d2aa69..f90e1906caf 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -212,192 +212,123 @@ pub struct ThorinErrorWrapper(pub thorin::Error); impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let build = |msg| DiagnosticBuilder::new(dcx, level, msg); - let mut diag; match self.0 { - thorin::Error::ReadInput(_) => { - diag = build(fluent::codegen_ssa_thorin_read_input_failure); - diag - } + thorin::Error::ReadInput(_) => build(fluent::codegen_ssa_thorin_read_input_failure), thorin::Error::ParseFileKind(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_file_kind); - diag + build(fluent::codegen_ssa_thorin_parse_input_file_kind) } thorin::Error::ParseObjectFile(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_object_file); - diag + build(fluent::codegen_ssa_thorin_parse_input_object_file) } thorin::Error::ParseArchiveFile(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_input_archive_file); - diag + build(fluent::codegen_ssa_thorin_parse_input_archive_file) } thorin::Error::ParseArchiveMember(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_archive_member); - diag - } - thorin::Error::InvalidInputKind => { - diag = build(fluent::codegen_ssa_thorin_invalid_input_kind); - diag - } - thorin::Error::DecompressData(_) => { - diag = build(fluent::codegen_ssa_thorin_decompress_data); - diag + build(fluent::codegen_ssa_thorin_parse_archive_member) } + thorin::Error::InvalidInputKind => build(fluent::codegen_ssa_thorin_invalid_input_kind), + thorin::Error::DecompressData(_) => build(fluent::codegen_ssa_thorin_decompress_data), thorin::Error::NamelessSection(_, offset) => { - diag = build(fluent::codegen_ssa_thorin_section_without_name); - diag.set_arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_section_without_name) + .with_arg("offset", format!("0x{offset:08x}")) } thorin::Error::RelocationWithInvalidSymbol(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); - diag.set_arg("section", section); - diag.set_arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol) + .with_arg("section", section) + .with_arg("offset", format!("0x{offset:08x}")) } thorin::Error::MultipleRelocations(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_multiple_relocations); - diag.set_arg("section", section); - diag.set_arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_multiple_relocations) + .with_arg("section", section) + .with_arg("offset", format!("0x{offset:08x}")) } thorin::Error::UnsupportedRelocation(section, offset) => { - diag = build(fluent::codegen_ssa_thorin_unsupported_relocation); - diag.set_arg("section", section); - diag.set_arg("offset", format!("0x{offset:08x}")); - diag - } - thorin::Error::MissingDwoName(id) => { - diag = build(fluent::codegen_ssa_thorin_missing_dwo_name); - diag.set_arg("id", format!("0x{id:08x}")); - diag + build(fluent::codegen_ssa_thorin_unsupported_relocation) + .with_arg("section", section) + .with_arg("offset", format!("0x{offset:08x}")) } + thorin::Error::MissingDwoName(id) => build(fluent::codegen_ssa_thorin_missing_dwo_name) + .with_arg("id", format!("0x{id:08x}")), thorin::Error::NoCompilationUnits => { - diag = build(fluent::codegen_ssa_thorin_no_compilation_units); - diag - } - thorin::Error::NoDie => { - diag = build(fluent::codegen_ssa_thorin_no_die); - diag + build(fluent::codegen_ssa_thorin_no_compilation_units) } + thorin::Error::NoDie => build(fluent::codegen_ssa_thorin_no_die), thorin::Error::TopLevelDieNotUnit => { - diag = build(fluent::codegen_ssa_thorin_top_level_die_not_unit); - diag + build(fluent::codegen_ssa_thorin_top_level_die_not_unit) } thorin::Error::MissingRequiredSection(section) => { - diag = build(fluent::codegen_ssa_thorin_missing_required_section); - diag.set_arg("section", section); - diag + build(fluent::codegen_ssa_thorin_missing_required_section) + .with_arg("section", section) } thorin::Error::ParseUnitAbbreviations(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_abbreviations); - diag + build(fluent::codegen_ssa_thorin_parse_unit_abbreviations) } thorin::Error::ParseUnitAttribute(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_attribute); - diag + build(fluent::codegen_ssa_thorin_parse_unit_attribute) } thorin::Error::ParseUnitHeader(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit_header); - diag - } - thorin::Error::ParseUnit(_) => { - diag = build(fluent::codegen_ssa_thorin_parse_unit); - diag + build(fluent::codegen_ssa_thorin_parse_unit_header) } + thorin::Error::ParseUnit(_) => build(fluent::codegen_ssa_thorin_parse_unit), thorin::Error::IncompatibleIndexVersion(section, format, actual) => { - diag = build(fluent::codegen_ssa_thorin_incompatible_index_version); - diag.set_arg("section", section); - diag.set_arg("actual", actual); - diag.set_arg("format", format); - diag + build(fluent::codegen_ssa_thorin_incompatible_index_version) + .with_arg("section", section) + .with_arg("actual", actual) + .with_arg("format", format) } thorin::Error::OffsetAtIndex(_, index) => { - diag = build(fluent::codegen_ssa_thorin_offset_at_index); - diag.set_arg("index", index); - diag + build(fluent::codegen_ssa_thorin_offset_at_index).with_arg("index", index) } thorin::Error::StrAtOffset(_, offset) => { - diag = build(fluent::codegen_ssa_thorin_str_at_offset); - diag.set_arg("offset", format!("0x{offset:08x}")); - diag + build(fluent::codegen_ssa_thorin_str_at_offset) + .with_arg("offset", format!("0x{offset:08x}")) } thorin::Error::ParseIndex(_, section) => { - diag = build(fluent::codegen_ssa_thorin_parse_index); - diag.set_arg("section", section); - diag + build(fluent::codegen_ssa_thorin_parse_index).with_arg("section", section) } thorin::Error::UnitNotInIndex(unit) => { - diag = build(fluent::codegen_ssa_thorin_unit_not_in_index); - diag.set_arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_unit_not_in_index) + .with_arg("unit", format!("0x{unit:08x}")) } thorin::Error::RowNotInIndex(_, row) => { - diag = build(fluent::codegen_ssa_thorin_row_not_in_index); - diag.set_arg("row", row); - diag - } - thorin::Error::SectionNotInRow => { - diag = build(fluent::codegen_ssa_thorin_section_not_in_row); - diag - } - thorin::Error::EmptyUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_empty_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_row_not_in_index).with_arg("row", row) } + thorin::Error::SectionNotInRow => build(fluent::codegen_ssa_thorin_section_not_in_row), + thorin::Error::EmptyUnit(unit) => build(fluent::codegen_ssa_thorin_empty_unit) + .with_arg("unit", format!("0x{unit:08x}")), thorin::Error::MultipleDebugInfoSection => { - diag = build(fluent::codegen_ssa_thorin_multiple_debug_info_section); - diag + build(fluent::codegen_ssa_thorin_multiple_debug_info_section) } thorin::Error::MultipleDebugTypesSection => { - diag = build(fluent::codegen_ssa_thorin_multiple_debug_types_section); - diag - } - thorin::Error::NotSplitUnit => { - diag = build(fluent::codegen_ssa_thorin_not_split_unit); - diag - } - thorin::Error::DuplicateUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_duplicate_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_multiple_debug_types_section) } + thorin::Error::NotSplitUnit => build(fluent::codegen_ssa_thorin_not_split_unit), + thorin::Error::DuplicateUnit(unit) => build(fluent::codegen_ssa_thorin_duplicate_unit) + .with_arg("unit", format!("0x{unit:08x}")), thorin::Error::MissingReferencedUnit(unit) => { - diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); - diag + build(fluent::codegen_ssa_thorin_missing_referenced_unit) + .with_arg("unit", format!("0x{unit:08x}")) } thorin::Error::NoOutputObjectCreated => { - diag = build(fluent::codegen_ssa_thorin_not_output_object_created); - diag + build(fluent::codegen_ssa_thorin_not_output_object_created) } thorin::Error::MixedInputEncodings => { - diag = build(fluent::codegen_ssa_thorin_mixed_input_encodings); - diag + build(fluent::codegen_ssa_thorin_mixed_input_encodings) } thorin::Error::Io(e) => { - diag = build(fluent::codegen_ssa_thorin_io); - diag.set_arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_io).with_arg("error", format!("{e}")) } thorin::Error::ObjectRead(e) => { - diag = build(fluent::codegen_ssa_thorin_object_read); - diag.set_arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_object_read).with_arg("error", format!("{e}")) } thorin::Error::ObjectWrite(e) => { - diag = build(fluent::codegen_ssa_thorin_object_write); - diag.set_arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_object_write).with_arg("error", format!("{e}")) } thorin::Error::GimliRead(e) => { - diag = build(fluent::codegen_ssa_thorin_gimli_read); - diag.set_arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_gimli_read).with_arg("error", format!("{e}")) } thorin::Error::GimliWrite(e) => { - diag = build(fluent::codegen_ssa_thorin_gimli_write); - diag.set_arg("error", format!("{e}")); - diag + build(fluent::codegen_ssa_thorin_gimli_write).with_arg("error", format!("{e}")) } _ => unimplemented!("Untranslated thorin error"), } @@ -414,8 +345,8 @@ pub struct LinkingFailed<'a> { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for LinkingFailed<'_> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_ssa_linking_failed); - diag.set_arg("linker_path", format!("{}", self.linker_path.display())); - diag.set_arg("exit_status", format!("{}", self.exit_status)); + diag.arg("linker_path", format!("{}", self.linker_path.display())); + diag.arg("exit_status", format!("{}", self.exit_status)); let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 14915e816ee..48f3f4f2522 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -228,21 +228,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// In order to have a good line stepping behavior in debugger, we overwrite debug /// locations of macro expansions with that of the outermost expansion site (when the macro is /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). - fn adjust_span_for_debugging(&self, mut span: Span) -> Span { + fn adjust_span_for_debugging(&self, span: Span) -> Span { // Bail out if debug info emission is not enabled. if self.debug_context.is_none() { return span; } - - if self.cx.tcx().should_collapse_debuginfo(span) { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - // Use span of the outermost expansion site, while keeping the original lexical scope. - span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt()); - } - - span + // Walk up the macro expansion chain until we reach a non-expanded span. + // We also stop at the function body level because no line stepping can occur + // at the level above that. + // Use span of the outermost expansion site, while keeping the original lexical scope. + self.cx.tcx().collapsed_debuginfo(span, self.mir.span) } fn spill_operand_to_stack( diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 794cbd315b7..6f6f010422f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -231,14 +231,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx: &mut Bx, ) -> V { if let OperandValue::Pair(a, b) = self.val { - let llty = bx.cx().backend_type(self.layout); + let llty = bx.cx().immediate_backend_type(self.layout); debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); // Reconstruct the immediate aggregate. let mut llpair = bx.cx().const_poison(llty); - let imm_a = bx.from_immediate(a); - let imm_b = bx.from_immediate(b); - llpair = bx.insert_value(llpair, imm_a, 0); - llpair = bx.insert_value(llpair, imm_b, 1); + llpair = bx.insert_value(llpair, a, 0); + llpair = bx.insert_value(llpair, b, 1); llpair } else { self.immediate() @@ -251,14 +249,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { llval: V, layout: TyAndLayout<'tcx>, ) -> Self { - let val = if let Abi::ScalarPair(a, b) = layout.abi { + let val = if let Abi::ScalarPair(..) = layout.abi { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. let a_llval = bx.extract_value(llval, 0); - let a_llval = bx.to_immediate_scalar(a_llval, a); let b_llval = bx.extract_value(llval, 1); - let b_llval = bx.to_immediate_scalar(b_llval, b); OperandValue::Pair(a_llval, b_llval) } else { OperandValue::Immediate(llval) @@ -435,15 +431,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else { bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout); }; - let ty = bx.backend_type(dest.layout); let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi); - let llptr = bx.struct_gep(ty, dest.llval, 0); let val = bx.from_immediate(a); let align = dest.align; - bx.store_with_flags(val, llptr, align, flags); + bx.store_with_flags(val, dest.llval, align, flags); - let llptr = bx.struct_gep(ty, dest.llval, 1); + let llptr = + bx.inbounds_gep(bx.type_i8(), dest.llval, &[bx.const_usize(b_offset.bytes())]); let val = bx.from_immediate(b); let align = dest.align.restrict_for_offset(b_offset); bx.store_with_flags(val, llptr, align, flags); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index c0bb3ac5661..73c08e2ca61 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -108,20 +108,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // Also handles the first field of Scalar, ScalarPair, and Vector layouts. self.llval } - Abi::ScalarPair(a, b) - if offset == a.size(bx.cx()).align_to(b.align(bx.cx()).abi) => - { - // Offset matches second field. - let ty = bx.backend_type(self.layout); - bx.struct_gep(ty, self.llval, 1) + Abi::ScalarPair(..) => { + // FIXME(nikic): Generate this for all ABIs. + bx.inbounds_gep(bx.type_i8(), self.llval, &[bx.const_usize(offset.bytes())]) } - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => { + Abi::Scalar(_) | Abi::Vector { .. } if field.is_zst() => { // ZST fields (even some that require alignment) are not included in Scalar, // ScalarPair, and Vector layouts, so manually offset the pointer. bx.gep(bx.cx().type_i8(), self.llval, &[bx.const_usize(offset.bytes())]) } - Abi::Scalar(_) | Abi::ScalarPair(..) => { - // All fields of Scalar and ScalarPair layouts must have been handled by this point. + Abi::Scalar(_) => { + // All fields of Scalar layouts must have been handled by this point. // Vector layouts have additional fields for each element of the vector, so don't panic in that case. bug!( "offset of non-ZST field `{:?}` does not match layout `{:#?}`", diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 031fcc0adb1..0fef6bc110e 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,8 +1,8 @@ use crate::errors; use rustc_ast::ast; use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::unord::UnordMap; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -18,7 +18,7 @@ use rustc_span::Span; pub fn from_target_feature( tcx: TyCtxt<'_>, attr: &ast::Attribute, - supported_target_features: &FxHashMap<String, Option<Symbol>>, + supported_target_features: &UnordMap<String, Option<Symbol>>, target_features: &mut Vec<Symbol>, ) { let Some(list) = attr.meta_item_list() else { return }; @@ -27,7 +27,7 @@ pub fn from_target_feature( let code = "enable = \"..\""; tcx.dcx() .struct_span_err(span, msg) - .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) + .with_span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) .emit(); }; let rust_features = tcx.features(); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7fb5f10c6ca..6947ace17c5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -391,10 +391,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if ecx.tcx.is_ctfe_mir_available(def) { Ok(ecx.tcx.mir_for_ctfe(def)) } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { - let guar = ecx.tcx.dcx().span_delayed_bug( - rustc_span::DUMMY_SP, - "This is likely a const item that is missing from its impl", - ); + let guar = ecx + .tcx + .dcx() + .delayed_bug("This is likely a const item that is missing from its impl"); throw_inval!(AlreadyReported(guar.into())); } else { // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, @@ -630,7 +630,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // current number of evaluated terminators is a power of 2. The latter gives us a cheap // way to implement exponential backoff. let span = ecx.cur_span(); - ecx.tcx.dcx().emit_warning(LongRunningWarn { span, item_span: ecx.tcx.span }); + ecx.tcx.dcx().emit_warn(LongRunningWarn { span, item_span: ecx.tcx.span }); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 110ff87e27e..171cc89d6ad 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -518,7 +518,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { Ub(_) => {} Custom(custom) => { (custom.add_args)(&mut |name, value| { - builder.set_arg(name, value); + builder.arg(name, value); }); } ValidationError(e) => e.add_args(dcx, builder), @@ -536,65 +536,65 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { | UninhabitedEnumVariantWritten(_) | UninhabitedEnumVariantRead(_) => {} BoundsCheckFailed { len, index } => { - builder.set_arg("len", len); - builder.set_arg("index", index); + builder.arg("len", len); + builder.arg("index", index); } UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { - builder.set_arg("pointer", ptr); + builder.arg("pointer", ptr); } PointerUseAfterFree(alloc_id, msg) => { builder - .set_arg("alloc_id", alloc_id) - .set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + .arg("alloc_id", alloc_id) + .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { builder - .set_arg("alloc_id", alloc_id) - .set_arg("alloc_size", alloc_size.bytes()) - .set_arg("ptr_offset", ptr_offset) - .set_arg("ptr_size", ptr_size.bytes()) - .set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + .arg("alloc_id", alloc_id) + .arg("alloc_size", alloc_size.bytes()) + .arg("ptr_offset", ptr_offset) + .arg("ptr_size", ptr_size.bytes()) + .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } DanglingIntPointer(ptr, msg) => { if ptr != 0 { - builder.set_arg("pointer", format!("{ptr:#x}[noalloc]")); + builder.arg("pointer", format!("{ptr:#x}[noalloc]")); } - builder.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } AlignmentCheckFailed(Misalignment { required, has }, msg) => { - builder.set_arg("required", required.bytes()); - builder.set_arg("has", has.bytes()); - builder.set_arg("msg", format!("{msg:?}")); + builder.arg("required", required.bytes()); + builder.arg("has", has.bytes()); + builder.arg("msg", format!("{msg:?}")); } WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { - builder.set_arg("allocation", alloc); + builder.arg("allocation", alloc); } InvalidBool(b) => { - builder.set_arg("value", format!("{b:02x}")); + builder.arg("value", format!("{b:02x}")); } InvalidChar(c) => { - builder.set_arg("value", format!("{c:08x}")); + builder.arg("value", format!("{c:08x}")); } InvalidTag(tag) => { - builder.set_arg("tag", format!("{tag:x}")); + builder.arg("tag", format!("{tag:x}")); } InvalidStr(err) => { - builder.set_arg("err", format!("{err}")); + builder.arg("err", format!("{err}")); } InvalidUninitBytes(Some((alloc, info))) => { - builder.set_arg("alloc", alloc); - builder.set_arg("access", info.access); - builder.set_arg("uninit", info.bad); + builder.arg("alloc", alloc); + builder.arg("access", info.access); + builder.arg("uninit", info.bad); } ScalarSizeMismatch(info) => { - builder.set_arg("target_size", info.target_size); - builder.set_arg("data_size", info.data_size); + builder.arg("target_size", info.target_size); + builder.arg("data_size", info.data_size); } AbiMismatchArgument { caller_ty, callee_ty } | AbiMismatchReturn { caller_ty, callee_ty } => { - builder.set_arg("caller_ty", caller_ty.to_string()); - builder.set_arg("callee_ty", callee_ty.to_string()); + builder.arg("caller_ty", caller_ty.to_string()); + builder.arg("callee_ty", callee_ty.to_string()); } } } @@ -695,7 +695,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ) }; - err.set_arg("front_matter", message); + err.arg("front_matter", message); fn add_range_arg<G: EmissionGuarantee>( r: WrappingRange, @@ -725,12 +725,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ]; let args = args.iter().map(|(a, b)| (a, b)); let message = dcx.eagerly_translate_to_string(msg, args); - err.set_arg("in_range", message); + err.arg("in_range", message); } match self.kind { PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => { - err.set_arg("ty", ty); + err.arg("ty", ty); } PointerAsInt { expected } | Uninit { expected } => { let msg = match expected { @@ -747,28 +747,28 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ExpectedKind::Str => fluent::const_eval_validation_expected_str, }; let msg = dcx.eagerly_translate_to_string(msg, [].into_iter()); - err.set_arg("expected", msg); + err.arg("expected", msg); } InvalidEnumTag { value } | InvalidVTablePtr { value } | InvalidBool { value } | InvalidChar { value } | InvalidFnPtr { value } => { - err.set_arg("value", value); + err.arg("value", value); } NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { add_range_arg(range, max_value, dcx, err) } OutOfRange { range, max_value, value } => { - err.set_arg("value", value); + err.arg("value", value); add_range_arg(range, max_value, dcx, err); } UnalignedPtr { required_bytes, found_bytes, .. } => { - err.set_arg("required_bytes", required_bytes); - err.set_arg("found_bytes", found_bytes); + err.arg("required_bytes", required_bytes); + err.arg("found_bytes", found_bytes); } DanglingPtrNoProvenance { pointer, .. } => { - err.set_arg("pointer", pointer); + err.arg("pointer", pointer); } NullPtr { .. } | PtrToStatic { .. } @@ -814,10 +814,10 @@ impl ReportErrorExt for UnsupportedOpInfo { // print. So it's not worth the effort of having diagnostics that can print the `info`. UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { - builder.set_arg("ptr", ptr); + builder.arg("ptr", ptr); } ThreadLocalStatic(did) | ReadExternStatic(did) => { - builder.set_arg("did", format!("{did:?}")); + builder.arg("did", format!("{did:?}")); } } } @@ -844,7 +844,7 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> { InterpError::InvalidProgram(e) => e.add_args(dcx, builder), InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder), InterpError::MachineStop(e) => e.add_args(&mut |name, value| { - builder.set_arg(name, value); + builder.arg(name, value); }), } } @@ -880,15 +880,15 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(dcx, dummy_level); for (name, val) in diag.args() { - builder.set_arg(name.clone(), val.clone()); + builder.arg(name.clone(), val.clone()); } diag.cancel(); } InvalidProgramInfo::FnAbiAdjustForForeignAbi( AdjustForForeignAbiError::Unsupported { arch, abi }, ) => { - builder.set_arg("arch", arch); - builder.set_arg("abi", abi.name()); + builder.arg("arch", arch); + builder.arg("abi", abi.name()); } } } 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 92955c4ed14..738c532964a 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -338,7 +338,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { return; } - let mut err = op.build_error(self.ccx, span); + let err = op.build_error(self.ccx, span); assert!(err.is_error()); match op.importance() { 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 7e1cbfe6667..1efa52df581 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -157,9 +157,7 @@ impl Qualif for NeedsNonConstDrop { // FIXME(effects): If `destruct` is not a `const_trait`, // or effects are disabled in this crate, then give up. let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); - if cx.tcx.generics_of(destruct_def_id).host_effect_index.is_none() - || !cx.tcx.features().effects - { + if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects { return NeedsDrop::in_any_value_of_ty(cx, ty); } diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs index a2928bdf51b..e3582c7d317 100644 --- a/compiler/rustc_const_eval/src/transform/mod.rs +++ b/compiler/rustc_const_eval/src/transform/mod.rs @@ -1,3 +1,2 @@ pub mod check_consts; -pub mod promote_consts; pub mod validate; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b249ffb84b3..0b73691204d 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -74,7 +74,6 @@ impl<'tcx> MirPass<'tcx> for Validator { mir_phase, unwind_edge_count: 0, reachable_blocks: traversal::reachable_as_bitset(body), - place_cache: FxHashSet::default(), value_cache: FxHashSet::default(), can_unwind, }; @@ -106,7 +105,6 @@ struct CfgChecker<'a, 'tcx> { mir_phase: MirPhase, unwind_edge_count: usize, reachable_blocks: BitSet<BasicBlock>, - place_cache: FxHashSet<PlaceRef<'tcx>>, value_cache: FxHashSet<u128>, // If `false`, then the MIR must not contain `UnwindAction::Continue` or // `TerminatorKind::Resume`. @@ -294,19 +292,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match &statement.kind { - StatementKind::Assign(box (dest, rvalue)) => { - // FIXME(JakobDegen): Check this for all rvalues, not just this one. - if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { - // The sides of an assignment must not alias. Currently this just checks whether - // the places are identical. - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); - } - } - } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( @@ -341,7 +326,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { self.fail(location, format!("explicit `{kind:?}` is forbidden")); } } - StatementKind::StorageLive(_) + StatementKind::Assign(..) + | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Intrinsic(_) | StatementKind::Coverage(_) @@ -404,10 +390,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } // The call destination place and Operand::Move place used as an argument might be - // passed by a reference to the callee. Consequently they must be non-overlapping - // and cannot be packed. Currently this simply checks for duplicate places. - self.place_cache.clear(); - self.place_cache.insert(destination.as_ref()); + // passed by a reference to the callee. Consequently they cannot be packed. if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() { // This is bad! The callee will expect the memory to be aligned. self.fail( @@ -418,10 +401,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { ), ); } - let mut has_duplicates = false; for arg in args { if let Operand::Move(place) = arg { - has_duplicates |= !self.place_cache.insert(place.as_ref()); if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() { // This is bad! The callee will expect the memory to be aligned. self.fail( @@ -434,16 +415,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { } } } - - if has_duplicates { - self.fail( - location, - format!( - "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}", - terminator.kind, - ), - ); - } } TerminatorKind::Assert { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); @@ -1112,17 +1083,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } - // FIXME(JakobDegen): Check this for all rvalues, not just this one. - if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { - // The sides of an assignment must not alias. Currently this just checks whether - // the places are identical. - if dest == src { - self.fail( - location, - "encountered `Assign` statement with overlapping memory", - ); - } - } } StatementKind::AscribeUserType(..) => { if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index 9fce0e1e65c..80e72250470 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -7,6 +7,7 @@ pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>; pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>; pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>; pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>; +pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>; #[macro_export] macro_rules! define_id_collections { diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 4b819e1cbd6..a45f1dd72a1 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -394,6 +394,7 @@ impl<Node: Idx> Dominators<Node> { /// # Panics /// /// Panics if `b` is unreachable. + #[inline] pub fn dominates(&self, a: Node, b: Node) -> bool { match &self.kind { Kind::Path => a.index() <= b.index(), diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index ed2e558bffa..1436628139f 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -16,7 +16,7 @@ pub use index_map::SortedIndexMultiMap; /// stores data in a more compact way. It also supports accessing contiguous /// ranges of elements as a slice, and slices of already sorted elements can be /// inserted efficiently. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_Generic, Decodable_Generic)] pub struct SortedMap<K, V> { data: Vec<(K, V)>, } diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 6d75b0fb8a0..afe26f80de8 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -245,6 +245,32 @@ unsafe impl<T: StableOrd> StableOrd for &T { const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT; } +/// This is a companion trait to `StableOrd`. Some types like `Symbol` can be +/// compared in a cross-session stable way, but their `Ord` implementation is +/// not stable. In such cases, a `StableOrd` implementation can be provided +/// to offer a lightweight way for stable sorting. (The more heavyweight option +/// is to sort via `ToStableHashKey`, but then sorting needs to have access to +/// a stable hashing context and `ToStableHashKey` can also be expensive as in +/// the case of `Symbol` where it has to allocate a `String`.) +/// +/// See the documentation of [StableOrd] for how stable sort order is defined. +/// The same definition applies here. Be careful when implementing this trait. +pub trait StableCompare { + const CAN_USE_UNSTABLE_SORT: bool; + + fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering; +} + +/// `StableOrd` denotes that the type's `Ord` implementation is stable, so +/// we can implement `StableCompare` by just delegating to `Ord`. +impl<T: StableOrd> StableCompare for T { + const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT; + + fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { + self.cmp(other) + } +} + /// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since /// that has the same requirements. /// diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 71679086f16..1cfc9fecd47 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -10,7 +10,7 @@ use std::fmt; use crate::stable_hasher; -#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)] pub struct Svh { hash: Fingerprint, } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 43221d70e21..48edfba8da0 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -56,9 +56,6 @@ mod parallel; pub use parallel::scope; pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in}; -pub use std::sync::atomic::Ordering; -pub use std::sync::atomic::Ordering::SeqCst; - pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; @@ -67,8 +64,7 @@ mod freeze; pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; mod mode { - use super::Ordering; - use std::sync::atomic::AtomicU8; + use std::sync::atomic::{AtomicU8, Ordering}; const UNINITIALIZED: u8 = 0; const DYN_NOT_THREAD_SAFE: u8 = 1; @@ -113,6 +109,7 @@ cfg_match! { cfg(not(parallel_compiler)) => { use std::ops::Add; use std::cell::Cell; + use std::sync::atomic::Ordering; pub unsafe auto trait Send {} pub unsafe auto trait Sync {} diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 47c56eba7ad..907c866b3ed 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -3,9 +3,8 @@ //! as required by the query system. use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::SmallVec; use std::{ - borrow::Borrow, + borrow::{Borrow, BorrowMut}, collections::hash_map::Entry, hash::Hash, iter::{Product, Sum}, @@ -14,7 +13,7 @@ use std::{ use crate::{ fingerprint::Fingerprint, - stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey}, + stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey}, }; /// `UnordItems` is the order-less version of `Iterator`. It only contains methods @@ -134,36 +133,78 @@ impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> { } } -impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> { +impl<T, I: Iterator<Item = T>> UnordItems<T, I> { + #[inline] pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T> where T: ToStableHashKey<HCX>, { - let mut items: Vec<T> = self.0.collect(); - items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); - items + self.collect_sorted(hcx, true) } #[inline] pub fn into_sorted_stable_ord(self) -> Vec<T> where - T: Ord + StableOrd, + T: StableCompare, + { + self.collect_stable_ord_by_key(|x| x) + } + + #[inline] + pub fn into_sorted_stable_ord_by_key<K, C>(self, project_to_key: C) -> Vec<T> + where + K: StableCompare, + C: for<'a> Fn(&'a T) -> &'a K, { - let mut items: Vec<T> = self.0.collect(); - if !T::CAN_USE_UNSTABLE_SORT { - items.sort(); - } else { - items.sort_unstable() + self.collect_stable_ord_by_key(project_to_key) + } + + #[inline] + pub fn collect_sorted<HCX, C>(self, hcx: &HCX, cache_sort_key: bool) -> C + where + T: ToStableHashKey<HCX>, + C: FromIterator<T> + BorrowMut<[T]>, + { + let mut items: C = self.0.collect(); + + let slice = items.borrow_mut(); + if slice.len() > 1 { + if cache_sort_key { + slice.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); + } else { + slice.sort_by_key(|x| x.to_stable_hash_key(hcx)); + } } + items } - pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]> + #[inline] + pub fn collect_stable_ord_by_key<K, C, P>(self, project_to_key: P) -> C where - T: ToStableHashKey<HCX>, + K: StableCompare, + P: for<'a> Fn(&'a T) -> &'a K, + C: FromIterator<T> + BorrowMut<[T]>, { - let mut items: SmallVec<[T; LEN]> = self.0.collect(); - items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); + let mut items: C = self.0.collect(); + + let slice = items.borrow_mut(); + if slice.len() > 1 { + if !K::CAN_USE_UNSTABLE_SORT { + slice.sort_by(|a, b| { + let a_key = project_to_key(a); + let b_key = project_to_key(b); + a_key.stable_cmp(b_key) + }); + } else { + slice.sort_unstable_by(|a, b| { + let a_key = project_to_key(a); + let b_key = project_to_key(b); + a_key.stable_cmp(b_key) + }); + } + } + items } } @@ -185,7 +226,7 @@ trait UnordCollection {} /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordSet<V: Eq + Hash> { inner: FxHashSet<V>, } @@ -268,16 +309,30 @@ impl<V: Eq + Hash> UnordSet<V> { } /// Returns the items of this set in stable sort order (as defined by - /// `StableOrd`). This method is much more efficient than + /// `StableCompare`). This method is much more efficient than /// `into_sorted` because it does not need to transform keys to their /// `ToStableHashKey` equivalent. #[inline] - pub fn to_sorted_stable_ord(&self) -> Vec<V> + pub fn to_sorted_stable_ord(&self) -> Vec<&V> where - V: Ord + StableOrd + Clone, + V: StableCompare, { - let mut items: Vec<V> = self.inner.iter().cloned().collect(); - items.sort_unstable(); + let mut items: Vec<&V> = self.inner.iter().collect(); + items.sort_unstable_by(|a, b| a.stable_cmp(*b)); + items + } + + /// Returns the items of this set in stable sort order (as defined by + /// `StableCompare`). This method is much more efficient than + /// `into_sorted` because it does not need to transform keys to their + /// `ToStableHashKey` equivalent. + #[inline] + pub fn into_sorted_stable_ord(self) -> Vec<V> + where + V: StableCompare, + { + let mut items: Vec<V> = self.inner.into_iter().collect(); + items.sort_unstable_by(V::stable_cmp); items } @@ -362,7 +417,7 @@ impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> { /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordMap<K: Eq + Hash, V> { inner: FxHashMap<K, V>, } @@ -483,16 +538,16 @@ impl<K: Eq + Hash, V> UnordMap<K, V> { to_sorted_vec(hcx, self.inner.iter(), cache_sort_key, |&(k, _)| k) } - /// Returns the entries of this map in stable sort order (as defined by `StableOrd`). + /// Returns the entries of this map in stable sort order (as defined by `StableCompare`). /// This method can be much more efficient than `into_sorted` because it does not need /// to transform keys to their `ToStableHashKey` equivalent. #[inline] - pub fn to_sorted_stable_ord(&self) -> Vec<(K, &V)> + pub fn to_sorted_stable_ord(&self) -> Vec<(&K, &V)> where - K: Ord + StableOrd + Copy, + K: StableCompare, { - let mut items: Vec<(K, &V)> = self.inner.iter().map(|(&k, v)| (k, v)).collect(); - items.sort_unstable_by_key(|&(k, _)| k); + let mut items: Vec<_> = self.inner.iter().collect(); + items.sort_unstable_by(|(a, _), (b, _)| a.stable_cmp(*b)); items } @@ -510,6 +565,19 @@ impl<K: Eq + Hash, V> UnordMap<K, V> { to_sorted_vec(hcx, self.inner.into_iter(), cache_sort_key, |(k, _)| k) } + /// Returns the entries of this map in stable sort order (as defined by `StableCompare`). + /// This method can be much more efficient than `into_sorted` because it does not need + /// to transform keys to their `ToStableHashKey` equivalent. + #[inline] + pub fn into_sorted_stable_ord(self) -> Vec<(K, V)> + where + K: StableCompare, + { + let mut items: Vec<(K, V)> = self.inner.into_iter().collect(); + items.sort_unstable_by(|a, b| a.0.stable_cmp(&b.0)); + items + } + /// Returns the values of this map in stable sort order (as defined by K's /// `ToStableHashKey` implementation). /// @@ -558,7 +626,7 @@ impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> fo /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] pub struct UnordBag<V> { inner: Vec<V>, } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 49042984553..97a7dfef3b3 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -50,6 +50,7 @@ rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" +shlex = "1.0" time = { version = "0.3", default-features = false, features = ["alloc", "formatting"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index b7407f5a508..5dfd37a6da4 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -5,18 +5,92 @@ use std::io; use rustc_session::EarlyDiagCtxt; -fn arg_expand(arg: String) -> Result<Vec<String>, Error> { - if let Some(path) = arg.strip_prefix('@') { - let file = match fs::read_to_string(path) { - Ok(file) => file, - Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { - return Err(Error::Utf8Error(Some(path.to_string()))); +/// Expands argfiles in command line arguments. +#[derive(Default)] +struct Expander { + shell_argfiles: bool, + next_is_unstable_option: bool, + expanded: Vec<String>, +} + +impl Expander { + /// Handles the next argument. If the argument is an argfile, it is expanded + /// inline. + fn arg(&mut self, arg: &str) -> Result<(), Error> { + if let Some(argfile) = arg.strip_prefix('@') { + match argfile.split_once(':') { + Some(("shell", path)) if self.shell_argfiles => { + shlex::split(&Self::read_file(path)?) + .ok_or_else(|| Error::ShellParseError(path.to_string()))? + .into_iter() + .for_each(|arg| self.push(arg)); + } + _ => { + let contents = Self::read_file(argfile)?; + contents.lines().for_each(|arg| self.push(arg.to_string())); + } + } + } else { + self.push(arg.to_string()); + } + + Ok(()) + } + + /// Adds a command line argument verbatim with no argfile expansion. + fn push(&mut self, arg: String) { + // Unfortunately, we have to do some eager argparsing to handle unstable + // options which change the behavior of argfile arguments. + // + // Normally, all of the argfile arguments (e.g. `@args.txt`) are + // expanded into our arguments list *and then* the whole list of + // arguments are passed on to be parsed. However, argfile parsing + // options like `-Zshell_argfiles` need to change the behavior of that + // argument expansion. So we have to do a little parsing on our own here + // instead of leaning on the existing logic. + // + // All we care about are unstable options, so we parse those out and + // look for any that affect how we expand argfiles. This argument + // inspection is very conservative; we only change behavior when we see + // exactly the options we're looking for and everything gets passed + // through. + + if self.next_is_unstable_option { + self.inspect_unstable_option(&arg); + self.next_is_unstable_option = false; + } else if let Some(unstable_option) = arg.strip_prefix("-Z") { + if unstable_option.is_empty() { + self.next_is_unstable_option = true; + } else { + self.inspect_unstable_option(unstable_option); + } + } + + self.expanded.push(arg); + } + + /// Consumes the `Expander`, returning the expanded arguments. + fn finish(self) -> Vec<String> { + self.expanded + } + + /// Parses any relevant unstable flags specified on the command line. + fn inspect_unstable_option(&mut self, option: &str) { + match option { + "shell-argfiles" => self.shell_argfiles = true, + _ => (), + } + } + + /// Reads the contents of a file as UTF-8. + fn read_file(path: &str) -> Result<String, Error> { + fs::read_to_string(path).map_err(|e| { + if e.kind() == io::ErrorKind::InvalidData { + Error::Utf8Error(Some(path.to_string())) + } else { + Error::IOError(path.to_string(), e) } - Err(err) => return Err(Error::IOError(path.to_string(), err)), - }; - Ok(file.lines().map(ToString::to_string).collect()) - } else { - Ok(vec![arg]) + }) } } @@ -24,20 +98,20 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> { /// If this function is intended to be used with command line arguments, /// `argv[0]` must be removed prior to calling it manually. pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> { - let mut args = Vec::new(); + let mut expander = Expander::default(); for arg in at_args { - match arg_expand(arg.clone()) { - Ok(arg) => args.extend(arg), - Err(err) => early_dcx.early_fatal(format!("Failed to load argument file: {err}")), + if let Err(err) = expander.arg(arg) { + early_dcx.early_fatal(format!("Failed to load argument file: {err}")); } } - args + expander.finish() } #[derive(Debug)] pub enum Error { Utf8Error(Option<String>), IOError(String, io::Error), + ShellParseError(String), } impl fmt::Display for Error { @@ -46,6 +120,7 @@ impl fmt::Display for Error { Error::Utf8Error(None) => write!(fmt, "Utf8 error"), Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"), Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"), + Error::ShellParseError(path) => write!(fmt, "Invalid shell-style arguments in {path}"), } } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index ca6b0afc76a..2e4baf26176 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -12,6 +12,7 @@ #![feature(lazy_cell)] #![feature(let_chains)] #![feature(panic_update_hook)] +#![feature(result_flattening)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -24,7 +25,6 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; -use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; @@ -475,7 +475,7 @@ fn run_compiler( eprintln!( "Fuel used by {}: {}", sess.opts.unstable_opts.print_fuel.as_ref().unwrap(), - sess.print_fuel.load(SeqCst) + sess.print_fuel.load(Ordering::SeqCst) ); } @@ -715,7 +715,7 @@ fn print_crate_info( let result = parse_crate_attrs(sess); match result { Ok(attrs) => Some(attrs), - Err(mut parse_error) => { + Err(parse_error) => { parse_error.emit(); return Compilation::Stop; } @@ -1249,8 +1249,7 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuarantee /// Variant of `catch_fatal_errors` for the `interface::Result` return type /// that also computes the exit code. pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { - let result = catch_fatal_errors(f).and_then(|result| result); - match result { + match catch_fatal_errors(f).flatten() { Ok(()) => EXIT_SUCCESS, Err(_) => EXIT_FAILURE, } @@ -1393,7 +1392,7 @@ fn report_ice( ) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( + let emitter = Box::new(rustc_errors::emitter::HumanEmitter::stderr( rustc_errors::ColorConfig::Auto, fallback_bundle, )); @@ -1430,7 +1429,7 @@ fn report_ice( } Err(err) => { // The path ICE couldn't be written to disk, provide feedback to the user as to why. - dcx.emit_warning(session_diagnostics::IcePathError { + dcx.emit_warn(session_diagnostics::IcePathError { path: path.clone(), error: err.to_string(), env_var: std::env::var_os("RUSTC_ICE") diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1028d43f9c5..9cd9ed54d41 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -515,6 +515,8 @@ E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), E0795: include_str!("./error_codes/E0795.md"), +E0796: include_str!("./error_codes/E0796.md"), +E0797: include_str!("./error_codes/E0797.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0733.md b/compiler/rustc_error_codes/src/error_codes/E0733.md index 051b75148e5..42c01975dd8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0733.md +++ b/compiler/rustc_error_codes/src/error_codes/E0733.md @@ -10,35 +10,31 @@ async fn foo(n: usize) { } ``` -To perform async recursion, the `async fn` needs to be desugared such that the -`Future` is explicit in the return type: +The recursive invocation can be boxed: -```edition2018,compile_fail,E0720 -use std::future::Future; -fn foo_desugared(n: usize) -> impl Future<Output = ()> { - async move { - if n > 0 { - foo_desugared(n - 1).await; - } +```edition2018 +async fn foo(n: usize) { + if n > 0 { + Box::pin(foo(n - 1)).await; } } ``` -Finally, the future is wrapped in a pinned box: +The `Box<...>` ensures that the result is of known size, and the pin is +required to keep it in the same place in memory. + +Alternatively, the body can be boxed: ```edition2018 use std::future::Future; use std::pin::Pin; -fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> { +fn foo(n: usize) -> Pin<Box<dyn Future<Output = ()>>> { Box::pin(async move { if n > 0 { - foo_recursive(n - 1).await; + foo(n - 1).await; } }) } ``` -The `Box<...>` ensures that the result is of known size, and the pin is -required to keep it in the same place in memory. - [`async`]: https://doc.rust-lang.org/std/keyword.async.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md new file mode 100644 index 00000000000..cea18f8db85 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0796.md @@ -0,0 +1,22 @@ +Reference of mutable static. + +Erroneous code example: + +```compile_fail,edition2024,E0796 +static mut X: i32 = 23; +static mut Y: i32 = 24; + +unsafe { + let y = &X; + let ref x = X; + let (x, y) = (&X, &Y); + foo(&X); +} + +fn foo<'a>(_x: &'a i32) {} +``` + +Mutable statics can be written to by multiple threads: aliasing violations or +data races will cause undefined behavior. + +Reference of mutable static is a hard error from 2024 edition. diff --git a/compiler/rustc_error_codes/src/error_codes/E0797.md b/compiler/rustc_error_codes/src/error_codes/E0797.md new file mode 100644 index 00000000000..8a912307264 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0797.md @@ -0,0 +1,26 @@ +Struct update syntax was used without a base expression. + +Erroneous code example: + +```compile_fail,E0797 +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, .. }; // error +``` + +Using struct update syntax requires a 'base expression'. +This will be used to fill remaining fields. + +``` +struct Foo { + fizz: u8, + buzz: u8 +} + +let f1 = Foo { fizz: 10, buzz: 1}; +let f2 = Foo { fizz: 10, ..f1 }; +``` diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 48e48f59a99..97f2efa7874 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -20,7 +20,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::SourceFile; /// Generates diagnostics using annotate-snippet -pub struct AnnotateSnippetEmitterWriter { +pub struct AnnotateSnippetEmitter { source_map: Option<Lrc<SourceMap>>, fluent_bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, @@ -33,7 +33,7 @@ pub struct AnnotateSnippetEmitterWriter { macro_backtrace: bool, } -impl Translate for AnnotateSnippetEmitterWriter { +impl Translate for AnnotateSnippetEmitter { fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { self.fluent_bundle.as_ref() } @@ -43,7 +43,7 @@ impl Translate for AnnotateSnippetEmitterWriter { } } -impl Emitter for AnnotateSnippetEmitterWriter { +impl Emitter for AnnotateSnippetEmitter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, diag: &Diagnostic) { let fluent_args = to_fluent_args(diag.args()); @@ -86,10 +86,8 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => { - AnnotationType::Error - } - Level::Warning(_) => AnnotationType::Warning, + Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error, + Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help | Level::OnceHelp => AnnotationType::Help, // FIXME(#59346): Not sure how to map this level @@ -99,7 +97,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { } } -impl AnnotateSnippetEmitterWriter { +impl AnnotateSnippetEmitter { pub fn new( source_map: Option<Lrc<SourceMap>>, fluent_bundle: Option<Lrc<FluentBundle>>, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 49431fb7b3f..d8d6922a1bc 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -152,7 +152,6 @@ pub enum DiagnosticId { name: String, /// Indicates whether this lint should show up in cargo's future breakage report. has_future_breakage: bool, - is_force_warn: bool, }, } @@ -212,6 +211,9 @@ impl StringPart { } } +// Note: most of these methods are setters that return `&mut Self`. The small +// number of simple getter functions all have `get_` prefixes to distinguish +// them from the setters. impl Diagnostic { #[track_caller] pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self { @@ -241,13 +243,12 @@ impl Diagnostic { pub fn is_error(&self) -> bool { match self.level { - Level::Bug - | Level::DelayedBug - | Level::Fatal - | Level::Error { .. } - | Level::FailureNote => true, + Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error | Level::FailureNote => { + true + } - Level::Warning(_) + Level::ForceWarning(_) + | Level::Warning | Level::Note | Level::OnceNote | Level::Help @@ -261,7 +262,7 @@ impl Diagnostic { &mut self, unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>, ) { - if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) = + if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) = &mut self.level { if expectation_id.is_stable() { @@ -291,8 +292,11 @@ impl Diagnostic { } pub(crate) fn is_force_warn(&self) -> bool { - match self.code { - Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn, + match self.level { + Level::ForceWarning(_) => { + assert!(self.is_lint); + true + } _ => false, } } @@ -308,25 +312,27 @@ impl Diagnostic { /// In the meantime, though, callsites are required to deal with the "bug" /// locally in whichever way makes the most sense. #[track_caller] - pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { + pub fn downgrade_to_delayed_bug(&mut self) { assert!( self.is_error(), "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", self.level ); self.level = Level::DelayedBug; - - self } - /// Adds a span/label to be included in the resulting snippet. + /// Appends a labeled span to the diagnostic. /// - /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic - /// was first built. That means it will be shown together with the original - /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods. + /// Labels are used to convey additional context for the diagnostic's primary span. They will + /// be shown together with the original diagnostic's span, *not* with spans added by + /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because + /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed + /// either. /// - /// This span is *not* considered a ["primary span"][`MultiSpan`]; only - /// the `Span` supplied when creating the diagnostic is primary. + /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when + /// the diagnostic was constructed. However, the label span is *not* considered a + /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is + /// primary. #[rustc_lint_diagnostics] pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self { self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); @@ -344,7 +350,7 @@ impl Diagnostic { pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self { let before = self.span.clone(); - self.set_span(after); + self.span(after); for span_label in before.span_labels() { if let Some(label) = span_label.label { if span_label.is_primary && keep_label { @@ -469,7 +475,7 @@ impl Diagnostic { /// Add a warning attached to this diagnostic. #[rustc_lint_diagnostics] pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { - self.sub(Level::Warning(None), msg, MultiSpan::new()); + self.sub(Level::Warning, msg, MultiSpan::new()); self } @@ -481,7 +487,7 @@ impl Diagnostic { sp: S, msg: impl Into<SubdiagnosticMessage>, ) -> &mut Self { - self.sub(Level::Warning(None), msg, sp.into()); + self.sub(Level::Warning, msg, sp.into()); self } @@ -876,7 +882,7 @@ impl Diagnostic { self } - pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { + pub fn span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); if let Some(span) = self.span.primary_span() { self.sort_span = span; @@ -884,7 +890,7 @@ impl Diagnostic { self } - pub fn set_is_lint(&mut self) -> &mut Self { + pub fn is_lint(&mut self) -> &mut Self { self.is_lint = true; self } @@ -903,7 +909,7 @@ impl Diagnostic { self.code.clone() } - pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self { + pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self { self.messages[0] = (msg.into(), Style::NoStyle); self } @@ -915,7 +921,7 @@ impl Diagnostic { self.args.iter() } - pub fn set_arg( + pub fn arg( &mut self, name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index ae54d343dad..a02909f29c4 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -30,57 +30,44 @@ where G: EmissionGuarantee, { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { - let mut diag = self.node.into_diagnostic(dcx, level); - diag.set_span(self.span); - diag + self.node.into_diagnostic(dcx, level).with_span(self.span) } } /// Used for emitting structured error messages and other diagnostic information. +/// Each constructed `DiagnosticBuilder` must be consumed by a function such as +/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a +/// `DiagnosticBuilder` is dropped without being consumed by one of these +/// functions. /// /// If there is some state in a downstream crate you would like to /// access in the methods of `DiagnosticBuilder` here, consider /// extending `DiagCtxtFlags`. #[must_use] -#[derive(Clone)] pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { - state: DiagnosticBuilderState<'a>, + pub dcx: &'a DiagCtxt, - /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a - /// return value, especially within the frequently-used `PResult` type. - /// In theory, return value optimization (RVO) should avoid unnecessary - /// copying. In practice, it does not (at the time of writing). - diagnostic: Box<Diagnostic>, + /// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is + /// consumed via `emit`, `cancel`, etc. At that point it is consumed and + /// replaced with `None`. Then `drop` checks that it is `None`; if not, it + /// panics because a diagnostic was built but not used. + /// + /// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is + /// often used as a return value, especially within the frequently-used + /// `PResult` type. In theory, return value optimization (RVO) should avoid + /// unnecessary copying. In practice, it does not (at the time of writing). + diag: Option<Box<Diagnostic>>, _marker: PhantomData<G>, } -#[derive(Clone)] -enum DiagnosticBuilderState<'a> { - /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`. - /// - /// The `Diagnostic` will be emitted through this `DiagCtxt`. - Emittable(&'a DiagCtxt), +// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted +// twice, which would be bad. +impl<G> !Clone for DiagnosticBuilder<'_, G> {} - /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`. - /// - /// The `Diagnostic` will be ignored when calling `.emit()`, and it can be - /// assumed that `.emit()` was previously called, to end up in this state. - /// - /// While this is also used by `.cancel()`, this state is only observed by - /// the `Drop` `impl` of `DiagnosticBuilder`, because `.cancel()` takes - /// `self` by-value specifically to prevent any attempts to `.emit()`. - /// - // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`, - // despite that being potentially lossy, if important information is added - // *after* the original `.emit()` call. - AlreadyEmittedOrDuringCancellation, -} - -// `DiagnosticBuilderState` should be pointer-sized. rustc_data_structures::static_assert_size!( - DiagnosticBuilderState<'_>, - std::mem::size_of::<&DiagCtxt>() + DiagnosticBuilder<'_, ()>, + 2 * std::mem::size_of::<usize>() ); /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" @@ -94,68 +81,50 @@ pub trait EmissionGuarantee: Sized { /// `impl` of `EmissionGuarantee`, to make it impossible to create a value /// of `Self::EmitResult` without actually performing the emission. #[track_caller] - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult; + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult; } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + /// Takes the diagnostic. For use by methods that consume the + /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the + /// only code that will be run on `self`. + fn take_diag(&mut self) -> Diagnostic { + Box::into_inner(self.diag.take().unwrap()) + } + /// Most `emit_producing_guarantee` functions use this as a starting point. - fn emit_producing_nothing(&mut self) { - match self.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - dcx.emit_diagnostic_without_consuming(&mut self.diagnostic); - } - // `.emit()` was previously called, disallowed from repeating it. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} - } + fn emit_producing_nothing(mut self) { + let diag = self.take_diag(); + self.dcx.emit_diagnostic(diag); + } + + /// `ErrorGuaranteed::emit_producing_guarantee` uses this. + // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. + fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { + let diag = self.take_diag(); + + // Only allow a guarantee if the `level` wasn't switched to a + // non-error. The field isn't `pub`, but the whole `Diagnostic` can be + // overwritten with a new one, thanks to `DerefMut`. + assert!( + diag.is_error(), + "emitted non-error ({:?}) diagnostic from `DiagnosticBuilder<ErrorGuaranteed>`", + diag.level, + ); + + let guar = self.dcx.emit_diagnostic(diag); + guar.unwrap() } } -// FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`. impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - // Contrast this with `emit_producing_nothing`. - match db.state { - // First `.emit()` call, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => { - db.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; - let guar = dcx.emit_diagnostic_without_consuming(&mut db.diagnostic); - - // Only allow a guarantee if the `level` wasn't switched to a - // non-error - the field isn't `pub`, but the whole `Diagnostic` - // can be overwritten with a new one, thanks to `DerefMut`. - assert!( - db.diagnostic.is_error(), - "emitted non-error ({:?}) diagnostic \ - from `DiagnosticBuilder<ErrorGuaranteed>`", - db.diagnostic.level, - ); - guar.unwrap() - } - // `.emit()` was previously called, disallowed from repeating it, - // but can take advantage of the previous `.emit()`'s guarantee - // still being applicable (i.e. as a form of idempotency). - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { - // Only allow a guarantee if the `level` wasn't switched to a - // non-error - the field isn't `pub`, but the whole `Diagnostic` - // can be overwritten with a new one, thanks to `DerefMut`. - assert!( - db.diagnostic.is_error(), - "`DiagnosticBuilder<ErrorGuaranteed>`'s diagnostic \ - became non-error ({:?}), after original `.emit()`", - db.diagnostic.level, - ); - #[allow(deprecated)] - ErrorGuaranteed::unchecked_claim_error_was_emitted() - } - } + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_error_guaranteed() } } -// FIXME(eddyb) should there be a `Option<ErrorGuaranteed>` impl as well? impl EmissionGuarantee for () { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); } } @@ -168,7 +137,7 @@ pub struct BugAbort; impl EmissionGuarantee for BugAbort { type EmitResult = !; - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); panic::panic_any(ExplicitBug); } @@ -182,37 +151,48 @@ pub struct FatalAbort; impl EmissionGuarantee for FatalAbort { type EmitResult = !; - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); crate::FatalError.raise() } } impl EmissionGuarantee for rustc_span::fatal_error::FatalError { - fn emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { db.emit_producing_nothing(); rustc_span::fatal_error::FatalError } } -/// In general, the `DiagnosticBuilder` uses deref to allow access to -/// the fields and methods of the embedded `diagnostic` in a -/// transparent way. *However,* many of the methods are intended to -/// be used in a chained way, and hence ought to return `self`. In -/// that case, we can't just naively forward to the method on the -/// `diagnostic`, because the return type would be a `&Diagnostic` -/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes -/// it easy to declare such methods on the builder. +/// `DiagnosticBuilder` impls `DerefMut`, which allows access to the fields and +/// methods of the embedded `Diagnostic`. However, that doesn't allow method +/// chaining at the `DiagnosticBuilder` level. Each use of this macro defines +/// two builder methods at that level, both of which wrap the equivalent method +/// in `Diagnostic`. +/// - A `&mut self -> &mut Self` method, with the same name as the underlying +/// `Diagnostic` method. It is mostly to modify existing diagnostics, either +/// in a standalone fashion, e.g. `err.code(code)`, or in a chained fashion +/// to make multiple modifications, e.g. `err.code(code).span(span)`. +/// - A `self -> Self` method, which has a `with_` prefix added. +/// It is mostly used in a chained fashion when producing a new diagnostic, +/// e.g. `let err = struct_err(msg).with_code(code)`, or when emitting a new +/// diagnostic , e.g. `struct_err(msg).with_code(code).emit()`. +/// +/// Although the latter method can be used to modify an existing diagnostic, +/// e.g. `err = err.with_code(code)`, this should be avoided because the former +/// method gives shorter code, e.g. `err.code(code)`. macro_rules! forward { - // Forward pattern for &mut self -> &mut Self ( - $(#[$attrs:meta])* - pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self + ($f:ident, $with_f:ident)($($name:ident: $ty:ty),* $(,)?) ) => { - $(#[$attrs])* - #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] - pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { - self.diagnostic.$n($($name),*); + #[doc = concat!("See [`Diagnostic::", stringify!($f), "()`].")] + pub fn $f(&mut self, $($name: $ty),*) -> &mut Self { + self.diag.as_mut().unwrap().$f($($name),*); + self + } + #[doc = concat!("See [`Diagnostic::", stringify!($f), "()`].")] + pub fn $with_f(mut self, $($name: $ty),*) -> Self { + self.diag.as_mut().unwrap().$f($($name),*); self } }; @@ -222,13 +202,13 @@ impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> { type Target = Diagnostic; fn deref(&self) -> &Diagnostic { - &self.diagnostic + self.diag.as_ref().unwrap() } } impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> { fn deref_mut(&mut self) -> &mut Diagnostic { - &mut self.diagnostic + self.diag.as_mut().unwrap() } } @@ -242,20 +222,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diagnostic: Diagnostic) -> Self { + pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self { debug!("Created new diagnostic"); - Self { - state: DiagnosticBuilderState::Emittable(dcx), - diagnostic: Box::new(diagnostic), - _marker: PhantomData, - } + Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } } - /// Emit the diagnostic. Does not consume `self`, which may be surprising, - /// but there are various places that rely on continuing to use `self` - /// after calling `emit`. + /// Emit and consume the diagnostic. #[track_caller] - pub fn emit(&mut self) -> G::EmitResult { + pub fn emit(self) -> G::EmitResult { G::emit_producing_guarantee(self) } @@ -264,21 +238,17 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// /// See `emit` and `delay_as_bug` for details. #[track_caller] - pub fn emit_unless(&mut self, delay: bool) -> G::EmitResult { + pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { if delay { self.downgrade_to_delayed_bug(); } self.emit() } - /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or /// cancelled or it will panic when dropped). - /// - /// This method takes `self` by-value to disallow calling `.emit()` on it, - /// which may be expected to *guarantee* the emission of an error, either - /// at the time of the call, or through a prior `.emit()` call. pub fn cancel(mut self) { - self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + self.diag = None; drop(self); } @@ -294,44 +264,20 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { } /// Converts the builder to a `Diagnostic` for later emission, - /// unless dcx has disabled such buffering, or `.emit()` was called. - pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> { - let dcx = match self.state { - // No `.emit()` calls, the `&DiagCtxt` is still available. - DiagnosticBuilderState::Emittable(dcx) => dcx, - // `.emit()` was previously called, nothing we can do. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { - return None; - } - }; - - if dcx.inner.lock().flags.dont_buffer_diagnostics - || dcx.inner.lock().flags.treat_err_as_bug.is_some() - { + /// unless dcx has disabled such buffering. + fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> { + if self.dcx.inner.lock().flags.treat_err_as_bug.is_some() { self.emit(); return None; } - // Take the `Diagnostic` by replacing it with a dummy. - let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::from("")); - let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy); - - // Disable the ICE on `Drop`. - self.cancel(); + let diag = self.take_diag(); // Logging here is useful to help track down where in logs an error was // actually emitted. - debug!("buffer: diagnostic={:?}", diagnostic); + debug!("buffer: diag={:?}", diag); - Some((diagnostic, dcx)) - } - - /// Retrieves the [`DiagCtxt`] if available - pub fn dcx(&self) -> Option<&DiagCtxt> { - match self.state { - DiagnosticBuilderState::Emittable(dcx) => Some(dcx), - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None, - } + Some((diag, self.dcx)) } /// Buffers the diagnostic for later emission, @@ -351,207 +297,173 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// In the meantime, though, callsites are required to deal with the "bug" /// locally in whichever way makes the most sense. #[track_caller] - pub fn delay_as_bug(&mut self) -> G::EmitResult { + pub fn delay_as_bug(mut self) -> G::EmitResult { self.downgrade_to_delayed_bug(); self.emit() } - forward!( - #[track_caller] - pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self - ); - - forward!( - /// Appends a labeled span to the diagnostic. - /// - /// Labels are used to convey additional context for the diagnostic's primary span. They will - /// be shown together with the original diagnostic's span, *not* with spans added by - /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because - /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed - /// either. - /// - /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when - /// the diagnostic was constructed. However, the label span is *not* considered a - /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is - /// primary. - pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self); - - forward!( - /// Labels all the given spans with the provided label. - /// See [`Diagnostic::span_label()`] for more information. - pub fn span_labels( - &mut self, + forward!((span_label, with_span_label)( + span: Span, + label: impl Into<SubdiagnosticMessage>, + )); + forward!((span_labels, with_span_labels)( spans: impl IntoIterator<Item = Span>, label: &str, - ) -> &mut Self); - - forward!(pub fn note_expected_found( - &mut self, + )); + forward!((note_expected_found, with_note_expected_found)( expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, found_label: &dyn fmt::Display, found: DiagnosticStyledString, - ) -> &mut Self); - - forward!(pub fn note_expected_found_extra( - &mut self, + )); + forward!((note_expected_found_extra, with_note_expected_found_extra)( expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, found_label: &dyn fmt::Display, found: DiagnosticStyledString, expected_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display, - ) -> &mut Self); - - forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); - forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); - forward!(pub fn span_note( - &mut self, + )); + forward!((note, with_note)( + msg: impl Into<SubdiagnosticMessage>, + )); + forward!((note_once, with_note_once)( + msg: impl Into<SubdiagnosticMessage>, + )); + forward!((span_note, with_span_note)( sp: impl Into<MultiSpan>, msg: impl Into<SubdiagnosticMessage>, - ) -> &mut Self); - forward!(pub fn span_note_once( - &mut self, + )); + forward!((span_note_once, with_span_note_once)( sp: impl Into<MultiSpan>, msg: impl Into<SubdiagnosticMessage>, - ) -> &mut Self); - forward!(pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); - forward!(pub fn span_warn( - &mut self, + )); + forward!((warn, with_warn)( + msg: impl Into<SubdiagnosticMessage>, + )); + forward!((span_warn, with_span_warn)( sp: impl Into<MultiSpan>, msg: impl Into<SubdiagnosticMessage>, - ) -> &mut Self); - forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); - forward!(pub fn help_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); - forward!(pub fn span_help( - &mut self, + )); + forward!((help, with_help)( + msg: impl Into<SubdiagnosticMessage>, + )); + forward!((help_once, with_help_once)( + msg: impl Into<SubdiagnosticMessage>, + )); + forward!((span_help, with_span_help_once)( sp: impl Into<MultiSpan>, msg: impl Into<SubdiagnosticMessage>, - ) -> &mut Self); - forward!(pub fn set_is_lint(&mut self,) -> &mut Self); - - forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); - - forward!(pub fn multipart_suggestion( - &mut self, + )); + forward!((multipart_suggestion, with_multipart_suggestion)( msg: impl Into<SubdiagnosticMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn multipart_suggestion_verbose( - &mut self, + )); + forward!((multipart_suggestion_verbose, with_multipart_suggestion_verbose)( msg: impl Into<SubdiagnosticMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn tool_only_multipart_suggestion( - &mut self, + )); + forward!((tool_only_multipart_suggestion, with_tool_only_multipart_suggestion)( msg: impl Into<SubdiagnosticMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion( - &mut self, + )); + forward!((span_suggestion, with_span_suggestion)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestions( - &mut self, + )); + forward!((span_suggestions, with_span_suggestions)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestions: impl IntoIterator<Item = String>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn multipart_suggestions( - &mut self, + )); + forward!((multipart_suggestions, with_multipart_suggestions)( msg: impl Into<SubdiagnosticMessage>, suggestions: impl IntoIterator<Item = Vec<(Span, String)>>, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_short( - &mut self, + )); + forward!((span_suggestion_short, with_span_suggestion_short)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_verbose( - &mut self, + )); + forward!((span_suggestion_verbose, with_span_suggestion_verbose)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn span_suggestion_hidden( - &mut self, + )); + forward!((span_suggestion_hidden, with_span_suggestion_hidden)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - forward!(pub fn tool_only_span_suggestion( - &mut self, + )); + forward!((tool_only_span_suggestion, with_tool_only_span_suggestion)( sp: Span, msg: impl Into<SubdiagnosticMessage>, suggestion: impl ToString, applicability: Applicability, - ) -> &mut Self); - - forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self); - forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self); - forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); - forward!(pub fn set_arg( - &mut self, - name: impl Into<Cow<'static, str>>, - arg: impl IntoDiagnosticArg, - ) -> &mut Self); - - forward!(pub fn subdiagnostic( - &mut self, - subdiagnostic: impl crate::AddToDiagnostic - ) -> &mut Self); + )); + forward!((primary_message, with_primary_message)( + msg: impl Into<DiagnosticMessage>, + )); + forward!((span, with_span)( + sp: impl Into<MultiSpan>, + )); + forward!((code, with_code)( + s: DiagnosticId, + )); + forward!((arg, with_arg)( + name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg, + )); + forward!((subdiagnostic, with_subdiagnostic)( + subdiagnostic: impl crate::AddToDiagnostic, + )); + forward!((eager_subdiagnostic, with_eager_subdiagnostic)( + dcx: &DiagCtxt, + subdiagnostic: impl crate::AddToDiagnostic, + )); } impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diagnostic.fmt(f) + self.diag.fmt(f) } } -/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled -/// or we emit a bug. +/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted, +/// cancelled, etc.) or we emit a bug. impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> { fn drop(&mut self) { - match self.state { - // No `.emit()` or `.cancel()` calls. - DiagnosticBuilderState::Emittable(dcx) => { - if !panicking() { - dcx.emit_diagnostic(Diagnostic::new( - Level::Bug, - DiagnosticMessage::from( - "the following error was constructed but not emitted", - ), - )); - dcx.emit_diagnostic_without_consuming(&mut self.diagnostic); - panic!("error was constructed but not emitted"); - } + match self.diag.take() { + Some(diag) if !panicking() => { + self.dcx.emit_diagnostic(Diagnostic::new( + Level::Bug, + DiagnosticMessage::from("the following error was constructed but not emitted"), + )); + self.dcx.emit_diagnostic(*diag); + panic!("error was constructed but not emitted"); } - // `.emit()` was previously called, or maybe we're during `.cancel()`. - DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + _ => {} } } } #[macro_export] -macro_rules! struct_span_err { +macro_rules! struct_span_code_err { ($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({ - $dcx.struct_span_err_with_code( + $dcx.struct_span_err( $span, format!($($message)*), - $crate::error_code!($code), ) + .with_code($crate::error_code!($code)) }) } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 29cb304e8b5..39252dea283 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -249,60 +249,43 @@ impl<Id> IntoDiagnosticArg for hir::def::Res<Id> { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> { fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { - let mut diag; match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { - diag = - DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space); - diag.set_arg("addr_space", addr_space); - diag.set_arg("cause", cause); - diag.set_arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_address_space) + .with_arg("addr_space", addr_space) + .with_arg("cause", cause) + .with_arg("err", err) } TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits); - diag.set_arg("kind", kind); - diag.set_arg("bit", bit); - diag.set_arg("cause", cause); - diag.set_arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits) + .with_arg("kind", kind) + .with_arg("bit", bit) + .with_arg("cause", cause) + .with_arg("err", err) } TargetDataLayoutErrors::MissingAlignment { cause } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment); - diag.set_arg("cause", cause); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment) + .with_arg("cause", cause) } TargetDataLayoutErrors::InvalidAlignment { cause, err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment); - diag.set_arg("cause", cause); - diag.set_arg("err_kind", err.diag_ident()); - diag.set_arg("align", err.align()); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_alignment) + .with_arg("cause", cause) + .with_arg("err_kind", err.diag_ident()) + .with_arg("align", err.align()) } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { - diag = DiagnosticBuilder::new( - dcx, - level, - fluent::errors_target_inconsistent_architecture, - ); - diag.set_arg("dl", dl); - diag.set_arg("target", target); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_inconsistent_architecture) + .with_arg("dl", dl) + .with_arg("target", target) } TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { - diag = DiagnosticBuilder::new( - dcx, - level, - fluent::errors_target_inconsistent_pointer_width, - ); - diag.set_arg("pointer_size", pointer_size); - diag.set_arg("target", target); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_inconsistent_pointer_width) + .with_arg("pointer_size", pointer_size) + .with_arg("target", target) } TargetDataLayoutErrors::InvalidBitsSize { err } => { - diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size); - diag.set_arg("err", err); - diag + DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size) + .with_arg("err", err) } } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 546159c9d13..987832e6937 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -61,13 +61,13 @@ impl HumanReadableErrorType { self, mut dst: Box<dyn WriteColor + Send>, fallback_bundle: LazyFallbackBundle, - ) -> EmitterWriter { + ) -> HumanEmitter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); if !dst.supports_color() && color { dst = Box::new(Ansi::new(dst)); } - EmitterWriter::new(dst, fallback_bundle).short_message(short) + HumanEmitter::new(dst, fallback_bundle).short_message(short) } } @@ -196,13 +196,15 @@ pub trait Emitter: Translate { fn emit_diagnostic(&mut self, diag: &Diagnostic); /// Emit a notification that an artifact has been output. - /// This is currently only supported for the JSON format, - /// other formats can, and will, simply ignore it. + /// Currently only supported for the JSON format. fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} + /// Emit a report about future breakage. + /// Currently only supported for the JSON format. fn emit_future_breakage_report(&mut self, _diags: Vec<Diagnostic>) {} - /// Emit list of unused externs + /// Emit list of unused externs. + /// Currently only supported for the JSON format. fn emit_unused_externs( &mut self, _lint_level: rustc_lint_defs::Level, @@ -501,7 +503,7 @@ pub trait Emitter: Translate { } } -impl Translate for EmitterWriter { +impl Translate for HumanEmitter { fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> { self.fluent_bundle.as_ref() } @@ -511,7 +513,7 @@ impl Translate for EmitterWriter { } } -impl Emitter for EmitterWriter { +impl Emitter for HumanEmitter { fn source_map(&self) -> Option<&Lrc<SourceMap>> { self.sm.as_ref() } @@ -622,7 +624,7 @@ impl ColorConfig { /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` #[derive(Setters)] -pub struct EmitterWriter { +pub struct HumanEmitter { #[setters(skip)] dst: IntoDynSyncSend<Destination>, sm: Option<Lrc<SourceMap>>, @@ -647,14 +649,14 @@ pub struct FileWithAnnotatedLines { multiline_depth: usize, } -impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { +impl HumanEmitter { + pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> HumanEmitter { let dst = from_stderr(color_config); Self::create(dst, fallback_bundle) } - fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { - EmitterWriter { + fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter { + HumanEmitter { dst: IntoDynSyncSend(dst), sm: None, fluent_bundle: None, @@ -673,7 +675,7 @@ impl EmitterWriter { pub fn new( dst: Box<dyn WriteColor + Send>, fallback_bundle: LazyFallbackBundle, - ) -> EmitterWriter { + ) -> HumanEmitter { Self::create(dst, fallback_bundle) } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 52fcb50e9fb..87bf9c23456 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -198,7 +198,7 @@ impl Emitter for JsonEmitter { .into_iter() .map(|mut diag| { if diag.level == crate::Level::Allow { - diag.level = crate::Level::Warning(None); + diag.level = crate::Level::Warning; } FutureBreakageItem { diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e9507dcfed7..8fb539fc358 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,9 +7,11 @@ #![feature(rustdoc_internals)] #![feature(array_windows)] #![feature(associated_type_defaults)] +#![feature(box_into_inner)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(yeet_expr)] @@ -53,7 +55,7 @@ pub use snippet::Style; pub use termcolor::{Color, ColorSpec, WriteColor}; use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; -use emitter::{is_case_difference, DynEmitter, Emitter, EmitterWriter}; +use emitter::{is_case_difference, DynEmitter, Emitter, HumanEmitter}; use registry::Registry; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; @@ -418,6 +420,7 @@ pub struct DiagCtxt { /// as well as inconsistent state observation. struct DiagCtxtInner { flags: DiagCtxtFlags, + /// The number of lint errors that have been emitted. lint_err_count: usize, /// The number of errors that have been emitted, including duplicates. @@ -425,8 +428,13 @@ struct DiagCtxtInner { /// This is not necessarily the count that's reported to the user once /// compilation ends. err_count: usize, - warn_count: usize, deduplicated_err_count: usize, + /// The warning count, used for a recap upon finishing + deduplicated_warn_count: usize, + /// Has this diagnostic context printed any diagnostics? (I.e. has + /// `self.emitter.emit_diagnostic()` been called? + has_printed: bool, + emitter: Box<DynEmitter>, span_delayed_bugs: Vec<DelayedDiagnostic>, good_path_delayed_bugs: Vec<DelayedDiagnostic>, @@ -453,9 +461,6 @@ struct DiagCtxtInner { /// When `.abort_if_errors()` is called, these are also emitted. stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>, - /// The warning count, used for a recap upon finishing - deduplicated_warn_count: usize, - future_breakage_diagnostics: Vec<Diagnostic>, /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is @@ -507,11 +512,11 @@ pub enum StashKey { Cycle, } -fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { - (*f)(d) +fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { + (*f)(diag) } -pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> = +pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> = AtomicRef::new(&(default_track_diagnostic as _)); #[derive(Copy, Clone, Default)] @@ -522,12 +527,6 @@ pub struct DiagCtxtFlags { /// If Some, the Nth error-level diagnostic is upgraded to bug-level. /// (rustc: see `-Z treat-err-as-bug`) pub treat_err_as_bug: Option<NonZeroUsize>, - /// If true, immediately emit diagnostics that would otherwise be buffered. - /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`) - pub dont_buffer_diagnostics: bool, - /// If true, immediately print bugs registered with `span_delayed_bug`. - /// (rustc: see `-Z report-delayed-bugs`) - pub report_delayed_bugs: bool, /// Show macro backtraces. /// (rustc: see `-Z macro-backtrace`) pub macro_backtrace: bool, @@ -551,8 +550,7 @@ impl Drop for DiagCtxtInner { // instead of "require some error happened". Sadly that isn't ideal, as // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. - let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0; - if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() { + if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); self.flush_delayed( bugs, @@ -574,7 +572,7 @@ impl DiagCtxt { sm: Option<Lrc<SourceMap>>, fallback_bundle: LazyFallbackBundle, ) -> Self { - let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm)); + let emitter = Box::new(HumanEmitter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm)); Self::with_emitter(emitter) } pub fn disable_warnings(mut self) -> Self { @@ -598,9 +596,9 @@ impl DiagCtxt { flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() }, lint_err_count: 0, err_count: 0, - warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, + has_printed: false, emitter, span_delayed_bugs: Vec::new(), good_path_delayed_bugs: Vec::new(), @@ -651,10 +649,11 @@ impl DiagCtxt { /// the overall count of emitted error diagnostics. pub fn reset_err_count(&self) { let mut inner = self.inner.borrow_mut(); + inner.lint_err_count = 0; inner.err_count = 0; - inner.warn_count = 0; inner.deduplicated_err_count = 0; inner.deduplicated_warn_count = 0; + inner.has_printed = false; // actually free the underlying memory (which `clear` would not do) inner.span_delayed_bugs = Default::default(); @@ -673,16 +672,11 @@ impl DiagCtxt { let key = (span.with_parent(None), key); if diag.is_error() { - if matches!(diag.level, Error { lint: true }) { + if diag.is_lint { inner.lint_err_count += 1; } else { inner.err_count += 1; } - } else { - // Warnings are only automatically flushed if they're forced. - if diag.is_force_warn() { - inner.warn_count += 1; - } } // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic @@ -697,15 +691,11 @@ impl DiagCtxt { let key = (span.with_parent(None), key); let diag = inner.stashed_diagnostics.remove(&key)?; if diag.is_error() { - if matches!(diag.level, Error { lint: true }) { + if diag.is_lint { inner.lint_err_count -= 1; } else { inner.err_count -= 1; } - } else { - if diag.is_force_warn() { - inner.warn_count -= 1; - } } Some(DiagnosticBuilder::new_diagnostic(self, diag)) } @@ -731,24 +721,7 @@ impl DiagCtxt { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_warn(msg); - result.set_span(span); - result - } - - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// Also include a code. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_warn_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_span_warn(span, msg); - result.code(code); - result + self.struct_warn(msg).with_span(span) } /// Construct a builder at the `Warning` level with the `msg`. @@ -759,7 +732,7 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Warning(None), msg) + DiagnosticBuilder::new(self, Warning, msg) } /// Construct a builder at the `Allow` level with the `msg`. @@ -788,23 +761,7 @@ impl DiagCtxt { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_err(msg); - result.set_span(span); - result - } - - /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_err_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_span_err(span, msg); - result.code(code); - result + self.struct_err(msg).with_span(span) } /// Construct a builder at the `Error` level with the `msg`. @@ -812,33 +769,7 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Error { lint: false }, msg) - } - - /// Construct a builder at the `Error` level with the `msg` and the `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_err_with_code( - &self, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_err(msg); - result.code(code); - result - } - - /// Construct a builder at the `Warn` level with the `msg` and the `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_warn_with_code( - &self, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, ()> { - let mut result = self.struct_warn(msg); - result.code(code); - result + DiagnosticBuilder::new(self, Error, msg) } /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. @@ -849,23 +780,7 @@ impl DiagCtxt { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, FatalAbort> { - let mut result = self.struct_fatal(msg); - result.set_span(span); - result - } - - /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_fatal_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> DiagnosticBuilder<'_, FatalAbort> { - let mut result = self.struct_span_fatal(span, msg); - result.code(code); - result + self.struct_fatal(msg).with_span(span) } /// Construct a builder at the `Fatal` level with the `msg`. @@ -878,16 +793,6 @@ impl DiagCtxt { DiagnosticBuilder::new(self, Fatal, msg) } - /// Construct a builder at the `Fatal` level with the `msg`, that doesn't abort. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_almost_fatal( - &self, - msg: impl Into<DiagnosticMessage>, - ) -> DiagnosticBuilder<'_, FatalError> { - DiagnosticBuilder::new(self, Fatal, msg) - } - /// Construct a builder at the `Help` level with the `msg`. #[rustc_lint_diagnostics] pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { @@ -916,9 +821,7 @@ impl DiagCtxt { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, BugAbort> { - let mut result = self.struct_bug(msg); - result.set_span(span); - result + self.struct_bug(msg).with_span(span) } #[rustc_lint_diagnostics] @@ -929,17 +832,6 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] - pub fn span_fatal_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> ! { - self.struct_span_fatal_with_code(span, msg, code).emit() - } - - #[rustc_lint_diagnostics] - #[track_caller] pub fn span_err( &self, span: impl Into<MultiSpan>, @@ -950,32 +842,10 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] - pub fn span_err_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) -> ErrorGuaranteed { - self.struct_span_err_with_code(span, msg, code).emit() - } - - #[rustc_lint_diagnostics] - #[track_caller] pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) { self.struct_span_warn(span, msg).emit() } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_warn_with_code( - &self, - span: impl Into<MultiSpan>, - msg: impl Into<DiagnosticMessage>, - code: DiagnosticId, - ) { - self.struct_span_warn_with_code(span, msg, code).emit() - } - pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! { self.struct_span_bug(span, msg).emit() } @@ -989,10 +859,16 @@ impl DiagCtxt { /// For example, it can be used to create an [`ErrorGuaranteed`] /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission /// directly). - /// - /// If no span is available, use [`DUMMY_SP`]. - /// - /// [`DUMMY_SP`]: rustc_span::DUMMY_SP + #[track_caller] + pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { + let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug(); + if treat_next_err_as_bug { + self.bug(msg); + } + DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit() + } + + /// Like `delayed_bug`, but takes an additional span. /// /// Note: this function used to be called `delay_span_bug`. It was renamed /// to match similar functions like `span_err`, `span_warn`, etc. @@ -1004,23 +880,16 @@ impl DiagCtxt { ) -> ErrorGuaranteed { let treat_next_err_as_bug = self.inner.borrow().treat_next_err_as_bug(); if treat_next_err_as_bug { - // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } - let mut diagnostic = Diagnostic::new(DelayedBug, msg); - diagnostic.set_span(sp); - self.emit_diagnostic(diagnostic).unwrap() + DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit() } // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's // where the explanation of what "good path" is (also, it should be renamed). pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { let mut inner = self.inner.borrow_mut(); - - let mut diagnostic = Diagnostic::new(DelayedBug, msg); - if inner.flags.report_delayed_bugs { - inner.emit_diagnostic_without_consuming(&mut diagnostic); - } + let diagnostic = Diagnostic::new(DelayedBug, msg); let backtrace = std::backtrace::Backtrace::capture(); inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } @@ -1038,9 +907,7 @@ impl DiagCtxt { span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()> { - let mut db = DiagnosticBuilder::new(self, Note, msg); - db.set_span(span); - db + DiagnosticBuilder::new(self, Note, msg).with_span(span) } #[rustc_lint_diagnostics] @@ -1132,7 +999,7 @@ impl DiagCtxt { (0, 0) => return, (0, _) => inner .emitter - .emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))), + .emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))), (_, 0) => { inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); } @@ -1202,17 +1069,8 @@ impl DiagCtxt { self.inner.borrow_mut().emitter.emit_diagnostic(&db); } - pub fn emit_diagnostic(&self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> { - self.emit_diagnostic_without_consuming(&mut diagnostic) - } - - // It's unfortunate this exists. `emit_diagnostic` is preferred, because it - // consumes the diagnostic, thus ensuring it is emitted just once. - pub(crate) fn emit_diagnostic_without_consuming( - &self, - diagnostic: &mut Diagnostic, - ) -> Option<ErrorGuaranteed> { - self.inner.borrow_mut().emit_diagnostic_without_consuming(diagnostic) + pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> { + self.inner.borrow_mut().emit_diagnostic(diagnostic) } #[track_caller] @@ -1222,20 +1080,20 @@ impl DiagCtxt { #[track_caller] pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { - err.into_diagnostic(self, Error { lint: false }) + err.into_diagnostic(self, Error) } #[track_caller] - pub fn create_warning<'a>( + pub fn create_warn<'a>( &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self, Warning(None)) + warning.into_diagnostic(self, Warning) } #[track_caller] - pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { - self.create_warning(warning).emit() + pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { + self.create_warn(warning).emit() } #[track_caller] @@ -1367,7 +1225,7 @@ impl DiagCtxt { // Note: we prefer implementing operations on `DiagCtxt`, rather than // `DiagCtxtInner`, whenever possible. This minimizes functions where // `DiagCtxt::foo()` just borrows `inner` and forwards a call to -// `HanderInner::foo`. +// `DiagCtxtInner::foo`. impl DiagCtxtInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> { @@ -1377,21 +1235,17 @@ impl DiagCtxtInner { for diag in diags { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - if matches!(diag.level, Error { lint: true }) { + if diag.is_lint { self.lint_err_count -= 1; } else { self.err_count -= 1; } } else { - if diag.is_force_warn() { - self.warn_count -= 1; - } else { - // Unless they're forced, don't flush stashed warnings when - // there are errors, to avoid causing warning overload. The - // stash would've been stolen already if it were important. - if has_errors { - continue; - } + // Unless they're forced, don't flush stashed warnings when + // there are errors, to avoid causing warning overload. The + // stash would've been stolen already if it were important. + if !diag.is_force_warn() && has_errors { + continue; } } let reported_this = self.emit_diagnostic(diag); @@ -1401,14 +1255,7 @@ impl DiagCtxtInner { } fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> { - self.emit_diagnostic_without_consuming(&mut diagnostic) - } - - fn emit_diagnostic_without_consuming( - &mut self, - diagnostic: &mut Diagnostic, - ) -> Option<ErrorGuaranteed> { - if matches!(diagnostic.level, Error { .. } | Fatal) && self.treat_err_as_bug() { + if matches!(diagnostic.level, Error | Fatal) && self.treat_err_as_bug() { diagnostic.level = Bug; } @@ -1430,10 +1277,8 @@ impl DiagCtxtInner { self.span_delayed_bugs .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - if !self.flags.report_delayed_bugs { - #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); - } + #[allow(deprecated)] + return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } if diagnostic.has_future_breakage() { @@ -1449,23 +1294,20 @@ impl DiagCtxtInner { self.fulfilled_expectations.insert(expectation_id.normalize()); } - if matches!(diagnostic.level, Warning(_)) - && !self.flags.can_emit_warnings - && !diagnostic.is_force_warn() - { + if diagnostic.level == Warning && !self.flags.can_emit_warnings { if diagnostic.has_future_breakage() { - (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {}); + (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); } return None; } if matches!(diagnostic.level, Expect(_) | Allow) { - (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {}); + (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); return None; } let mut guaranteed = None; - (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| { + (*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| { if let Some(ref code) = diagnostic.code { self.emitted_diagnostic_codes.insert(code.clone()); } @@ -1501,15 +1343,16 @@ impl DiagCtxtInner { ); } - self.emitter.emit_diagnostic(diagnostic); + self.emitter.emit_diagnostic(&diagnostic); if diagnostic.is_error() { self.deduplicated_err_count += 1; - } else if let Warning(_) = diagnostic.level { + } else if matches!(diagnostic.level, ForceWarning(_) | Warning) { self.deduplicated_warn_count += 1; } + self.has_printed = true; } if diagnostic.is_error() { - if matches!(diagnostic.level, Error { lint: true }) { + if diagnostic.is_lint { self.bump_lint_err_count(); } else { self.bump_err_count(); @@ -1519,8 +1362,6 @@ impl DiagCtxtInner { { guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } - } else { - self.bump_warn_count(); } }); @@ -1616,10 +1457,6 @@ impl DiagCtxtInner { self.panic_if_treat_err_as_bug(); } - fn bump_warn_count(&mut self) { - self.warn_count += 1; - } - fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { match ( @@ -1698,27 +1535,26 @@ pub enum Level { /// internal overflows, some file operation errors. /// /// Its `EmissionGuarantee` is `FatalAbort`, except in the non-aborting "almost fatal" case - /// that is occasionaly used, where it is `FatalError`. + /// that is occasionally used, where it is `FatalError`. Fatal, /// An error in the code being compiled, which prevents compilation from finishing. This is the /// most common case. /// /// Its `EmissionGuarantee` is `ErrorGuaranteed`. - Error { - /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is - /// called. - lint: bool, - }, + Error, - /// A warning about the code being compiled. Does not prevent compilation from finishing. + /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation + /// from finishing. /// - /// This [`LintExpectationId`] is used for expected lint diagnostics, which should - /// also emit a warning due to the `force-warn` flag. In all other cases this should - /// be `None`. + /// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this + /// should be `None`. + ForceWarning(Option<LintExpectationId>), + + /// A warning about the code being compiled. Does not prevent compilation from finishing. /// /// Its `EmissionGuarantee` is `()`. - Warning(Option<LintExpectationId>), + Warning, /// A message giving additional context. Rare, because notes are more commonly attached to other /// diagnostics such as errors. @@ -1768,10 +1604,10 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | DelayedBug | Fatal | Error { .. } => { + Bug | DelayedBug | Fatal | Error => { spec.set_fg(Some(Color::Red)).set_intense(true); } - Warning(_) => { + ForceWarning(_) | Warning => { spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows)); } Note | OnceNote => { @@ -1789,8 +1625,8 @@ impl Level { pub fn to_str(self) -> &'static str { match self { Bug | DelayedBug => "error: internal compiler error", - Fatal | Error { .. } => "error", - Warning(_) => "warning", + Fatal | Error => "error", + ForceWarning(_) | Warning => "warning", Note | OnceNote => "note", Help | OnceHelp => "help", FailureNote => "failure-note", @@ -1804,7 +1640,7 @@ impl Level { pub fn get_expectation_id(&self) -> Option<LintExpectationId> { match self { - Expect(id) | Warning(Some(id)) => Some(*id), + Expect(id) | ForceWarning(Some(id)) => Some(*id), _ => None, } } diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 9189a501aa5..63247f9d051 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -9,7 +9,6 @@ doctest = false [dependencies] # tidy-alphabetical-start -crossbeam-channel = "0.5.0" rustc_ast = { path = "../rustc_ast" } rustc_ast_passes = { path = "../rustc_ast_passes" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 8b5a22d1914..e87f2306bc7 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1232,7 +1232,7 @@ pub fn expr_to_string( ) -> Option<(Symbol, ast::StrStyle)> { expr_to_spanned_string(cx, expr, err_msg) .map_err(|err| { - err.map(|(mut err, _)| { + err.map(|(err, _)| { err.emit(); }) }) @@ -1254,7 +1254,7 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> { match p.parse_expr() { Ok(e) => return Some(e), - Err(mut err) => { + Err(err) => { err.emit(); } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2283a3bfc76..d015d779963 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -362,7 +362,7 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) { let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { Ok(meta_item) => meta_item, - Err(mut err) => { + Err(err) => { err.emit(); return (true, None); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 676f9f17976..c39a3dce34e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -735,7 +735,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment_kind.expect_from_annotatables(items) } } - Err(mut err) => { + Err(err) => { err.emit(); fragment_kind.dummy(span) } @@ -855,7 +855,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(mut err) => { if err.span.is_dummy() { - err.set_span(span); + err.span(span); } annotate_err_with_kind(&mut err, kind, span); err.emit(); diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 2746e888b8d..eec86c36aed 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -180,7 +180,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.dcx().struct_span_err(span, msg.clone()).emit(); + self.cx.dcx().span_err(span, msg.clone()); self.result = Some(DummyResult::any(span)); } ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index b248a1fe349..ac5136539c3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -679,8 +679,8 @@ impl TtParser { // We use the span of the metavariable declaration to determine any // edition-specific matching behavior for non-terminals. let nt = match parser.to_mut().parse_nonterminal(kind) { - Err(mut err) => { - let guarantee = err.span_label( + Err(err) => { + let guarantee = err.with_span_label( span, format!( "while parsing argument for this `{kind}` macro fragment" diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e9736d6f2c8..a56c980791a 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -10,7 +10,7 @@ use crate::mbe::transcribe::transcribe; use rustc_ast as ast; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; @@ -213,45 +213,14 @@ fn expand_macro<'cx>( let arm_span = rhses[i].span(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { + let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { Ok(tts) => tts, - Err(mut err) => { + Err(err) => { err.emit(); return DummyResult::any(arm_span); } }; - // Replace all the tokens for the corresponding positions in the macro, to maintain - // proper positions in error reporting, while maintaining the macro_backtrace. - if tts.len() == rhs.tts.len() { - tts = tts.map_enumerated_owned(|i, mut tt| { - let rhs_tt = &rhs.tts[i]; - let ctxt = tt.span().ctxt(); - match (&mut tt, rhs_tt) { - // preserve the delim spans if able - ( - TokenTree::Delimited(target_sp, ..), - mbe::TokenTree::Delimited(source_sp, ..), - ) => { - target_sp.open = source_sp.open.with_ctxt(ctxt); - target_sp.close = source_sp.close.with_ctxt(ctxt); - } - ( - TokenTree::Delimited(target_sp, ..), - mbe::TokenTree::MetaVar(source_sp, ..), - ) => { - target_sp.open = source_sp.with_ctxt(ctxt); - target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi(); - } - _ => { - let sp = rhs_tt.span().with_ctxt(ctxt); - tt.set_span(sp); - } - } - tt - }); - } - if cx.trace_macros() { let msg = format!("to `{}`", pprust::tts_to_string(&tts)); trace_macros_note(&mut cx.expansions, sp, msg); @@ -489,7 +458,7 @@ pub fn compile_declarative_macro( return dummy_syn_ext(); } Error(sp, msg) => { - sess.dcx().struct_span_err(sp.substitute_dummy(def.span), msg).emit(); + sess.dcx().span_err(sp.substitute_dummy(def.span), msg); return dummy_syn_ext(); } ErrorReported(_) => { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 445be01bc97..889f43ed203 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -72,7 +72,7 @@ pub(super) fn parse( // `SyntaxContext::root()` from a foreign crate will // have the edition of that crate (which we manually // retrieve via the `edition` parameter). - if span.ctxt().is_root() { + if !span.from_expansion() { edition } else { span.edition() @@ -86,7 +86,7 @@ pub(super) fn parse( ); sess.dcx .struct_span_err(span, msg) - .help(VALID_FRAGMENT_NAMES_MSG) + .with_help(VALID_FRAGMENT_NAMES_MSG) .emit(); token::NonterminalKind::Ident }, @@ -175,7 +175,7 @@ fn parse_tree<'a>( // of a meta-variable expression (e.g. `${count(ident)}`). // Try to parse the meta-variable expression. match MetaVarExpr::parse(tts, delim_span.entire(), sess) { - Err(mut err) => { + Err(err) => { err.emit(); // Returns early the same read `$` to avoid spanning // unrelated diagnostics that could be performed afterwards diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index f2a9875ffd2..434891ebc76 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::errors::{ NoSyntaxVarsExprRepeat, VarStillRepeating, }; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch}; -use crate::mbe::{self, MetaVarExpr}; +use crate::mbe::{self, KleeneOp, MetaVarExpr}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; @@ -13,19 +13,28 @@ use rustc_errors::DiagnosticBuilder; use rustc_errors::{pluralize, PResult}; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; // A Marker adds the given mark to the syntax context. -struct Marker(LocalExpnId, Transparency); +struct Marker(LocalExpnId, Transparency, FxHashMap<SyntaxContext, SyntaxContext>); impl MutVisitor for Marker { const VISIT_TOKENS: bool = true; fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0.to_expn_id(), self.1) + // `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and + // by itself. All tokens in a macro body typically have the same syntactic context, unless + // it's some advanced case with macro-generated macros. So if we cache the marked version + // of that context once, we'll typically have a 100% cache hit rate after that. + let Marker(expn_id, transparency, ref mut cache) = *self; + let data = span.data(); + let marked_ctxt = *cache + .entry(data.ctxt) + .or_insert_with(|| data.ctxt.apply_mark(expn_id.to_expn_id(), transparency)); + *span = data.with_ctxt(marked_ctxt); } } @@ -42,6 +51,7 @@ enum Frame<'a> { tts: &'a [mbe::TokenTree], idx: usize, sep: Option<Token>, + kleene_op: KleeneOp, }, } @@ -122,7 +132,7 @@ pub(super) fn transcribe<'a>( // again, and we are done transcribing. let mut result: Vec<TokenTree> = Vec::new(); let mut result_stack = Vec::new(); - let mut marker = Marker(cx.current_expansion.id, transparency); + let mut marker = Marker(cx.current_expansion.id, transparency, Default::default()); loop { // Look at the last frame on the stack. @@ -207,7 +217,7 @@ pub(super) fn transcribe<'a>( // Is the repetition empty? if len == 0 { - if seq.kleene.op == mbe::KleeneOp::OneOrMore { + if seq.kleene.op == KleeneOp::OneOrMore { // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. @@ -227,6 +237,7 @@ pub(super) fn transcribe<'a>( idx: 0, sep: seq.separator.clone(), tts: &delimited.tts, + kleene_op: seq.kleene.op, }); } } @@ -243,7 +254,7 @@ pub(super) fn transcribe<'a>( MatchedTokenTree(tt) => { // `tt`s are emitted into the output stream directly as "raw tokens", // without wrapping them into groups. - result.push(tt.clone()); + result.push(maybe_use_metavar_location(cx, &stack, sp, tt)); } MatchedNonterminal(nt) => { // Other variables are emitted into the output stream as groups with @@ -308,6 +319,62 @@ pub(super) fn transcribe<'a>( } } +/// Usually metavariables `$var` produce interpolated tokens, which have an additional place for +/// keeping both the original span and the metavariable span. For `tt` metavariables that's not the +/// case however, and there's no place for keeping a second span. So we try to give the single +/// produced span a location that would be most useful in practice (the hygiene part of the span +/// must not be changed). +/// +/// Different locations are useful for different purposes: +/// - The original location is useful when we need to report a diagnostic for the original token in +/// isolation, without combining it with any surrounding tokens. This case occurs, but it is not +/// very common in practice. +/// - The metavariable location is useful when we need to somehow combine the token span with spans +/// of its surrounding tokens. This is the most common way to use token spans. +/// +/// So this function replaces the original location with the metavariable location in all cases +/// except these two: +/// - The metavariable is an element of undelimited sequence `$($tt)*`. +/// These are typically used for passing larger amounts of code, and tokens in that code usually +/// combine with each other and not with tokens outside of the sequence. +/// - The metavariable span comes from a different crate, then we prefer the more local span. +/// +/// FIXME: Find a way to keep both original and metavariable spans for all tokens without +/// regressing compilation time too much. Several experiments for adding such spans were made in +/// the past (PR #95580, #118517, #118671) and all showed some regressions. +fn maybe_use_metavar_location( + cx: &ExtCtxt<'_>, + stack: &[Frame<'_>], + metavar_span: Span, + orig_tt: &TokenTree, +) -> TokenTree { + let undelimited_seq = matches!( + stack.last(), + Some(Frame::Sequence { + tts: [_], + sep: None, + kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore, + .. + }) + ); + if undelimited_seq || cx.source_map().is_imported(metavar_span) { + return orig_tt.clone(); + } + + match orig_tt { + TokenTree::Token(Token { kind, span }, spacing) => { + let span = metavar_span.with_ctxt(span.ctxt()); + TokenTree::Token(Token { kind: kind.clone(), span }, *spacing) + } + TokenTree::Delimited(dspan, dspacing, delimiter, tts) => { + let open = metavar_span.shrink_to_lo().with_ctxt(dspan.open.ctxt()); + let close = metavar_span.shrink_to_hi().with_ctxt(dspan.close.ctxt()); + let dspan = DelimSpan::from_pair(open, close); + TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone()) + } + } +} + /// Lookup the meta-var named `ident` and return the matched token tree from the invocation using /// the set of matches `interpolations`. /// diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 60647c3350a..e979f9a75d4 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -282,7 +282,7 @@ impl ModError<'_> { secondary_path: secondary_path.display().to_string(), }) } - ModError::ParserError(mut err) => err.emit(), + ModError::ParserError(err) => err.emit(), } } } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 73a7d433b5c..a1d21361957 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -13,16 +13,16 @@ use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::profiling::SpannedEventArgRecorder; use rustc_span::{Span, DUMMY_SP}; -struct CrossbeamMessagePipe<T> { - tx: crossbeam_channel::Sender<T>, - rx: crossbeam_channel::Receiver<T>, +struct MessagePipe<T> { + tx: std::sync::mpsc::SyncSender<T>, + rx: std::sync::mpsc::Receiver<T>, } -impl<T> pm::bridge::server::MessagePipe<T> for CrossbeamMessagePipe<T> { +impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> { fn new() -> (Self, Self) { - let (tx1, rx1) = crossbeam_channel::bounded(1); - let (tx2, rx2) = crossbeam_channel::bounded(1); - (CrossbeamMessagePipe { tx: tx1, rx: rx2 }, CrossbeamMessagePipe { tx: tx2, rx: rx1 }) + let (tx1, rx1) = std::sync::mpsc::sync_channel(1); + let (tx2, rx2) = std::sync::mpsc::sync_channel(1); + (MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 }) } fn send(&mut self, value: T) { @@ -35,7 +35,7 @@ impl<T> pm::bridge::server::MessagePipe<T> for CrossbeamMessagePipe<T> { } fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy { - pm::bridge::server::MaybeCrossThread::<CrossbeamMessagePipe<_>>::new( + pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new( ecx.sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, ) @@ -171,7 +171,7 @@ impl MultiItemModifier for DeriveProcMacro { items.push(Annotatable::Item(item)); } } - Err(mut err) => { + Err(err) => { err.emit(); break; } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5eb6aed7253..6392894fea2 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -379,8 +379,8 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>> impl ToInternal<rustc_errors::Level> for Level { fn to_internal(self) -> rustc_errors::Level { match self { - Level::Error => rustc_errors::Level::Error { lint: false }, - Level::Warning => rustc_errors::Level::Warning(None), + Level::Error => rustc_errors::Level::Error, + Level::Warning => rustc_errors::Level::Warning, Level::Note => rustc_errors::Level::Note, Level::Help => rustc_errors::Level::Help, _ => unreachable!("unknown proc_macro::Level variant: {:?}", self), @@ -497,7 +497,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) { let mut diag = rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); - diag.set_span(MultiSpan::from_spans(diagnostic.spans)); + diag.span(MultiSpan::from_spans(diagnostic.spans)); for child in diagnostic.children { diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans)); } @@ -537,7 +537,7 @@ impl server::TokenStream for Rustc<'_, '_> { } expr }; - let expr = expr.map_err(|mut err| { + let expr = expr.map_err(|err| { err.emit(); })?; diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 0b859841828..3c14ad5e7b8 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{BytePos, Span}; use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::EmitterWriter; +use rustc_errors::emitter::HumanEmitter; use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use termcolor::WriteColor; @@ -30,7 +30,7 @@ fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) { vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], false, ); - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + let emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)); let dcx = DiagCtxt::with_emitter(Box::new(emitter)); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e6faad74384..59ea828440f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -210,7 +210,7 @@ declare_features! ( /// Allows the `multiple_supertrait_upcastable` lint. (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! - (incomplete, negative_bounds, "1.71.0", None), + (internal, negative_bounds, "1.71.0", None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2c34fc13919..58ac9668da5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1258,7 +1258,7 @@ pub struct Arm<'hir> { /// If this pattern and the optional guard matches, then `body` is evaluated. pub pat: &'hir Pat<'hir>, /// Optional guard clause. - pub guard: Option<Guard<'hir>>, + pub guard: Option<&'hir Expr<'hir>>, /// The expression the arm evaluates to if this arm matches. pub body: &'hir Expr<'hir>, } @@ -1281,26 +1281,6 @@ pub struct Let<'hir> { } #[derive(Debug, Clone, Copy, HashStable_Generic)] -pub enum Guard<'hir> { - If(&'hir Expr<'hir>), - IfLet(&'hir Let<'hir>), -} - -impl<'hir> Guard<'hir> { - /// Returns the body of the guard - /// - /// In other words, returns the e in either of the following: - /// - /// - `if e` - /// - `if let x = e` - pub fn body(&self) -> &'hir Expr<'hir> { - match self { - Guard::If(e) | Guard::IfLet(Let { init: e, .. }) => e, - } - } -} - -#[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct ExprField<'hir> { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -1381,6 +1361,12 @@ impl CoroutineKind { } } +impl CoroutineKind { + pub fn is_fn_like(self) -> bool { + matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) + } +} + impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -2017,7 +2003,7 @@ pub enum LocalSource { AsyncFn, /// A desugared `<expr>.await`. AwaitDesugar, - /// A desugared `expr = expr`, where the LHS is a tuple, struct or array. + /// A desugared `expr = expr`, where the LHS is a tuple, struct, array or underscore expression. /// The span is that of the `=` sign. AssignDesugar(Span), } @@ -2419,6 +2405,39 @@ impl<'hir> Ty<'hir> { my_visitor.visit_ty(self); my_visitor.0 } + + /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to + /// use inference to provide suggestions for the appropriate type if possible. + pub fn is_suggestable_infer_ty(&self) -> bool { + fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool { + generic_args.iter().any(|arg| match arg { + GenericArg::Type(ty) => ty.is_suggestable_infer_ty(), + GenericArg::Infer(_) => true, + _ => false, + }) + } + debug!(?self); + match &self.kind { + TyKind::Infer => true, + TyKind::Slice(ty) => ty.is_suggestable_infer_ty(), + TyKind::Array(ty, length) => { + ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _)) + } + TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), + TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), + TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), + TyKind::Path(QPath::TypeRelative(ty, segment)) => { + ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) + } + TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => { + ty_opt.is_some_and(Self::is_suggestable_infer_ty) + || segments + .iter() + .any(|segment| are_suggestable_generic_args(segment.args().args)) + } + _ => false, + } + } } /// Not represented directly in the AST; referred to by name through a `ty_path`. @@ -2749,7 +2768,7 @@ pub enum FnRetTy<'hir> { Return(&'hir Ty<'hir>), } -impl FnRetTy<'_> { +impl<'hir> FnRetTy<'hir> { #[inline] pub fn span(&self) -> Span { match *self { @@ -2757,6 +2776,15 @@ impl FnRetTy<'_> { Self::Return(ref ty) => ty.span, } } + + pub fn get_infer_ret_ty(&self) -> Option<&'hir Ty<'hir>> { + if let Self::Return(ty) = self { + if ty.is_suggestable_infer_ty() { + return Some(*ty); + } + } + None + } } /// Represents `for<...>` binder before a closure diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e58e4c8fe0e..dd3633b6b4f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -619,13 +619,8 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { visitor.visit_id(arm.hir_id); visitor.visit_pat(arm.pat); - if let Some(ref g) = arm.guard { - match g { - Guard::If(ref e) => visitor.visit_expr(e), - Guard::IfLet(ref l) => { - visitor.visit_let_expr(l); - } - } + if let Some(ref e) = arm.guard { + visitor.visit_expr(e); } visitor.visit_expr(arm.body); } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index b671bebeb05..b5ebc1fab76 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8b6b9a1272..6a17668ad17 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -346,6 +346,20 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` .label = `#[start]` function is not allowed to be `#[track_caller]` +hir_analysis_static_mut_ref = reference of mutable static is disallowed + .label = reference of mutable static + .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + +hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged + .label = shared reference of mutable static + .label_mut = mutable reference of mutable static + .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer + .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer + .note = reference of mutable static is a hard error from 2024 edition + .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior + hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 91b3807d744..1f88aaa6a4b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -26,23 +26,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { span: Span, ) { let tcx = self.tcx(); + let sized_def_id = tcx.lang_items().sized_trait(); + let mut seen_negative_sized_bound = false; // Try to find an unbound in bounds. let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| { for ab in ast_bounds { - if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { - unbounds.push(ptr) + let hir::GenericBound::Trait(ptr, modifier) = ab else { + continue; + }; + match modifier { + hir::TraitBoundModifier::Maybe => unbounds.push(ptr), + hir::TraitBoundModifier::Negative => { + if let Some(sized_def_id) = sized_def_id + && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) + { + seen_negative_sized_bound = true; + } + } + _ => {} } } }; search_bounds(ast_bounds); if let Some((self_ty, where_clause)) = self_ty_where_predicates { for clause in where_clause { - if let hir::WherePredicate::BoundPredicate(pred) = clause { - if pred.is_param_bound(self_ty.to_def_id()) { - search_bounds(pred.bounds); - } + if let hir::WherePredicate::BoundPredicate(pred) = clause + && pred.is_param_bound(self_ty.to_def_id()) + { + search_bounds(pred.bounds); } } } @@ -53,15 +66,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { }); } - let sized_def_id = tcx.lang_items().sized_trait(); - let mut seen_sized_unbound = false; for unbound in unbounds { - if let Some(sized_def_id) = sized_def_id { - if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) { - seen_sized_unbound = true; - continue; - } + if let Some(sized_def_id) = sized_def_id + && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) + { + seen_sized_unbound = true; + continue; } // There was a `?Trait` bound, but it was not `?Sized`; warn. tcx.dcx().span_warn( @@ -71,15 +82,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); } - // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available. - if sized_def_id.is_none() { - // No lang item for `Sized`, so we can't add it as a bound. - return; - } - if seen_sized_unbound { - // There was in fact a `?Sized` bound, return without doing anything - } else { - // There was no `?Sized` bound; add implicitly sized if `Sized` is available. + if seen_sized_unbound || seen_negative_sized_bound { + // There was in fact a `?Sized` or `!Sized` bound; + // we don't need to do anything. + } else if sized_def_id.is_some() { + // There was no `?Sized` or `!Sized` bound; + // add `Sized` if it's available. bounds.push_sized(tcx, self_ty, span); } } @@ -297,7 +305,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { binding.span, format!("{} `{}` is private", assoc_item.kind, binding.item_name), ) - .span_label(binding.span, format!("private {}", assoc_item.kind)) + .with_span_label(binding.span, format!("private {}", assoc_item.kind)) .emit(); } tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); @@ -454,7 +462,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { late_bound_in_trait_ref, late_bound_in_ty, |br_name| { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), binding.span, E0582, diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index f17f19bb77c..fc2ed104b3d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -6,7 +6,8 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; +use rustc_data_structures::unord::UnordMap; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; @@ -57,13 +58,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !trait_def.paren_sugar { if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar { // For now, require that parenthetical notation be used only with `Fn()` etc. - let mut err = feature_err( + feature_err( &self.tcx().sess.parse_sess, sym::unboxed_closures, span, "parenthetical notation is only stable when used with `Fn`-family traits", - ); - err.emit(); + ) + .emit(); } return; @@ -345,7 +346,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { candidates: Vec<DefId>, span: Span, ) -> ErrorGuaranteed { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.tcx().dcx(), name.span, E0034, @@ -444,7 +445,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { String::new() }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), name.span, E0220, @@ -605,7 +606,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let violations = object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); if !violations.is_empty() { - report_object_safety_error(tcx, *span, trait_def_id, &violations).emit(); + report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit(); object_safety_violations = true; } } @@ -673,7 +674,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { })) }) .flatten() - .collect::<FxHashMap<Symbol, &ty::AssocItem>>(); + .collect::<UnordMap<Symbol, &ty::AssocItem>>(); let mut names = names .into_iter() @@ -696,7 +697,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let names = names.join(", "); trait_bound_spans.sort(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), trait_bound_spans, E0191, @@ -709,7 +710,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut where_constraints = vec![]; let mut already_has_generics_args_suggestion = false; for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); + let mut names: UnordMap<_, usize> = Default::default(); for item in assoc_items { types_count += 1; *names.entry(item.name).or_insert(0) += 1; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 7d840ba7e81..e2cd4d5f21c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -5,7 +5,7 @@ use crate::astconv::{ }; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -27,7 +27,7 @@ fn generic_arg_mismatch_err( help: Option<String>, ) -> ErrorGuaranteed { let sess = tcx.sess; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), arg.span(), E0747, @@ -70,7 +70,7 @@ fn generic_arg_mismatch_err( Res::Err => { add_braces_suggestion(arg, &mut err); return err - .set_primary_message("unresolved item provided when a constant was expected") + .with_primary_message("unresolved item provided when a constant was expected") .emit(); } Res::Def(DefKind::TyParam, src_def_id) => { @@ -650,9 +650,9 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( if position == GenericArgPosition::Value && args.num_lifetime_params() != param_counts.lifetimes { - let mut err = struct_span_err!(tcx.dcx(), span, E0794, "{}", msg); - err.span_note(span_late, note); - err.emit(); + struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg) + .with_span_note(span_late, note) + .emit(); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index f3b93c91ae9..3761d529517 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -1,7 +1,9 @@ use rustc_ast::TraitObjectSyntax; use rustc_errors::{Diagnostic, StashKey}; use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; +use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use super::AstConv; @@ -32,32 +34,146 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } let of_trait_span = of_trait_ref.path.span; // make sure that we are not calling unwrap to abort during the compilation - let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { - return; - }; let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; - // check if the trait has generics, to make a correct suggestion - 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}")) - } else { - (generics.span, format!("<{param_name}: {impl_trait_name}>")) + let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span) + else { + return; + }; + let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name); + if sugg.is_empty() { + return; }; diag.multipart_suggestion( format!( - "alternatively use a blanket \ - implementation to implement `{of_trait_name}` for \ + "alternatively use a blanket implementation to implement `{of_trait_name}` for \ all types that also implement `{impl_trait_name}`" ), - vec![(self_ty.span, param_name), add_generic_sugg], + sugg, Applicability::MaybeIncorrect, ); } } + fn add_generic_param_suggestion( + &self, + generics: &hir::Generics<'_>, + self_ty_span: Span, + impl_trait_name: &str, + ) -> Vec<(Span, String)> { + // check if the trait has generics, to make a correct suggestion + 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}")) + } else { + (generics.span, format!("<{param_name}: {impl_trait_name}>")) + }; + vec![(self_ty_span, param_name), add_generic_sugg] + } + + /// Make sure that we are in the condition to suggest `impl Trait`. + fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool { + let tcx = self.tcx(); + let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; + let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + generics, + .. + })) = tcx.hir_node_by_def_id(parent_id) + else { + return false; + }; + let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { + return false; + }; + let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())]; + let is_object_safe = match self_ty.kind { + hir::TyKind::TraitObject(objects, ..) => { + objects.iter().all(|o| match o.trait_ref.path.res { + Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id), + _ => false, + }) + } + _ => false, + }; + if let hir::FnRetTy::Return(ty) = sig.decl.output + && ty.hir_id == self_ty.hir_id + { + let pre = if !is_object_safe { + format!("`{trait_name}` is not object safe, ") + } else { + String::new() + }; + let msg = format!( + "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \ + single underlying type", + ); + diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable); + if is_object_safe { + diag.multipart_suggestion_verbose( + "alternatively, you can return an owned trait object", + vec![ + (ty.span.shrink_to_lo(), "Box<dyn ".to_string()), + (ty.span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); + } + return true; + } + for ty in sig.decl.inputs { + if ty.hir_id != self_ty.hir_id { + continue; + } + let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name); + if !sugg.is_empty() { + diag.multipart_suggestion_verbose( + format!("use a new generic type parameter, constrained by `{trait_name}`"), + sugg, + Applicability::MachineApplicable, + ); + diag.multipart_suggestion_verbose( + "you can also use an opaque type, but users won't be able to specify the type \ + parameter when calling the `fn`, having to rely exclusively on type inference", + impl_sugg, + Applicability::MachineApplicable, + ); + } + if !is_object_safe { + diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); + // We'll emit the object safety error already, with a structured suggestion. + diag.downgrade_to_delayed_bug(); + } else { + let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { + // There are more than one trait bound, we need surrounding parentheses. + vec![ + (self_ty.span.shrink_to_lo(), "&(dyn ".to_string()), + (self_ty.span.shrink_to_hi(), ")".to_string()), + ] + } else { + vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())] + }; + diag.multipart_suggestion_verbose( + format!( + "alternatively, use a trait object to accept any type that implements \ + `{trait_name}`, accessing its methods at runtime using dynamic dispatch", + ), + sugg, + Applicability::MachineApplicable, + ); + } + return true; + } + false + } + pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { let tcx = self.tcx(); if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = @@ -97,8 +213,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; let mut diag = - rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); - if self_ty.span.can_be_used_for_suggestions() { + rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); + if self_ty.span.can_be_used_for_suggestions() + && !self.maybe_lint_impl_trait(self_ty, &mut diag) + { diag.multipart_suggestion_verbose( label, sugg, @@ -116,11 +234,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty.span, msg, |lint| { - lint.multipart_suggestion_verbose( - "use `dyn`", - sugg, - Applicability::MachineApplicable, - ); + if self_ty.span.can_be_used_for_suggestions() + && !self.maybe_lint_impl_trait(self_ty, lint) + { + lint.multipart_suggestion_verbose( + "use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + } self.maybe_lint_blanket_trait_impl(self_ty, lint); }, ); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 092df257dbf..1f47564649e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - FatalError, MultiSpan, + error_code, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, FatalError, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -866,7 +866,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { traits: &[String], name: Symbol, ) -> ErrorGuaranteed { - let mut err = struct_span_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type"); + let mut err = + struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type"); if self .tcx() .resolutions(()) @@ -1032,7 +1033,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name) }); - let Some(mut bound) = matching_candidates.next() else { + let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, &ty_param_name.to_string(), @@ -1046,38 +1047,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); - // look for a candidate that is not the same as our first bound, disregarding - // whether the bound is const. - let mut next_cand = matching_candidates.next(); - while let Some(mut bound2) = next_cand { - debug!(?bound2); - if bound2.bound_vars() != bound.bound_vars() { - break; - } - - let generics = tcx.generics_of(bound.def_id()); - let Some(host_index) = generics.host_effect_index else { break }; - - // always return the bound that contains the host param. - if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { - (bound, bound2) = (bound2, bound); - } - - let unconsted_args = bound - .skip_binder() - .args - .iter() - .enumerate() - .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); - - if unconsted_args.eq(bound2.skip_binder().args.iter()) { - next_cand = matching_candidates.next(); - } else { - break; - } - } - - if let Some(bound2) = next_cand { + if let Some(bound2) = matching_candidates.next() { debug!(?bound2); let assoc_kind_str = assoc_kind_str(assoc_kind); @@ -1344,7 +1314,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = format!("expected type, found variant `{assoc_ident}`"); tcx.dcx().span_err(span, msg) } else if qself_ty.is_enum() { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), assoc_ident.span, E0599, @@ -1385,7 +1355,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { reported } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { // `<impl Trait as OtherTrait>::Assoc` makes no sense. - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(alias_ty.def_id), E0667, @@ -1647,9 +1617,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = format!("{kind} `{name}` is private"); let def_span = tcx.def_span(item); tcx.dcx() - .struct_span_err_with_code(span, msg, rustc_errors::error_code!(E0624)) - .span_label(span, format!("private {kind}")) - .span_label(def_span, format!("{kind} defined here")) + .struct_span_err(span, msg) + .with_code(rustc_errors::error_code!(E0624)) + .with_span_label(span, format!("private {kind}")) + .with_span_label(def_span, format!("{kind} defined here")) .emit(); } tcx.check_stability(item, Some(block), span, None); @@ -1880,7 +1851,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.tcx().dcx(), span, E0109, @@ -2631,7 +2602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), decl.output.span(), E0581, diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index a614d4abf25..ea2f5f50b5c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -2,7 +2,7 @@ use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBou use crate::bounds::Bounds; use crate::errors::TraitObjectDeclaredWithNoTraits; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -89,7 +89,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if regular_traits.len() > 1 { let first_trait = ®ular_traits[0]; let additional_trait = ®ular_traits[1]; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), additional_trait.bottom().1, E0225, @@ -140,6 +140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let reported = report_object_safety_error( tcx, span, + Some(hir_id), item.trait_ref().def_id(), &object_safety_violations, ) @@ -289,19 +290,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if references_self { let def_id = i.bottom().0.def_id(); - let mut err = struct_span_err!( + struct_span_code_err!( tcx.dcx(), i.bottom().1, E0038, "the {} `{}` cannot be made into an object", tcx.def_descr(def_id), tcx.item_name(def_id), - ); - err.note( + ) + .with_note( rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) .error_msg(), - ); - err.emit(); + ) + .emit(); } ty::ExistentialTraitRef { def_id: trait_ref.def_id, args } @@ -374,7 +375,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_region_to_region(lifetime, None) } else { self.re_infer(None, span).unwrap_or_else(|| { - let mut err = struct_span_err!( + let err = struct_span_code_err!( tcx.dcx(), span, E0228, diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b6688e0ce29..b69f679880d 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -45,24 +45,6 @@ impl<'tcx> Bounds<'tcx> { polarity: ty::ImplPolarity, ) { self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - - // push a non-const (`host = true`) version of the bound if it is `~const`. - if tcx.features().effects - && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index - && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_ - { - let generics = tcx.generics_of(trait_ref.def_id()); - let Some(host_index) = generics.host_effect_index else { return }; - let trait_ref = trait_ref.map_bound(|mut trait_ref| { - trait_ref.args = - tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { - if host_index == n { tcx.consts.true_.into() } else { arg } - })); - trait_ref - }); - - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - } } fn push_trait_bound_inner( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d2e96ac74df..6265ddafef0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -8,7 +8,7 @@ use rustc_attr as attr; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::def_id::LocalModDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; @@ -17,7 +17,7 @@ use rustc_middle::middle::stability::EvalResult; use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; -use rustc_middle::ty::util::{Discr, IntTypeExt}; +use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{ AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -37,7 +37,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { match tcx.sess.target.is_abi_supported(abi) { Some(true) => (), Some(false) => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), span, E0570, @@ -58,7 +58,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { // This ABI is only allowed on function pointers if abi == Abi::CCmseNonSecureCall { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), span, E0781, @@ -198,8 +198,8 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". -fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { - let item = tcx.hir().item(id); +fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let item = tcx.hir().expect_item(def_id); let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { tcx.dcx().span_delayed_bug(item.span, "expected opaque item"); return; @@ -213,13 +213,12 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { return; } - let args = GenericArgs::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, origin).is_err() { + if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() { return; } @@ -230,19 +229,36 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { pub(super) fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, - args: GenericArgsRef<'tcx>, span: Span, - origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { - if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() { - let reported = match origin { - hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span), - _ => opaque_type_cycle_error(tcx, def_id, span), - }; - Err(reported) - } else { - Ok(()) + let args = GenericArgs::identity_for_item(tcx, def_id); + + // First, try to look at any opaque expansion cycles, considering coroutine fields + // (even though these aren't necessarily true errors). + if tcx + .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::Yes) + .is_err() + { + // Look for true opaque expansion cycles, but ignore coroutines. + // This will give us any true errors. Coroutines are only problematic + // if they cause layout computation errors. + if tcx + .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No) + .is_err() + { + let reported = opaque_type_cycle_error(tcx, def_id, span); + return Err(reported); + } + + // And also look for cycle errors in the layout of coroutines. + if let Err(&LayoutError::Cycle(guar)) = + tcx.layout_of(tcx.param_env(def_id).and(Ty::new_opaque(tcx, def_id.to_def_id(), args))) + { + return Err(guar); + } } + + Ok(()) } /// Check that the concrete type behind `impl Trait` actually implements `Trait`. @@ -440,40 +456,31 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } -fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { - debug!( - "check_item_type(it.def_id={:?}, it.name={})", - id.owner_id, - tcx.def_path_str(id.owner_id) - ); +pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let _indenter = indenter(); - match tcx.def_kind(id.owner_id) { + match tcx.def_kind(def_id) { DefKind::Static(..) => { - tcx.ensure().typeck(id.owner_id.def_id); - maybe_check_static_with_link_section(tcx, id.owner_id.def_id); - check_static_inhabited(tcx, id.owner_id.def_id); - check_static_linkage(tcx, id.owner_id.def_id); + tcx.ensure().typeck(def_id); + maybe_check_static_with_link_section(tcx, def_id); + check_static_inhabited(tcx, def_id); + check_static_linkage(tcx, def_id); } DefKind::Const => { - tcx.ensure().typeck(id.owner_id.def_id); + tcx.ensure().typeck(def_id); } DefKind::Enum => { - check_enum(tcx, id.owner_id.def_id); + check_enum(tcx, def_id); } DefKind::Fn => {} // entirely within check_item_body DefKind::Impl { of_trait } => { - if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(id.owner_id) { - check_impl_items_against_trait( - tcx, - id.owner_id.def_id, - impl_trait_ref.instantiate_identity(), - ); - check_on_unimplemented(tcx, id); + if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(def_id) { + check_impl_items_against_trait(tcx, def_id, impl_trait_ref.instantiate_identity()); + check_on_unimplemented(tcx, def_id); } } DefKind::Trait => { - let assoc_items = tcx.associated_items(id.owner_id); - check_on_unimplemented(tcx, id); + let assoc_items = tcx.associated_items(def_id); + check_on_unimplemented(tcx, def_id); for &assoc_item in assoc_items.in_definition_order() { match assoc_item.kind { @@ -482,12 +489,12 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi); } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { - let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id); + let trait_args = GenericArgs::identity_for_item(tcx, def_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, assoc_item, - ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_args), + ty::TraitRef::new(tcx, def_id.to_def_id(), trait_args), ); } _ => {} @@ -495,13 +502,13 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } } DefKind::Struct => { - check_struct(tcx, id.owner_id.def_id); + check_struct(tcx, def_id); } DefKind::Union => { - check_union(tcx, id.owner_id.def_id); + check_union(tcx, def_id); } DefKind::OpaqueTy => { - let origin = tcx.opaque_type_origin(id.owner_id.def_id); + let origin = tcx.opaque_type_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) @@ -509,16 +516,16 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { { // Skip opaques from RPIT in traits with no default body. } else { - check_opaque(tcx, id); + check_opaque(tcx, def_id); } } DefKind::TyAlias => { - let pty_ty = tcx.type_of(id.owner_id).instantiate_identity(); - let generics = tcx.generics_of(id.owner_id); + let pty_ty = tcx.type_of(def_id).instantiate_identity(); + let generics = tcx.generics_of(def_id); check_type_params_are_used(tcx, generics, pty_ty); } DefKind::ForeignMod => { - let it = tcx.hir().item(id); + let it = tcx.hir().expect_item(def_id); let hir::ItemKind::ForeignMod { abi, items } = it.kind else { return; }; @@ -553,14 +560,14 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { (0, _) => ("const", "consts", None), _ => ("type or const", "types or consts", None), }; - struct_span_err!( + struct_span_code_err!( tcx.dcx(), item.span, E0044, "foreign items may not have {kinds} parameters", ) - .span_label(item.span, format!("can't have {kinds} parameters")) - .help( + .with_span_label(item.span, format!("can't have {kinds} parameters")) + .with_help( // FIXME: once we start storing spans for type arguments, turn this // into a suggestion. format!( @@ -589,19 +596,19 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } } DefKind::GlobalAsm => { - let it = tcx.hir().item(id); + let it = tcx.hir().expect_item(def_id); let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; - InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); + InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id); } _ => {} } } -pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: hir::ItemId) { +pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) { // an error would be reported if this fails. - let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id()); + let _ = OnUnimplementedDirective::of_item(tcx, def_id.to_def_id()); } pub(super) fn check_specialization_validity<'tcx>( @@ -652,10 +659,7 @@ pub(super) fn check_specialization_validity<'tcx>( if !tcx.is_impl_trait_in_trait(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { - tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("parent item: {parent_impl:?} not marked as default"), - ); + tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); } } } @@ -680,7 +684,7 @@ fn check_impl_items_against_trait<'tcx>( ty::ImplPolarity::Negative => { if let [first_item_ref, ..] = impl_item_refs { let first_item_span = tcx.def_span(first_item_ref); - struct_span_err!( + struct_span_code_err!( tcx.dcx(), first_item_span, E0749, @@ -797,10 +801,9 @@ fn check_impl_items_against_trait<'tcx>( }; tcx.dcx() .struct_span_err(tcx.def_span(def_id), msg) - .note(format!( - "specialization behaves in inconsistent and \ - surprising ways with {feature}, \ - and for now is disallowed" + .with_note(format!( + "specialization behaves in inconsistent and surprising ways with \ + {feature}, and for now is disallowed" )) .emit(); } @@ -833,13 +836,13 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { { let fields = &def.non_enum_variant().fields; if fields.is_empty() { - struct_span_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); + struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } let e = fields[FieldIdx::from_u32(0)].ty(tcx, args); if !fields.iter().all(|f| f.ty(tcx, args) == e) { - struct_span_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous") - .span_label(sp, "SIMD elements must have the same type") + struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous") + .with_span_label(sp, "SIMD elements must have the same type") .emit(); return; } @@ -851,10 +854,10 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { }; if let Some(len) = len { if len == 0 { - struct_span_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); + struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } else if len > MAX_SIMD_LANES { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), sp, E0075, @@ -877,7 +880,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) => { /* struct([f32; 4]) is ok */ } _ => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), sp, E0077, @@ -900,7 +903,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { && let Some(repr_pack) = repr.pack && pack as u64 != repr_pack.bytes() { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), sp, E0634, @@ -911,7 +914,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { } } if repr.align.is_some() { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), sp, E0587, @@ -920,7 +923,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { .emit(); } else { if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), sp, E0588, @@ -1110,13 +1113,13 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { if def.variants().is_empty() { if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), attr.span, E0084, "unsupported representation for zero-variant enum" ) - .span_label(tcx.def_span(def_id), "zero-variant enum") + .with_span_label(tcx.def_span(def_id), "zero-variant enum") .emit(); } } @@ -1149,13 +1152,13 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { let disr_non_unit = def.variants().iter().any(|var| !is_unit(var) && has_disr(var)); if disr_non_unit || (disr_units && has_non_units) { - let mut err = struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0732, "`#[repr(inttype)]` must be specified" - ); - err.emit(); + ) + .emit(); } } @@ -1235,7 +1238,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) if discrs[i].1.val == discrs[o].1.val { let err = error.get_or_insert_with(|| { - let mut ret = struct_span_err!( + let mut ret = struct_span_code_err!( tcx.dcx(), tcx.def_span(adt.did()), E0081, @@ -1258,7 +1261,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } } - if let Some(mut e) = error { + if let Some(e) = error { e.emit(); } @@ -1302,33 +1305,19 @@ pub(super) fn check_type_params_are_used<'tcx>( && let ty::GenericParamDefKind::Type { .. } = param.kind { let span = tcx.def_span(param.def_id); - struct_span_err!(tcx.dcx(), span, E0091, "type parameter `{}` is unused", param.name,) - .span_label(span, "unused type parameter") - .emit(); + struct_span_code_err!( + tcx.dcx(), + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) + .with_span_label(span, "unused type parameter") + .emit(); } } } -pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let module = tcx.hir_module_items(module_def_id); - for id in module.items() { - check_item_type(tcx, id); - } - if module_def_id == LocalModDefId::CRATE_DEF_ID { - super::entry::check_for_entry_fn(tcx); - } -} - -fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed { - struct_span_err!(tcx.dcx(), span, E0733, "recursion in an `async fn` requires boxing") - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .note( - "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", - ) - .emit() -} - /// Emit an error for recursive opaque types. /// /// If this is a return `impl Trait`, find the item's return expressions and point at them. For @@ -1342,7 +1331,7 @@ fn opaque_type_cycle_error( opaque_def_id: LocalDefId, span: Span, ) -> ErrorGuaranteed { - let mut err = struct_span_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type"); + let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type"); let mut label = false; if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) { 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 dbcaa244f29..469e7a6a13c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,8 +1,8 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use hir::def_id::{DefId, LocalDefId}; +use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -19,7 +19,7 @@ use rustc_middle::ty::{ self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -478,7 +478,7 @@ fn compare_asyncness<'tcx>( pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, -) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { +) -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = @@ -625,7 +625,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) { Ok(()) => {} Err(terr) => { - let mut diag = struct_span_err!( + let mut diag = struct_span_code_err!( tcx.dcx(), cause.span(), E0053, @@ -706,7 +706,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 remapped_types = FxHashMap::default(); + let mut remapped_types = DefIdMap::default(); for (def_id, (ty, args)) in collected_types { match infcx.fully_resolve((ty, args)) { Ok((ty, args)) => { @@ -934,17 +934,15 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { return_span, "return type captures more lifetimes than trait definition", ) - .span_label(self.tcx.def_span(def_id), "this lifetime was captured") - .span_note( + .with_span_label(self.tcx.def_span(def_id), "this lifetime was captured") + .with_span_note( self.tcx.def_span(self.def_id), "hidden type must only reference lifetimes captured by this impl trait", ) - .note(format!("hidden type inferred to be `{}`", self.ty)) + .with_note(format!("hidden type inferred to be `{}`", self.ty)) .emit() } - _ => { - self.tcx.dcx().span_delayed_bug(DUMMY_SP, "should've been able to remap region") - } + _ => self.tcx.dcx().delayed_bug("should've been able to remap region"), }; return Err(guar); }; @@ -972,7 +970,7 @@ fn report_trait_method_mismatch<'tcx>( let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(infcx, terr, &cause, impl_m, trait_m); - let mut diag = struct_span_err!( + let mut diag = struct_span_code_err!( tcx.dcx(), impl_err_span, E0053, @@ -1217,7 +1215,7 @@ fn compare_self_type<'tcx>( (false, true) => { let self_descr = self_string(impl_m); let impl_m_span = tcx.def_span(impl_m.def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), impl_m_span, E0185, @@ -1237,7 +1235,7 @@ fn compare_self_type<'tcx>( (true, false) => { let self_descr = self_string(trait_m); let impl_m_span = tcx.def_span(impl_m.def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), impl_m_span, E0186, @@ -1303,8 +1301,7 @@ fn compare_number_of_generics<'tcx>( // inheriting the generics from will also have mismatched arguments, and // we'll report an error for that instead. Delay a bug for safety, though. if trait_.is_impl_trait_in_trait() { - return Err(tcx.dcx().span_delayed_bug( - rustc_span::DUMMY_SP, + return Err(tcx.dcx().delayed_bug( "errors comparing numbers of generics of trait/impl functions were not emitted", )); } @@ -1371,7 +1368,7 @@ fn compare_number_of_generics<'tcx>( let spans = arg_spans(impl_.kind, impl_item.generics); let span = spans.first().copied(); - let mut err = tcx.dcx().struct_span_err_with_code( + let mut err = tcx.dcx().struct_span_err( spans, format!( "{} `{}` has {} {kind} parameter{} but its trait \ @@ -1384,8 +1381,8 @@ fn compare_number_of_generics<'tcx>( pluralize!(trait_count), kind = kind, ), - DiagnosticId::Error("E0049".into()), ); + err.code(DiagnosticId::Error("E0049".into())); let msg = format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),); @@ -1463,7 +1460,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .unwrap_or_else(|| tcx.def_span(impl_m.def_id)); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), impl_span, E0050, @@ -1530,7 +1527,7 @@ fn compare_synthetic_generics<'tcx>( let impl_def_id = impl_def_id.expect_local(); let impl_span = tcx.def_span(impl_def_id); let trait_span = tcx.def_span(trait_def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), impl_span, E0643, @@ -1689,7 +1686,7 @@ fn compare_generic_param_kinds<'tcx>( let param_impl_span = tcx.def_span(param_impl.def_id); let param_trait_span = tcx.def_span(param_trait.def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), param_impl_span, E0053, @@ -1836,7 +1833,7 @@ fn compare_const_predicate_entailment<'tcx>( let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); cause.span = ty.span; - let mut diag = struct_span_err!( + let mut diag = struct_span_code_err!( tcx.dcx(), cause.span, E0326, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index fd1571426c8..f7fc0c81b95 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -7,7 +7,7 @@ use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_trait_selection::traits::{ elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt, }; @@ -153,10 +153,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( trait_m_sig.inputs_and_output, )); if !ocx.select_all_or_error().is_empty() { - tcx.dcx().span_delayed_bug( - DUMMY_SP, - "encountered errors when checking RPITIT refinement (selection)", - ); + tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (selection)"); return; } let outlives_env = OutlivesEnvironment::with_bounds( @@ -165,18 +162,12 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.dcx().span_delayed_bug( - DUMMY_SP, - "encountered errors when checking RPITIT refinement (regions)", - ); + tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (regions)"); return; } // Resolve any lifetime variables that may have been introduced during normalization. let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { - tcx.dcx().span_delayed_bug( - DUMMY_SP, - "encountered errors when checking RPITIT refinement (resolution)", - ); + tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)"); return; }; diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 3492499db68..3275a81c3dd 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -2,7 +2,7 @@ // // We don't do any drop checking during hir typeck. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, ErrorGuaranteed}; +use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::util::CheckRegions; @@ -88,8 +88,12 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( let drop_impl_span = tcx.def_span(drop_impl_did); let item_span = tcx.def_span(self_type_did); let self_descr = tcx.def_descr(self_type_did); - let mut err = - struct_span_err!(tcx.dcx(), drop_impl_span, E0366, "`Drop` impls cannot be specialized"); + let mut err = struct_span_code_err!( + tcx.dcx(), + drop_impl_span, + E0366, + "`Drop` impls cannot be specialized" + ); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { err.note(format!("`{arg}` is mentioned multiple times")) @@ -154,14 +158,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let item_span = tcx.def_span(adt_def_id); let self_descr = tcx.def_descr(adt_def_id.to_def_id()); guar = Some( - struct_span_err!( + struct_span_code_err!( tcx.dcx(), error.root_obligation.cause.span, E0367, "`Drop` impl requires `{root_predicate}` \ but the {self_descr} it is implemented for does not", ) - .span_note(item_span, "the implementor must specify the same requirement") + .with_span_note(item_span, "the implementor must specify the same requirement") .emit(), ); } @@ -186,14 +190,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( } }; guar = Some( - struct_span_err!( + struct_span_code_err!( tcx.dcx(), error.origin().span(), E0367, "`Drop` impl requires `{outlives}` \ but the {self_descr} it is implemented for does not", ) - .span_note(item_span, "the implementor must specify the same requirement") + .with_span_note(item_span, "the implementor must specify the same requirement") .emit(), ); } diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs new file mode 100644 index 00000000000..27bb2c57a5c --- /dev/null +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -0,0 +1,97 @@ +use rustc_hir as hir; +use rustc_hir_pretty::qpath_to_string; +use rustc_lint_defs::builtin::STATIC_MUT_REF; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; +use rustc_type_ir::Mutability; + +use crate::errors; + +/// Check for shared or mutable references of `static mut` inside expression +pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { + let span = expr.span; + let hir_id = expr.hir_id; + if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind + && matches!(borrow_kind, hir::BorrowKind::Ref) + && let Some(var) = is_path_static_mut(*expr) + { + handle_static_mut_ref( + tcx, + span, + var, + span.edition().at_least_rust_2024(), + matches!(m, Mutability::Mut), + hir_id, + ); + } +} + +/// Check for shared or mutable references of `static mut` inside statement +pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { + if let hir::StmtKind::Local(loc) = stmt.kind + && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind + && matches!(ba.0, rustc_ast::ByRef::Yes) + && let Some(init) = loc.init + && let Some(var) = is_path_static_mut(*init) + { + handle_static_mut_ref( + tcx, + init.span, + var, + loc.span.edition().at_least_rust_2024(), + matches!(ba.1, Mutability::Mut), + stmt.hir_id, + ); + } +} + +fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> { + if let hir::ExprKind::Path(qpath) = expr.kind + && let hir::QPath::Resolved(_, path) = qpath + && let hir::def::Res::Def(def_kind, _) = path.res + && let hir::def::DefKind::Static(mt) = def_kind + && matches!(mt, Mutability::Mut) + { + return Some(qpath_to_string(&qpath)); + } + None +} + +fn handle_static_mut_ref( + tcx: TyCtxt<'_>, + span: Span, + var: String, + e2024: bool, + mutable: bool, + hir_id: hir::HirId, +) { + if e2024 { + let sugg = if mutable { + errors::StaticMutRefSugg::Mut { span, var } + } else { + errors::StaticMutRefSugg::Shared { span, var } + }; + tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg }); + return; + } + + let (label, sugg, shared) = if mutable { + ( + errors::RefOfMutStaticLabel::Mut { span }, + errors::RefOfMutStaticSugg::Mut { span, var }, + "mutable ", + ) + } else { + ( + errors::RefOfMutStaticLabel::Shared { span }, + errors::RefOfMutStaticSugg::Shared { span, var }, + "shared ", + ) + }; + tcx.emit_spanned_lint( + STATIC_MUT_REF, + hir_id, + span, + errors::RefOfMutStatic { shared, why_note: (), label, sugg }, + ); +} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 632af780ed8..7c3e296dfce 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -8,7 +8,7 @@ use crate::errors::{ }; use hir::def_id::DefId; -use rustc_errors::{struct_span_err, DiagnosticMessage}; +use rustc_errors::{struct_span_code_err, DiagnosticMessage}; use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,8 +29,8 @@ fn equate_intrinsic_type<'tcx>( (own_counts, generics.span) } _ => { - struct_span_err!(tcx.dcx(), it.span, E0622, "intrinsic must be a function") - .span_label(it.span, "expected a function") + struct_span_code_err!(tcx.dcx(), it.span, E0622, "intrinsic must be a function") + .with_span_label(it.span, "expected a function") .emit(); return; } @@ -552,7 +552,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)), _ => { let msg = format!("unrecognized platform-specific intrinsic function: `{name}`"); - tcx.dcx().struct_span_err(it.span, msg).emit(); + tcx.dcx().span_err(it.span, msg); return; } }; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index ac18e6de0ba..db619d5169e 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::{Symbol, DUMMY_SP}; +use rustc_span::Symbol; use rustc_target::abi::FieldIdx; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; @@ -153,12 +153,14 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { }; let Some(asm_ty) = asm_ty else { let msg = format!("cannot use value of type `{ty}` for inline assembly"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note( - "only integers, floats, SIMD vectors, pointers and function pointers \ - can be used as arguments for inline assembly", - ); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .with_note( + "only integers, floats, SIMD vectors, pointers and function pointers \ + can be used as arguments for inline assembly", + ) + .emit(); return None; }; @@ -166,9 +168,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // possibly fail is for SIMD types which don't #[derive(Copy)]. if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { let msg = "arguments for inline assembly must be copyable"; - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note(format!("`{ty}` does not implement the Copy trait")); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .with_note(format!("`{ty}` does not implement the Copy trait")) + .emit(); } // Ideally we wouldn't need to do this, but LLVM's register allocator @@ -183,16 +187,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some((in_expr, Some(in_asm_ty))) = tied_input { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; - let mut err = self.tcx.dcx().struct_span_err(vec![in_expr.span, expr.span], msg); - let in_expr_ty = (self.get_operand_ty)(in_expr); - err.span_label(in_expr.span, format!("type `{in_expr_ty}`")); - err.span_label(expr.span, format!("type `{ty}`")); - err.note( - "asm inout arguments must have the same type, \ - unless they are both pointers or integers of the same size", - ); - err.emit(); + self.tcx + .dcx() + .struct_span_err(vec![in_expr.span, expr.span], msg) + .with_span_label(in_expr.span, format!("type `{in_expr_ty}`")) + .with_span_label(expr.span, format!("type `{ty}`")) + .with_note( + "asm inout arguments must have the same type, \ + unless they are both pointers or integers of the same size", + ) + .emit(); } // All of the later checks have already been done on the input, so @@ -234,13 +239,15 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some(feature) = feature { if !target_features.contains(feature) { let msg = format!("`{feature}` target feature is not enabled"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); - err.note(format!( - "this is required to use type `{}` with register class `{}`", - ty, - reg_class.name(), - )); - err.emit(); + self.tcx + .dcx() + .struct_span_err(expr.span, msg) + .with_note(format!( + "this is required to use type `{}` with register class `{}`", + ty, + reg_class.name(), + )) + .emit(); return Some(asm_ty); } } @@ -287,7 +294,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); let Some(asm_arch) = self.tcx.sess.asm_arch else { - self.tcx.dcx().span_delayed_bug(DUMMY_SP, "target architecture does not support asm"); + self.tcx.dcx().delayed_bug("target architecture does not support asm"); return; }; for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { @@ -318,7 +325,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { op.is_clobber(), ) { let msg = format!("cannot use register `{}`: {}", reg.name(), msg); - self.tcx.dcx().struct_span_err(*op_sp, msg).emit(); + self.tcx.dcx().span_err(*op_sp, msg); continue; } } @@ -357,7 +364,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { reg_class.name(), feature ); - self.tcx.dcx().struct_span_err(*op_sp, msg).emit(); + self.tcx.dcx().span_err(*op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -371,7 +378,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { .intersperse(", ") .collect::<String>(), ); - self.tcx.dcx().struct_span_err(*op_sp, msg).emit(); + self.tcx.dcx().span_err(*op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -449,14 +456,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Never | ty::Error(_) => {} ty::FnDef(..) => {} _ => { - let mut err = - self.tcx.dcx().struct_span_err(*op_sp, "invalid `sym` operand"); - err.span_label( - self.tcx.def_span(anon_const.def_id), - format!("is {} `{}`", ty.kind().article(), ty), - ); - err.help("`sym` operands must refer to either a function or a static"); - err.emit(); + self.tcx + .dcx() + .struct_span_err(*op_sp, "invalid `sym` operand") + .with_span_label( + self.tcx.def_span(anon_const.def_id), + format!("is {} `{}`", ty.kind().article(), ty), + ) + .with_help( + "`sym` operands must refer to either a function or a static", + ) + .emit(); } }; } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index faec72cfeb6..3b05eaedf34 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -66,6 +66,7 @@ mod check; mod compare_impl_item; pub mod dropck; mod entry; +mod errs; pub mod intrinsic; pub mod intrinsicck; mod region; @@ -75,10 +76,9 @@ pub use check::check_abi; use std::num::NonZeroU32; -use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorGuaranteed; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_code_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; @@ -110,7 +110,6 @@ pub fn provide(providers: &mut Providers) { wfcheck::provide(providers); *providers = Providers { adt_destructor, - check_mod_item_types, region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index eab83c7a254..5d5a4789734 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -18,6 +18,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::source_map; use rustc_span::Span; +use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; + use std::mem; #[derive(Debug, Copy, Clone)] @@ -177,6 +179,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { + fn has_let_expr(expr: &Expr<'_>) -> bool { + match &expr.kind { + hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + hir::ExprKind::Let(..) => true, + _ => false, + } + } + let prev_cx = visitor.cx; visitor.terminating_scopes.insert(arm.hir_id.local_id); @@ -184,7 +194,9 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); visitor.cx.var_parent = visitor.cx.parent; - if let Some(hir::Guard::If(expr)) = arm.guard { + if let Some(expr) = arm.guard + && !has_let_expr(expr) + { visitor.terminating_scopes.insert(expr.hir_id.local_id); } @@ -214,6 +226,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h let stmt_id = stmt.hir_id.local_id; debug!("resolve_stmt(stmt.id={:?})", stmt_id); + maybe_stmt_static_mut(visitor.tcx, *stmt); + // Every statement will clean up the temporaries created during // execution of that statement. Therefore each statement has an // associated destruction scope that represents the scope of the @@ -232,6 +246,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) { debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr); + maybe_expr_static_mut(visitor.tcx, *expr); + let prev_cx = visitor.cx; visitor.enter_node_scope_with_dtor(expr.hir_id.local_id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 580d4bd5b02..59c72227144 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -3,7 +3,9 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; @@ -172,7 +174,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() item.name = ? tcx.def_path_str(def_id) ); - match item.kind { + let res = match item.kind { // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // @@ -197,11 +199,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); - let mut err = - tcx.dcx().struct_span_err(sp, "impls of auto traits cannot be default"); - err.span_labels(impl_.defaultness_span, "default because of this"); - err.span_label(sp, "auto trait"); - res = Err(err.emit()); + res = Err(tcx + .dcx() + .struct_span_err(sp, "impls of auto traits cannot be default") + .with_span_labels(impl_.defaultness_span, "default because of this") + .with_span_label(sp, "auto trait") + .emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match tcx.impl_polarity(def_id) { @@ -216,7 +219,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() if let hir::Defaultness::Default { .. } = impl_.defaultness { let mut spans = vec![span]; spans.extend(impl_.defaultness_span); - res = Err(struct_span_err!( + res = Err(struct_span_code_err!( tcx.dcx(), spans, E0750, @@ -271,7 +274,11 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() } } _ => Ok(()), - } + }; + + crate::check::check::check_item_type(tcx, def_id); + + res } fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> { @@ -485,35 +492,32 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { if !unsatisfied_bounds.is_empty() { let plural = pluralize!(unsatisfied_bounds.len()); - let mut err = tcx.dcx().struct_span_err( - gat_item_hir.span, - format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), - ); - let suggestion = format!( "{} {}", gat_item_hir.generics.add_where_or_trailing_comma(), unsatisfied_bounds.join(", "), ); - err.span_suggestion( - gat_item_hir.generics.tail_span_for_predicate_suggestion(), - format!("add the required where clause{plural}"), - suggestion, - Applicability::MachineApplicable, - ); - let bound = if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note(format!( - "{bound} currently required to ensure that impls have maximum flexibility" - )); - err.note( - "we are soliciting feedback, see issue #87479 \ - <https://github.com/rust-lang/rust/issues/87479> \ - for more information", - ); - - err.emit(); + tcx.dcx() + .struct_span_err( + gat_item_hir.span, + format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), + ) + .with_span_suggestion( + gat_item_hir.generics.tail_span_for_predicate_suggestion(), + format!("add the required where clause{plural}"), + suggestion, + Applicability::MachineApplicable, + ) + .with_note(format!( + "{bound} currently required to ensure that impls have maximum flexibility" + )) + .with_note( + "we are soliciting feedback, see issue #87479 \ + <https://github.com/rust-lang/rust/issues/87479> for more information", + ) + .emit(); } } } @@ -834,8 +838,8 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem trait_should_be_self, "associated item referring to unboxed trait object for its own trait", ) - .span_label(trait_name.span, "in this trait") - .multipart_suggestion( + .with_span_label(trait_name.span, "in this trait") + .with_multipart_suggestion( "you might have meant to use `Self` to refer to the implementing type", sugg, Applicability::MachineApplicable, @@ -934,8 +938,8 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), }; if may_suggest_feature && tcx.sess.is_nightly_build() { diag.help( - "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", - ); + "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", + ); } Err(diag.emit()) @@ -1113,7 +1117,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker) { for associated_def_id in &*tcx.associated_item_def_ids(def_id) { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(*associated_def_id), E0714, @@ -1595,7 +1599,7 @@ fn check_method_receiver<'tcx>( the `arbitrary_self_types` feature", ), ) - .help(HELP_FOR_SELF_TYPE) + .with_help(HELP_FOR_SELF_TYPE) .emit() } else { // Report error; would not have worked with `arbitrary_self_types`. @@ -1607,9 +1611,9 @@ fn check_method_receiver<'tcx>( } fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed { - struct_span_err!(tcx.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}") - .note("type of `self` must be `Self` or a type that dereferences to it") - .help(HELP_FOR_SELF_TYPE) + struct_span_code_err!(tcx.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}") + .with_note("type of `self` must be `Self` or a type that dereferences to it") + .with_help(HELP_FOR_SELF_TYPE) .emit() } @@ -1909,14 +1913,16 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); - res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))) + res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + if module == LocalModDefId::CRATE_DEF_ID { + super::entry::check_for_entry_fn(tcx); + } + res } fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> { - let mut err = - struct_span_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used"); - err.span_label(span, "unused parameter"); - err + struct_span_code_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used") + .with_span_label(span, "unused parameter") } pub fn provide(providers: &mut Providers) { 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 ec15aa65e7a..4c3455c7240 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -70,17 +70,16 @@ impl<'tcx> InherentOverlapChecker<'tcx> { match seen_items.entry(norm_ident) { Entry::Occupied(entry) => { let former = entry.get(); - let mut err = struct_span_err!( + struct_span_code_err!( self.tcx.dcx(), span, E0592, "duplicate definitions with name `{}`", ident, - ); - err.span_label(span, format!("duplicate definitions for `{ident}`")); - err.span_label(*former, format!("other definition for `{ident}`")); - - err.emit(); + ) + .with_span_label(span, format!("duplicate definitions for `{ident}`")) + .with_span_label(*former, format!("other definition for `{ident}`")) + .emit(); } Entry::Vacant(entry) => { entry.insert(span); @@ -105,7 +104,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { if let Some(item2) = collision { let name = item1.ident(self.tcx).normalize_to_macros_2_0(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.tcx.dcx(), self.tcx.def_span(item1.def_id), E0592, diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 5cc9da25d6a..561a254e89e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -6,7 +6,7 @@ // mappings. That mapping code resides here. use crate::errors; -use rustc_errors::{error_code, struct_span_err}; +use rustc_errors::{error_code, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -45,7 +45,7 @@ fn enforce_trait_manually_implementable( // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` if tcx.trait_def(trait_def_id).deny_explicit_impl { let trait_name = tcx.item_name(trait_def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), impl_header_span, E0322, @@ -88,7 +88,7 @@ fn enforce_empty_impls_for_marker_traits( return; } - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(impl_def_id), E0715, @@ -173,7 +173,7 @@ fn check_object_overlap<'tcx>( let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { let span = tcx.def_span(impl_def_id); - struct_span_err!( + struct_span_code_err!( tcx.dcx(), span, E0371, @@ -181,7 +181,7 @@ fn check_object_overlap<'tcx>( trait_ref.self_ty(), tcx.def_path_str(trait_def_id) ) - .span_label( + .with_span_label( span, format!( "`{}` automatically implements trait `{}`", diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index d208c55055b..7b146573a1b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -1,7 +1,7 @@ //! Unsafety checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; @@ -18,14 +18,14 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0199, "implementing the trait `{}` is not unsafe", trait_ref.print_trait_sugared() ) - .span_suggestion_verbose( + .with_span_suggestion_verbose( item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), "remove `unsafe` from this trait implementation", "", @@ -35,20 +35,20 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { } (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0200, "the trait `{}` requires an `unsafe impl` declaration", trait_ref.print_trait_sugared() ) - .note(format!( + .with_note(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", trait_ref.print_trait_sugared() )) - .span_suggestion_verbose( + .with_span_suggestion_verbose( item.span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", @@ -58,20 +58,20 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { } (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), tcx.def_span(def_id), E0569, "requires an `unsafe impl` declaration due to `#[{}]` attribute", attr_name ) - .note(format!( + .with_note(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", trait_ref.print_trait_sugared() )) - .span_suggestion_verbose( + .with_span_suggestion_verbose( item.span.shrink_to_lo(), "add `unsafe` to this trait implementation", "unsafe ", diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8aeab2ca67e..c9f89a0c3ef 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -16,6 +16,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -641,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); - if !is_suggestable_infer_ty(ty) { + if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr()); @@ -673,7 +674,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { hir::TraitItemKind::Const(ty, body_id) => { tcx.ensure().type_of(def_id); if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) - && !(is_suggestable_infer_ty(ty) && body_id.is_some()) + && !(ty.is_suggestable_infer_ty() && body_id.is_some()) { // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); @@ -725,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } hir::ImplItemKind::Const(ty, _) => { // Account for `const T: _ = ..;` - if !is_suggestable_infer_ty(ty) { + if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant"); @@ -979,7 +980,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { }) // Check for duplicates .and_then(|list| { - let mut set: FxHashMap<Symbol, Span> = FxHashMap::default(); + let mut set: UnordMap<Symbol, Span> = Default::default(); let mut no_dups = true; for ident in &*list { @@ -1053,48 +1054,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } } -fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { - generic_args.iter().any(|arg| match arg { - hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty), - hir::GenericArg::Infer(_) => true, - _ => false, - }) -} - -/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to -/// use inference to provide suggestions for the appropriate type if possible. -fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { - debug!(?ty); - use hir::TyKind::*; - match &ty.kind { - Infer => true, - Slice(ty) => is_suggestable_infer_ty(ty), - Array(ty, length) => { - is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _)) - } - Tup(tys) => tys.iter().any(is_suggestable_infer_ty), - Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), - OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), - Path(hir::QPath::TypeRelative(ty, segment)) => { - is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args) - } - Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => { - ty_opt.is_some_and(is_suggestable_infer_ty) - || segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args)) - } - _ => false, - } -} - -pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { - if let hir::FnRetTy::Return(ty) = output { - if is_suggestable_infer_ty(ty) { - return Some(*ty); - } - } - None -} - #[instrument(level = "debug", skip(tcx))] fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> { use rustc_hir::Node::*; @@ -1187,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( ) -> ty::PolyFnSig<'tcx> { let hir_id = tcx.local_def_id_to_hir_id(def_id); - match get_infer_ret_ty(&sig.decl.output) { + match sig.decl.output.get_infer_ret_ty() { Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 41520718aa8..ab9ed6ef98d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,38 +38,12 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { - // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, - // because only implementing `Self: Trait<.., false>` is currently not possible. - Some(( - ty::TraitRef::new( - tcx, - def_id, - ty::GenericArgs::for_item(tcx, def_id, |param, _| { - if param.is_host_effect() { - tcx.consts.true_.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) - .to_predicate(tcx), + + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), span, - )) - } else { - None - }; - result.predicates = tcx.arena.alloc_from_iter( - result - .predicates - .iter() - .copied() - .chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), - span, - ))) - .chain(non_const_bound), - ); + )))); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result 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 9a28534d790..3d8390d1946 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -8,7 +8,7 @@ use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::fmt; use crate::errors; @@ -335,13 +335,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // though this may happen when we call `poly_trait_ref_binder_info` with // an (erroneous, #113423) associated return type bound in an impl header. if !supertrait_bound_vars.is_empty() { - self.tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!( - "found supertrait lifetimes without a binder to append \ + self.tcx.dcx().delayed_bug(format!( + "found supertrait lifetimes without a binder to append \ them to: {supertrait_bound_vars:?}" - ), - ); + )); } break (vec![], BinderScopeType::Normal); } @@ -737,7 +734,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // Ensure that the parent of the def is an item, not HRTB let parent_id = self.tcx.hir().parent_id(hir_id); if !parent_id.is_owner() { - struct_span_err!( + struct_span_code_err!( self.tcx.dcx(), lifetime.ident.span, E0657, @@ -750,12 +747,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { kind: hir::ItemKind::OpaqueTy { .. }, .. }) = self.tcx.hir_node(parent_id) { - let mut err = self.tcx.dcx().struct_span_err( + self.tcx.dcx().struct_span_err( lifetime.ident.span, "higher kinded lifetime bounds on nested opaque types are not supported yet", - ); - err.span_note(self.tcx.def_span(def_id), "lifetime declared here"); - err.emit(); + ) + .with_span_note(self.tcx.def_span(def_id), "lifetime declared here") + .emit(); self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } } @@ -2114,7 +2111,7 @@ pub fn deny_non_region_late_bound( hir::GenericParamKind::Lifetime { .. } => continue, }; - let mut diag = tcx.dcx().struct_span_err( + let diag = tcx.dcx().struct_span_err( param.span, format!("late-bound {what} parameter not allowed on {where_}"), ); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 55720e6d2aa..3ceea3dc7ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -9,8 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; +use super::bad_placeholder; use super::ItemCtxt; -use super::{bad_placeholder, is_suggestable_infer_ty}; pub use opaque::test_opaque_hidden_types; mod opaque; @@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { - is_suggestable_infer_ty(ty).then(|| { + ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( tcx, def_id, @@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Ty::new_fn_def(tcx, def_id.to_def_id(), args) } ImplItemKind::Const(ty, body_id) => { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type( tcx, def_id, @@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty Node::Item(item) => match item.kind { ItemKind::Static(ty, .., body_id) => { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type( tcx, def_id, @@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty } } ItemKind::Const(ty, _, body_id) => { - if is_suggestable_infer_ty(ty) { + if ty.is_suggestable_infer_ty() { infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") } else { icx.to_ty(ty) @@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>( } err.emit(); + // diagnostic stashing loses the information of whether something is a hard error. + Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error") } None => { let mut diag = bad_placeholder(tcx, vec![span], kind); @@ -623,15 +625,9 @@ fn infer_placeholder_type<'a>( } } - diag.emit(); + Ty::new_error(tcx, diag.emit()) } } - - // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(ty, |r, _| match *r { - ty::ReErased => tcx.lifetimes.re_static, - _ => r, - }) } fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 5a73097b0f6..1f7ca48234a 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -69,6 +69,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local Node::Item(it) => locator.visit_item(it), Node::ImplItem(it) => locator.visit_impl_item(it), Node::TraitItem(it) => locator.visit_trait_item(it), + Node::ForeignItem(it) => locator.visit_foreign_item(it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } @@ -133,6 +134,21 @@ impl TaitConstraintLocator<'_> { debug!("no constraint: no typeck results"); return; } + + if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() { + if hir_sig.output.get_infer_ret_ty().is_some() { + let guar = self.tcx.dcx().span_delayed_bug( + hir_sig.output.span(), + "inferring return types and opaque types do not mix well", + ); + self.found = Some(ty::OpaqueHiddenType { + span: DUMMY_SP, + ty: Ty::new_error(self.tcx, guar), + }); + return; + } + } + // Calling `mir_borrowck` can lead to cycle errors through // const-checking, avoid calling it if we don't have to. // ```rust @@ -240,6 +256,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + trace!(?it.owner_id); + assert_ne!(it.owner_id.def_id, self.def_id); + // No need to call `check`, as we do not run borrowck on foreign items. + intravisit::walk_foreign_item(self, it); + } } pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 75e7a5524a7..4f22da4ba3b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -319,10 +319,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for MissingTypeParams { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut err = DiagnosticBuilder::new(dcx, level, fluent::hir_analysis_missing_type_params); - err.set_span(self.span); + err.span(self.span); err.code(error_code!(E0393)); - err.set_arg("parameterCount", self.missing_type_params.len()); - err.set_arg( + err.arg("parameterCount", self.missing_type_params.len()); + err.arg( "parameters", self.missing_type_params .iter() @@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> { pub mut_key: &'a str, pub ptr_ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_static_mut_ref, code = "E0796")] +#[note] +pub struct StaticMutRef { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: StaticMutRefSugg, +} + +#[derive(Subdiagnostic)] +pub enum StaticMutRefSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} + +// STATIC_MUT_REF lint +#[derive(LintDiagnostic)] +#[diag(hir_analysis_static_mut_ref_lint)] +#[note] +pub struct RefOfMutStatic<'a> { + pub shared: &'a str, + #[note(hir_analysis_why_note)] + pub why_note: (), + #[subdiagnostic] + pub label: RefOfMutStaticLabel, + #[subdiagnostic] + pub sugg: RefOfMutStaticSugg, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticLabel { + #[label(hir_analysis_label)] + Shared { + #[primary_span] + span: Span, + }, + #[label(hir_analysis_label_mut)] + Mut { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub enum RefOfMutStaticSugg { + #[suggestion( + hir_analysis_suggestion, + style = "verbose", + code = "addr_of!({var})", + applicability = "maybe-incorrect" + )] + Shared { + #[primary_span] + span: Span, + var: String, + }, + #[suggestion( + hir_analysis_suggestion_mut, + style = "verbose", + code = "addr_of_mut!({var})", + applicability = "maybe-incorrect" + )] + Mut { + #[primary_span] + span: Span, + var: String, + }, +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index ff5fff9363f..3f9b1f384d7 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -12,7 +12,7 @@ use crate::constrained_generic_params as cgp; use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; @@ -170,7 +170,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) } fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), span, E0207, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 81d8982eb15..dfc54ac5b23 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -166,13 +166,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { // this ensures that later parts of type checking can assume that items // have valid types and not error - // FIXME(matthewjasper) We shouldn't need to use `track_errors`. - tcx.sess.track_errors(|| { - tcx.sess.time("type_collecting", || { - tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) - }); - })?; + tcx.sess.time("type_collecting", || { + tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) + }); + // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function + // or the compiler in general. if tcx.features().rustc_attrs { tcx.sess.track_errors(|| { tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); @@ -200,18 +199,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; } - let errs = tcx.sess.time("wf_checking", || { + tcx.sess.time("wf_checking", || { tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) - }); - - // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. - tcx.sess.time("item_types_checking", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) - }); - - // HACK: `check_mod_type_wf` may spuriously emit errors due to `span_delayed_bug`, even if - // those errors only actually get emitted in `check_mod_item_types`. - errs?; + })?; if tcx.features().rustc_attrs { tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index c17925471d9..0cb38094cec 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -59,6 +59,17 @@ pub(super) fn infer_predicates( } } + DefKind::TyAlias if tcx.type_alias_is_lazy(item_did) => { + insert_required_predicates_to_be_wf( + tcx, + tcx.type_of(item_did).instantiate_identity(), + tcx.def_span(item_did), + &global_inferred_outlives, + &mut item_required_predicates, + &mut explicit_map, + ); + } + _ => {} }; @@ -88,14 +99,14 @@ pub(super) fn infer_predicates( fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, - field_ty: Ty<'tcx>, - field_span: Span, + ty: Ty<'tcx>, + span: Span, global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { - for arg in field_ty.walk() { - let ty = match arg.unpack() { + for arg in ty.walk() { + let leaf_ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, // No predicates from lifetimes or constants, except potentially @@ -103,63 +114,26 @@ fn insert_required_predicates_to_be_wf<'tcx>( GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, }; - match *ty.kind() { - // The field is of type &'a T which means that we will have - // a predicate requirement of T: 'a (T outlives 'a). - // - // We also want to calculate potential predicates for the T + match *leaf_ty.kind() { ty::Ref(region, rty, _) => { + // The type is `&'a T` which means that we will have + // a predicate requirement of `T: 'a` (`T` outlives `'a`). + // + // We also want to calculate potential predicates for the `T`. debug!("Ref"); - insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates); + insert_outlives_predicate(tcx, rty.into(), region, span, required_predicates); } - // For each Adt (struct/enum/union) type `Foo<'a, T>`, we - // can load the current set of inferred and explicit - // predicates from `global_inferred_outlives` and filter the - // ones that are TypeOutlives. ty::Adt(def, args) => { - // First check the inferred predicates - // - // Example 1: - // - // struct Foo<'a, T> { - // field1: Bar<'a, T> - // } - // - // struct Bar<'b, U> { - // field2: &'b U - // } - // - // Here, when processing the type of `field1`, we would - // request the set of implicit predicates computed for `Bar` - // thus far. This will initially come back empty, but in next - // round we will get `U: 'b`. We then apply the substitution - // `['b => 'a, U => T]` and thus get the requirement that `T: - // 'a` holds for `Foo`. + // For ADTs (structs/enums/unions), we check inferred and explicit predicates. debug!("Adt"); - if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) { - for (unsubstituted_predicate, &span) in - unsubstituted_predicates.as_ref().skip_binder() - { - // `unsubstituted_predicate` is `U: 'b` in the - // example above. So apply the substitution to - // get `T: 'a` (or `predicate`): - let predicate = unsubstituted_predicates - .rebind(*unsubstituted_predicate) - .instantiate(tcx, args); - insert_outlives_predicate( - tcx, - predicate.0, - predicate.1, - span, - required_predicates, - ); - } - } - - // Check if the type has any explicit predicates that need - // to be added to `required_predicates` - // let _: () = args.region_at(0); + check_inferred_predicates( + tcx, + def.did(), + args, + global_inferred_outlives, + required_predicates, + ); check_explicit_predicates( tcx, def.did(), @@ -170,13 +144,31 @@ fn insert_required_predicates_to_be_wf<'tcx>( ); } + ty::Alias(ty::Weak, alias) => { + // This corresponds to a type like `Type<'a, T>`. + // We check inferred and explicit predicates. + debug!("Weak"); + check_inferred_predicates( + tcx, + alias.def_id, + alias.args, + global_inferred_outlives, + required_predicates, + ); + check_explicit_predicates( + tcx, + alias.def_id, + alias.args, + required_predicates, + explicit_map, + None, + ); + } + ty::Dynamic(obj, ..) => { // This corresponds to `dyn Trait<..>`. In this case, we should // use the explicit predicates as well. - debug!("Dynamic"); - debug!("field_ty = {}", &field_ty); - debug!("ty in field = {}", &ty); if let Some(ex_trait_ref) = obj.principal() { // Here, we are passing the type `usize` as a // placeholder value with the function @@ -198,21 +190,22 @@ fn insert_required_predicates_to_be_wf<'tcx>( } } - ty::Alias(ty::Projection, obj) => { - // This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the - // explicit predicates as well. + ty::Alias(ty::Projection, alias) => { + // This corresponds to a type like `<() as Trait<'a, T>>::Type`. + // We only use the explicit predicates of the trait but + // not the ones of the associated type itself. debug!("Projection"); check_explicit_predicates( tcx, - tcx.parent(obj.def_id), - obj.args, + tcx.parent(alias.def_id), + alias.args, required_predicates, explicit_map, None, ); } - // FIXME(inherent_associated_types): Handle this case properly. + // FIXME(inherent_associated_types): Use the explicit predicates from the parent impl. ty::Alias(ty::Inherent, _) => {} _ => {} @@ -220,19 +213,21 @@ fn insert_required_predicates_to_be_wf<'tcx>( } } -/// We also have to check the explicit predicates -/// declared on the type. +/// Check the explicit predicates declared on the type. +/// +/// ### Example +/// /// ```ignore (illustrative) -/// struct Foo<'a, T> { -/// field1: Bar<T> +/// struct Outer<'a, T> { +/// field: Inner<T>, /// } /// -/// struct Bar<U> where U: 'static, U: Foo { -/// ... +/// struct Inner<U> where U: 'static, U: Outer { +/// // ... /// } /// ``` /// Here, we should fetch the explicit predicates, which -/// will give us `U: 'static` and `U: Foo`. The latter we +/// will give us `U: 'static` and `U: Outer`. The latter we /// can ignore, but we will want to process `U: 'static`, /// applying the substitution as above. fn check_explicit_predicates<'tcx>( @@ -303,3 +298,45 @@ fn check_explicit_predicates<'tcx>( insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates); } } + +/// Check the inferred predicates declared on the type. +/// +/// ### Example +/// +/// ```ignore (illustrative) +/// struct Outer<'a, T> { +/// outer: Inner<'a, T>, +/// } +/// +/// struct Inner<'b, U> { +/// inner: &'b U, +/// } +/// ``` +/// +/// Here, when processing the type of field `outer`, we would request the +/// set of implicit predicates computed for `Inner` thus far. This will +/// initially come back empty, but in next round we will get `U: 'b`. +/// We then apply the substitution `['b => 'a, U => T]` and thus get the +/// requirement that `T: 'a` holds for `Outer`. +fn check_inferred_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + required_predicates: &mut RequiredPredicates<'tcx>, +) { + // Load the current set of inferred and explicit predicates from `global_inferred_outlives` + // and filter the ones that are `TypeOutlives`. + + let Some(predicates) = global_inferred_outlives.get(&def_id) else { + return; + }; + + for (&predicate, &span) in predicates.as_ref().skip_binder() { + // `predicate` is `U: 'b` in the example above. + // So apply the substitution to get `T: 'a`. + let ty::OutlivesPredicate(arg, region) = + predicates.rebind(predicate).instantiate(tcx, args); + insert_outlives_predicate(tcx, arg, region, span, required_predicates); + } +} diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 72511bfa01f..a87112dcc12 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -21,6 +21,10 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau let crate_map = tcx.inferred_outlives_crate(()); crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) } + DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => { + let crate_map = tcx.inferred_outlives_crate(()); + crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) + } DefKind::AnonConst if tcx.features().generic_const_exprs => { let id = tcx.local_def_id_to_hir_id(item_def_id); if tcx.hir().opt_const_param_default_param_def_id(id).is_some() { @@ -47,8 +51,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau } fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { - // Compute a map from each struct/enum/union S to the **explicit** - // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote. + // Compute a map from each ADT (struct/enum/union) and lazy type alias to + // the **explicit** outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote. // Typically there won't be many of these, except in older code where // they were mandatory. Nonetheless, we have to ensure that every such // predicate is satisfied, so they form a kind of base set of requirements 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 ae68a8bf281..6657e3fd872 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 @@ -523,8 +523,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx> { let span = self.path_segment.ident.span; let msg = self.create_error_message(); - - self.tcx.dcx().struct_span_err_with_code(span, msg, self.code()) + self.tcx.dcx().struct_span_err(span, msg).with_code(self.code()) } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d6eea07cfbc..1eaec997053 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1874,17 +1874,9 @@ impl<'a> State<'a> { self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { - match *g { - hir::Guard::If(e) => { - self.word_space("if"); - self.print_expr(e); - self.space(); - } - hir::Guard::IfLet(&hir::Let { pat, ty, init, .. }) => { - self.word_nbsp("if"); - self.print_let(pat, ty, init); - } - } + self.word_space("if"); + self.print_expr(g); + self.space(); } self.word_space("=>"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 181de372840..cf1f232229d 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -78,16 +78,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut other_arms = vec![]; // Used only for diagnostics. let mut prior_arm = None; for arm in arms { - if let Some(g) = &arm.guard { + if let Some(e) = &arm.guard { self.diverges.set(Diverges::Maybe); - match g { - hir::Guard::If(e) => { - self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); - } - hir::Guard::IfLet(l) => { - self.check_expr_let(l); - } - }; + self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); } self.diverges.set(Diverges::Maybe); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index de2cb5a6d5c..1a4e03d50ca 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> { callee_expr.span, format!("evaluate({predicate:?}) = {result:?}"), ) - .span_label(predicate_span, "predicate") + .with_span_label(predicate_span, "predicate") .emit(); } } @@ -490,11 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span)); let fn_once_output_def_id = self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span)); - if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() { - if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { - self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); - } - } else { + if self.tcx.has_host_param(fn_once_def_id) { let const_param: ty::GenericArg<'tcx> = ([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into(); self.register_predicate(traits::Obligation::new( @@ -523,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); self.select_obligations_where_possible(|_| {}); + } else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) { + self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); } } else { self.dcx().emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty }); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 63185444479..a720a858f3c 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } CastError::NeedViaInt => { make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx) - .help("cast through an integer first") + .with_help("cast through an integer first") .emit(); } CastError::IllegalCast => { @@ -277,7 +277,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } CastError::DifferingKinds => { make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx) - .note("vtable kinds may not match") + .with_note("vtable kinds may not match") .emit(); } CastError::CastToBool => { @@ -512,7 +512,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty, fcx, ) - .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") + .with_note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") .emit(); } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2a408ac255c..c887368b2a2 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -28,10 +28,10 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; pub(super) fn check_fn<'a, 'tcx>( fcx: &mut FnCtxt<'a, 'tcx>, fn_sig: ty::FnSig<'tcx>, + coroutine_types: Option<CoroutineTypes<'tcx>>, decl: &'tcx hir::FnDecl<'tcx>, fn_def_id: LocalDefId, body: &'tcx hir::Body<'tcx>, - closure_kind: Option<hir::ClosureKind>, params_can_be_unsized: bool, ) -> Option<CoroutineTypes<'tcx>> { let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id); @@ -49,54 +49,13 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.param_env, )); + fcx.coroutine_types = coroutine_types; fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); let span = body.value.span; forbid_intrinsic_abi(tcx, span, fn_sig.abi); - if let Some(hir::ClosureKind::Coroutine(kind)) = closure_kind { - let yield_ty = match kind { - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) - | hir::CoroutineKind::Coroutine(_) => { - let yield_ty = fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - yield_ty - } - // HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly - // guide inference on the yield type so that we can handle `AsyncIterator` - // in this block in projection correctly. In the new trait solver, it is - // not a problem. - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { - let yield_ty = fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - - Ty::new_adt( - tcx, - tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, Some(span))), - tcx.mk_args(&[Ty::new_adt( - tcx, - tcx.adt_def(tcx.require_lang_item(hir::LangItem::Option, Some(span))), - tcx.mk_args(&[yield_ty.into()]), - ) - .into()]), - ) - } - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => Ty::new_unit(tcx), - }; - - // Resume type defaults to `()` if the coroutine has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx)); - - fcx.resume_yield_tys = Some((resume_ty, yield_ty)); - } - GatherLocalsVisitor::new(fcx).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` @@ -114,7 +73,8 @@ pub(super) fn check_fn<'a, 'tcx>( let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. - let ty_span = try { inputs_hir?.get(idx)?.span }; + let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? }; + let ty_span = ty.map(|ty| ty.span); fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); // Check that argument is Sized. @@ -122,14 +82,14 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.require_type_is_sized( param_ty, param.pat.span, - // ty_span == binding_span iff this is a closure parameter with no type ascription, + // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter traits::SizedArgumentType( if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into()) { None } else { - ty_span + ty.map(|ty| ty.hir_id) }, ), ); @@ -147,25 +107,6 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); fcx.check_return_expr(body.value, false); - // We insert the deferred_coroutine_interiors entry after visiting the body. - // This ensures that all nested coroutines appear before the entry of this coroutine. - // resolve_coroutine_interiors relies on this property. - let coroutine_ty = if let Some(hir::ClosureKind::Coroutine(coroutine_kind)) = closure_kind { - let interior = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_coroutine_interiors.borrow_mut().push(( - fn_def_id, - body.id(), - interior, - coroutine_kind, - )); - - let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(CoroutineTypes { resume_ty, yield_ty, interior }) - } else { - None - }; - // Finalize the return check by taking the LUB of the return types // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed @@ -201,7 +142,7 @@ pub(super) fn check_fn<'a, 'tcx>( check_lang_start_fn(tcx, fn_sig, fn_def_id); } - coroutine_ty + fcx.coroutine_types } fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index bf6fda20df8..7edb5912dd5 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -72,7 +72,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_kind: Option<ty::ClosureKind>, expected_sig: Option<ExpectedSig<'tcx>>, ) -> Ty<'tcx> { - let body = self.tcx.hir().body(closure.body); + let tcx = self.tcx; + let body = tcx.hir().body(closure.body); trace!("decl = {:#?}", closure.fn_decl); let expr_def_id = closure.def_id; @@ -83,81 +84,151 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); + // FIXME: We could probably actually just unify this further -- + // instead of having a `FnSig` and a `Option<CoroutineTypes>`, + // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`, + // similar to how `ty::GenSig` is a distinct data structure. + let coroutine_types = match closure.kind { + hir::ClosureKind::Closure => None, + hir::ClosureKind::Coroutine(kind) => { + let yield_ty = match kind { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + | hir::CoroutineKind::Coroutine(_) => { + let yield_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: expr_span, + }); + self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); + yield_ty + } + // HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly + // guide inference on the yield type so that we can handle `AsyncIterator` + // in this block in projection correctly. In the new trait solver, it is + // not a problem. + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { + let yield_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: expr_span, + }); + self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); + + Ty::new_adt( + tcx, + tcx.adt_def( + tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)), + ), + tcx.mk_args(&[Ty::new_adt( + tcx, + tcx.adt_def( + tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)), + ), + tcx.mk_args(&[yield_ty.into()]), + ) + .into()]), + ) + } + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { + tcx.types.unit + } + }; + + // Resume type defaults to `()` if the coroutine has no argument. + let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); + + Some(CoroutineTypes { resume_ty, yield_ty }) + } + }; + let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id); - let coroutine_types = check_fn( + check_fn( &mut fcx, liberated_sig, + coroutine_types, closure.fn_decl, expr_def_id, body, - Some(closure.kind), // Closure "rust-call" ABI doesn't support unsized params false, ); - let parent_args = GenericArgs::identity_for_item( - self.tcx, - self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), - ); + let parent_args = + GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, - span: self.tcx.def_span(expr_def_id), - }); - - if let Some(CoroutineTypes { resume_ty, yield_ty, interior }) = coroutine_types { - let coroutine_args = ty::CoroutineArgs::new( - self.tcx, - ty::CoroutineArgsParts { - parent_args, - resume_ty, - yield_ty, - return_ty: liberated_sig.output(), - witness: interior, - tupled_upvars_ty, - }, - ); - - return Ty::new_coroutine(self.tcx, expr_def_id.to_def_id(), coroutine_args.args); - } - - // Tuple up the arguments and insert the resulting function type into - // the `closures` table. - let sig = bound_sig.map_bound(|sig| { - self.tcx.mk_fn_sig( - [Ty::new_tup(self.tcx, sig.inputs())], - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ) + span: expr_span, }); - debug!(?sig, ?opt_kind); - - let closure_kind_ty = match opt_kind { - Some(kind) => Ty::from_closure_kind(self.tcx, kind), + match closure.kind { + hir::ClosureKind::Closure => { + assert_eq!(coroutine_types, None); + // Tuple up the arguments and insert the resulting function type into + // the `closures` table. + let sig = bound_sig.map_bound(|sig| { + tcx.mk_fn_sig( + [Ty::new_tup(tcx, sig.inputs())], + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }); - // Create a type variable (for now) to represent the closure kind. - // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.next_root_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish closure kind inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }), - }; + debug!(?sig, ?opt_kind); + + let closure_kind_ty = match opt_kind { + Some(kind) => Ty::from_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_root_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + + let closure_args = ty::ClosureArgs::new( + tcx, + ty::ClosureArgsParts { + parent_args, + closure_kind_ty, + closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), + tupled_upvars_ty, + }, + ); - let closure_args = ty::ClosureArgs::new( - self.tcx, - ty::ClosureArgsParts { - parent_args, - closure_kind_ty, - closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig), - tupled_upvars_ty, - }, - ); + Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args) + } + hir::ClosureKind::Coroutine(_) => { + let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else { + bug!("expected coroutine to have yield/resume types"); + }; + let interior = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: body.value.span, + }); + fcx.deferred_coroutine_interiors.borrow_mut().push(( + expr_def_id, + body.id(), + interior, + )); + + let coroutine_args = ty::CoroutineArgs::new( + tcx, + ty::CoroutineArgsParts { + parent_args, + resume_ty, + yield_ty, + return_ty: liberated_sig.output(), + witness: interior, + tupled_upvars_ty, + }, + ); - Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_args.args) + Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args) + } + } } /// Given the expected type, figures out what it can about this closure we diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1aa25a5bd7f..0b266202b26 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,7 +36,7 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -1571,7 +1571,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; match *cause.code() { ObligationCauseCode::ReturnNoExpression => { - err = struct_span_err!( + err = struct_span_code_err!( fcx.dcx(), cause.span, E0069, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index c717319e507..9850892bd36 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Requires that the two types unify, and prints an error message if /// they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) { + if let Some(e) = self.demand_suptype_diag(sp, expected, actual) { e.emit(); } } @@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) { + if let Some(err) = self.demand_eqtype_diag(sp, expected, actual) { err.emit(); } } @@ -228,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); - if let Some(mut err) = err { + if let Some(err) = err { err.emit(); } ty diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index ff03cf16a27..4f929068887 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -215,7 +215,7 @@ impl AddToDiagnostic for TypeMismatchFruTypo { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.set_arg("expr", self.expr.as_deref().unwrap_or("NONE")); + diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up if self.expr_span.between(self.fru_span).is_empty() { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7425d6f8901..fdad998c451 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -15,6 +15,7 @@ use crate::errors::{ use crate::fatally_break_rust; use crate::method::SelfSource; use crate::type_error_struct; +use crate::CoroutineTypes; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; use crate::{ report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs, @@ -24,7 +25,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, + pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, StashKey, }; use rustc_hir as hir; @@ -939,12 +940,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // FIXME: Make this use Diagnostic once error codes can be dynamically set. - let mut err = self.dcx().struct_span_err_with_code( - op_span, - "invalid left-hand side of assignment", - DiagnosticId::Error(err_code.into()), - ); + let mut err = self.dcx().struct_span_err(op_span, "invalid left-hand side of assignment"); + err.code(DiagnosticId::Error(err_code.into())); err.span_label(lhs.span, "cannot assign to this expression"); self.comes_from_while_condition(lhs.hir_id, |expr| { @@ -1337,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - if let Some(mut err) = self.report_method_error( + if let Some(err) = self.report_method_error( span, rcvr_t, segment.ident, @@ -1763,7 +1760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure the programmer specified correct number of fields. if adt_kind == AdtKind::Union { if ast_fields.len() != 1 { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), span, E0784, @@ -1970,7 +1967,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0063, @@ -2010,7 +2007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { != range_def_id { // Suppress any range expr type mismatches - if let Some(mut diag) = + if let Some(diag) = self.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo) { diag.delay_as_bug(); @@ -2197,7 +2194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = self.err_ctxt().type_error_struct_with_diag( field.ident.span, |actual| match ty.kind() { - ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!( + ty::Adt(adt, ..) if adt.is_enum() => struct_span_code_err!( self.dcx(), field.ident.span, E0559, @@ -2207,7 +2204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant.name, field.ident ), - _ => struct_span_err!( + _ => struct_span_code_err!( self.dcx(), field.ident.span, E0560, @@ -2835,15 +2832,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn private_field_err(&self, field: Ident, base_did: DefId) -> DiagnosticBuilder<'_> { let struct_path = self.tcx().def_path_str(base_did); let kind_name = self.tcx().def_descr(base_did); - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), field.span, E0616, "field `{field}` of {kind_name} `{struct_path}` is private", - ); - err.span_label(field.span, "private field"); - - err + ) + .with_span_label(field.span, "private field") } pub(crate) fn get_field_candidates_considering_privacy( @@ -3163,8 +3158,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { - match self.resume_yield_tys { - Some((resume_ty, yield_ty)) => { + match self.coroutine_types { + Some(CoroutineTypes { resume_ty, yield_ty }) => { self.check_expr_coercible_to_type(value, yield_ty, None); resume_ty @@ -3184,9 +3179,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); if !is_input && !expr.is_syntactic_place_expr() { - let mut err = self.dcx().struct_span_err(expr.span, "invalid asm output"); - err.span_label(expr.span, "cannot assign to this expression"); - err.emit(); + self.dcx() + .struct_span_err(expr.span, "invalid asm output") + .with_span_label(expr.span, "cannot assign to this expression") + .emit(); } // If this is an input value, we require its type to be fully resolved @@ -3279,27 +3275,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0599, "no variant named `{ident}` found for enum `{container}`", - ); - err.span_label(field.span, "variant not found"); - err.emit(); + ) + .with_span_label(field.span, "variant not found") + .emit(); break; }; let Some(&subfield) = fields.next() else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0795, "`{ident}` is an enum variant; expected field at end of `offset_of`", - ); - err.span_label(field.span, "enum variant"); - err.emit(); + ) + .with_span_label(field.span, "enum variant") + .emit(); break; }; let (subident, sub_def_scope) = @@ -3310,16 +3306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else { - let mut err = type_error_struct!( + type_error_struct!( self.dcx(), ident.span, container, E0609, "no field named `{subfield}` on enum variant `{container}::{ident}`", - ); - err.span_label(field.span, "this enum variant..."); - err.span_label(subident.span, "...does not have this field"); - err.emit(); + ) + .with_span_label(field.span, "this enum variant...") + .with_span_label(subident.span, "...does not have this field") + .emit(); break; }; diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index e952a7ff9e8..ed3dd1e39df 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -669,12 +669,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); - match arm.guard { - Some(hir::Guard::If(e)) => self.consume_expr(e), - Some(hir::Guard::IfLet(l)) => { - self.walk_local(l.init, l.pat, None, |t| t.borrow_expr(l.init, ty::ImmBorrow)) - } - None => {} + if let Some(ref e) = arm.guard { + self.consume_expr(e) } self.consume_expr(arm.body); diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 023bd70be17..aa8bbad1d12 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -85,7 +85,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } - // not setting the `fallback_has_occured` field here because + // not setting the `fallback_has_occurred` field here because // that field is only used for type fallback diagnostics. for effect in unsolved_effects { let expected = self.tcx.consts.true_; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 994f11b57d1..a4cd9ccc984 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -534,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coroutines = std::mem::take(&mut *self.deferred_coroutine_interiors.borrow_mut()); debug!(?coroutines); - for &(expr_def_id, body_id, interior, _) in coroutines.iter() { + for &(expr_def_id, body_id, interior) in coroutines.iter() { debug!(?expr_def_id); // Create the `CoroutineWitness` type that we will unify with `interior`. @@ -845,7 +845,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|r| { // lint bare trait if the method is found in the trait if span.edition().at_least_rust_2021() - && let Some(mut diag) = + && let Some(diag) = self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { diag.emit(); @@ -877,7 +877,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // emit or cancel the diagnostic for bare traits if span.edition().at_least_rust_2021() - && let Some(mut diag) = + && let Some(diag) = self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { if trait_missing_method { @@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if item_name.name != kw::Empty { - if let Some(mut e) = self.report_method_error( + if let Some(e) = self.report_method_error( span, ty.normalized, item_name, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7b85c492eae..8cd5ed3494b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -6,7 +6,8 @@ use crate::method::MethodCallee; use crate::TupleArgumentsFlag::*; use crate::{errors, Expectation::*}; use crate::{ - struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, Needs, RawTy, TupleArgumentsFlag, + struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, Needs, RawTy, + TupleArgumentsFlag, }; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; @@ -204,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { // Otherwise, there's a mismatch, so clear out what we're expecting, and set // our input types to err_args so we don't blow up the error messages - struct_span_err!( + struct_span_code_err!( tcx.dcx(), call_span, E0059, @@ -664,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {call_name} are incorrect"), ); } else { - err = tcx.dcx().struct_span_err_with_code( + err = tcx.dcx().struct_span_err( full_call_span, format!( "{call_name} takes {}{} but {} {} supplied", @@ -676,8 +677,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { potentially_plural_count(provided_args.len(), "argument"), pluralize!("was", provided_args.len()) ), - DiagnosticId::Error(err_code.to_owned()), ); + err.code(DiagnosticId::Error(err_code.to_owned())); err.multipart_suggestion_verbose( "wrap these arguments in parentheses to construct a tuple", vec![ @@ -807,7 +808,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut err = if formal_and_expected_inputs.len() == provided_args.len() { - struct_span_err!( + struct_span_code_err!( tcx.dcx(), full_call_span, E0308, @@ -815,18 +816,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_name, ) } else { - tcx.dcx().struct_span_err_with_code( - full_call_span, - format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(formal_and_expected_inputs.len(), "argument"), - potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) - ), - DiagnosticId::Error(err_code.to_owned()), - ) + tcx.dcx() + .struct_span_err( + full_call_span, + format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(formal_and_expected_inputs.len(), "argument"), + potentially_plural_count(provided_args.len(), "argument"), + pluralize!("was", provided_args.len()) + ), + ) + .with_code(DiagnosticId::Error(err_code.to_owned())) }; // As we encounter issues, keep track of what we want to provide for the suggestion @@ -1377,14 +1379,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (issue #88844). guar } - _ => struct_span_err!( + _ => struct_span_code_err!( self.dcx(), path_span, E0071, "expected struct, variant or union type, found {}", ty.normalized.sort_string(self.tcx) ) - .span_label(path_span, "not a struct") + .with_span_label(path_span, "not a struct") .emit(), }) } @@ -1459,8 +1461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); - if let Some(mut err) = - self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + if let Some(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) { err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 635284c5f73..fde3d41faec 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -5,7 +5,7 @@ mod checks; mod suggestions; use crate::coercion::DynamicCoerceMany; -use crate::{Diverges, EnclosingBreakables, Inherited}; +use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited}; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -68,7 +68,7 @@ pub struct FnCtxt<'a, 'tcx> { /// First span of a return site that we find. Used in error messages. pub(super) ret_coercion_span: Cell<Option<Span>>, - pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, + pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>, /// Whether the last checked node generates a divergence (e.g., /// `return` will set this to `Always`). In general, when entering @@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err_count_on_creation: inh.tcx.dcx().err_count(), ret_coercion: None, ret_coercion_span: Cell::new(None), - resume_yield_tys: None, + coroutine_types: None, diverges: Cell::new(Diverges::Maybe), enclosing_breakables: RefCell::new(EnclosingBreakables { stack: Vec::new(), diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index e169b45d725..52dc1e85916 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -60,7 +60,7 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> { // parameters are special cases of patterns, but we want to handle them as // *distinct* cases. so track when we are hitting a pattern *within* an fn // parameter. - outermost_fn_param_pat: Option<Span>, + outermost_fn_param_pat: Option<(Span, hir::HirId)>, } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { @@ -131,7 +131,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span); + let old_outermost_fn_param_pat = + self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id)); intravisit::walk_param(self, param); self.outermost_fn_param_pat = old_outermost_fn_param_pat; } @@ -141,7 +142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if let PatKind::Binding(_, _, ident, _) = p.kind { let var_ty = self.assign(p.span, p.hir_id, None); - if let Some(ty_span) = self.outermost_fn_param_pat { + if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat { if !self.fcx.tcx.features().unsized_fn_params { self.fcx.require_type_is_sized( var_ty, @@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { { None } else { - Some(ty_span) + Some(hir_id) }, ), ); diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 7a6a2b2a010..4ad46845f0b 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -55,8 +55,7 @@ pub struct Inherited<'tcx> { pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>, - pub(super) deferred_coroutine_interiors: - RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::CoroutineKind)>>, + pub(super) deferred_coroutine_interiors: RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>)>>, /// Whenever we introduce an adjustment from `!` into a type variable, /// we record that type variable here. This is later used to inform diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 44d28123fa3..e087733130e 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -1,5 +1,5 @@ use hir::HirId; -use rustc_errors::struct_span_err; +use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; @@ -73,10 +73,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { - struct_span_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type") - .note(format!("source type: {from}")) - .note(format!("target type: {to}")) - .help("cast with `as` to a pointer instead") + struct_span_code_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type") + .with_note(format!("source type: {from}")) + .with_note(format!("target type: {to}")) + .with_help("cast with `as` to a pointer instead") .emit(); return; } @@ -112,7 +112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(err) => err.to_string(), }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), span, E0512, @@ -121,6 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if from == to { err.note(format!("`{from}` does not have a fixed size")); + err.emit(); } else { err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); @@ -128,8 +129,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.delay_as_bug(); } else if let Err(LayoutError::ReferencesError(_)) = sk_to { err.delay_as_bug(); + } else { + err.emit(); } } - err.emit(); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index da9a2bde783..36dd06d944c 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -52,7 +52,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::RawTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{struct_span_code_err, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -72,7 +72,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[macro_export] macro_rules! type_error_struct { ($dcx:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ - let mut err = rustc_errors::struct_span_err!($dcx, $span, $code, $($message)*); + let mut err = rustc_errors::struct_span_code_err!($dcx, $span, $code, $($message)*); if $typ.references_error() { err.downgrade_to_delayed_bug(); @@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>( let mut fcx = FnCtxt::new(&inh, param_env, def_id); if let Some(hir::FnSig { header, decl, .. }) = fn_sig { - let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { + let fn_sig = if decl.output.get_infer_ret_ty().is_some() { fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None) } else { tcx.fn_sig(def_id).instantiate_identity() @@ -193,7 +193,7 @@ fn typeck_with_fallback<'tcx>( let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig); - check_fn(&mut fcx, fn_sig, decl, def_id, body, None, tcx.features().unsized_fn_params); + check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params); } else { let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty { Some(fcx.next_ty_var(TypeVariableOrigin { @@ -295,15 +295,13 @@ fn typeck_with_fallback<'tcx>( /// When `check_fn` is invoked on a coroutine (i.e., a body that /// includes yield), it returns back some information about the yield /// points. +#[derive(Debug, PartialEq, Copy, Clone)] struct CoroutineTypes<'tcx> { /// Type of coroutine argument / values returned by `yield`. resume_ty: Ty<'tcx>, /// Type of value that is yielded. yield_ty: Ty<'tcx>, - - /// Types that are captured (see `CoroutineInterior` for more). - interior: Ty<'tcx>, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -368,18 +366,17 @@ fn report_unexpected_variant_res( _ => res.descr(), }; let path_str = rustc_hir_pretty::qpath_to_string(qpath); - let mut err = tcx.dcx().struct_span_err_with_code( - span, - format!("expected {expected}, found {res_descr} `{path_str}`"), - DiagnosticId::Error(err_code.into()), - ); + let err = tcx + .dcx() + .struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`")) + .with_code(DiagnosticId::Error(err_code.into())); match res { Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => { let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html"; - err.span_label(span, "`fn` calls are not allowed in patterns"); - err.help(format!("for more information, visit {patterns_url}")) + err.with_span_label(span, "`fn` calls are not allowed in patterns") + .with_help(format!("for more information, visit {patterns_url}")) } - _ => err.span_label(span, format!("not a {expected}")), + _ => err.with_span_label(span, format!("not a {expected}")), } .emit() } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 47fdd64796e..1f01c6b7406 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::StashKey; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, + pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -148,7 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } MethodError::Ambiguity(mut sources) => { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), item_name.span, E0034, @@ -171,7 +171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => { let kind = self.tcx.def_kind_descr(kind, def_id); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), item_name.span, E0624, @@ -263,8 +263,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'_> { let mut file = None; let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file); - let mut err = - struct_span_err!(self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", ty_str); + let mut err = struct_span_code_err!( + self.dcx(), + rcvr_expr.span, + E0599, + "cannot write into `{}`", + ty_str + ); err.span_note( rcvr_expr.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", @@ -913,7 +918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ((span, add_where_or_comma), obligations) in type_params.into_iter() { restrict_type_params = true; // #74886: Sort here so that the output is always the same. - let obligations = obligations.to_sorted_stable_ord(); + let obligations = obligations.into_sorted_stable_ord(); err.span_suggestion_verbose( span, format!( @@ -961,7 +966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { but its trait bounds were not satisfied" ) }); - err.set_primary_message(primary_message); + err.primary_message(primary_message); if let Some(label) = label { custom_span_label = true; err.span_label(span, label); @@ -1836,7 +1841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !actual.has_concrete_skeleton() && let SelfSource::MethodCall(expr) = source { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), span, E0689, @@ -2252,6 +2257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diagnostic, errors: Vec<FulfillmentError<'tcx>>, + suggest_derive: bool, ) { let all_local_types_needing_impls = errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { @@ -2322,10 +2328,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone()))) .collect(); - self.suggest_derive(err, &preds); + if suggest_derive { + self.suggest_derive(err, &preds); + } else { + // The predicate comes from a binop where the lhs and rhs have different types. + let _ = self.note_predicate_source_and_get_derives(err, &preds); + } } - pub fn suggest_derive( + fn note_predicate_source_and_get_derives( &self, err: &mut Diagnostic, unsatisfied_predicates: &[( @@ -2333,7 +2344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>, )], - ) { + ) -> Vec<(String, Span, Symbol)> { let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut traits = Vec::new(); for (pred, _, _) in unsatisfied_predicates { @@ -2382,21 +2393,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits.sort(); traits.dedup(); - derives.sort(); - derives.dedup(); - - let mut derives_grouped = Vec::<(String, Span, String)>::new(); - for (self_name, self_span, trait_name) in derives.into_iter() { - 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()); - continue; - } - } - derives_grouped.push((self_name, self_span, trait_name.to_string())); - } - let len = traits.len(); if len > 0 { let span = @@ -2419,6 +2415,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + derives + } + + pub(crate) fn suggest_derive( + &self, + err: &mut Diagnostic, + unsatisfied_predicates: &[( + ty::Predicate<'tcx>, + Option<ty::Predicate<'tcx>>, + Option<ObligationCause<'tcx>>, + )], + ) { + let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates); + derives.sort(); + derives.dedup(); + + let mut derives_grouped = Vec::<(String, Span, String)>::new(); + for (self_name, self_span, trait_name) in derives.into_iter() { + 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()); + continue; + } + } + derives_grouped.push((self_name, self_span, trait_name.to_string())); + } + for (self_name, self_span, traits) in &derives_grouped { err.span_suggestion_verbose( self_span.shrink_to_lo(), diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index de3d5f498d5..ee411f8ed5f 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -4,7 +4,7 @@ use super::method::MethodCallee; use super::{has_expected_num_generic_args, FnCtxt}; use crate::Expectation; use rustc_ast as ast; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -306,7 +306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id))); let (mut err, output_def_id) = match is_assign { IsAssign::Yes => { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), expr.span, E0368, @@ -318,7 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), ); - self.note_unmet_impls_on_type(&mut err, errors); + self.note_unmet_impls_on_type(&mut err, errors, false); (err, None) } IsAssign::No => { @@ -370,12 +370,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .cloned() }); - let mut err = struct_span_err!(self.dcx(), op.span, E0369, "{message}"); + let mut err = + struct_span_code_err!(self.dcx(), op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { err.span_label(lhs_expr.span, lhs_ty.to_string()); err.span_label(rhs_expr.span, rhs_ty.to_string()); } - self.note_unmet_impls_on_type(&mut err, errors); + let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); + self.note_unmet_impls_on_type(&mut err, errors, suggest_derive); (err, output_def_id) } }; @@ -384,7 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::ExprKind::Assign(..) = expr.kind { // We defer to the later error produced by `check_lhs_assignable`. - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } let suggest_deref_binop = @@ -787,7 +789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(errors) => { let actual = self.resolve_vars_if_possible(operand_ty); let guar = actual.error_reported().err().unwrap_or_else(|| { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), ex.span, E0600, @@ -852,7 +854,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Str | Never | Char | Tuple(_) | Array(_, _) => {} Ref(_, lty, _) if *lty.kind() == Str => {} _ => { - self.note_unmet_impls_on_type(&mut err, errors); + self.note_unmet_impls_on_type(&mut err, errors, true); } } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 02a35110716..95813cb68a6 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -3,7 +3,7 @@ use crate::{errors, FnCtxt, RawTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; @@ -117,7 +117,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { actual: Ty<'tcx>, ti: TopInfo<'tcx>, ) { - if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { + if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { err.emit(); } } @@ -441,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // then that's equivalent to there existing a LUB. let cause = self.pattern_cause(ti, span); - if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { + if let Some(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { err.emit_unless( ti.span .filter(|&s| { @@ -546,7 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (_, Some((true, _, sp))) => sp, _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"), }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0029, @@ -837,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. let type_str = self.ty_to_string(expected); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0033, @@ -1103,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti); - let had_err = if let Some(mut err) = diag { + let had_err = if let Some(err) = diag { err.emit(); true } else { @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let last_field_def_span = *field_def_spans.last().unwrap(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), MultiSpan::from_spans(subpat_spans), E0023, @@ -1329,9 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(mut err) = - self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) - { + if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) { let reported = err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 @@ -1469,8 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } match (inexistent_fields_err, unmentioned_err) { - (Some(mut i), Some(mut u)) => { - if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + (Some(i), Some(u)) => { + if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { // We don't want to show the nonexistent fields error when this was // `Foo { a, b }` when it should have been `Foo(a, b)`. i.delay_as_bug(); @@ -1481,19 +1479,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { u.emit(); } } - (None, Some(mut u)) => { - if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + (None, Some(u)) => { + if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { u.delay_as_bug(); e.emit(); } else { u.emit(); } } - (Some(mut err), None) => { + (Some(err), None) => { err.emit(); } (None, None) - if let Some(mut err) = + if let Some(err) = self.error_tuple_variant_index_shorthand(variant, pat, fields) => { err.emit(); @@ -1518,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand); if has_shorthand_field_name { let path = rustc_hir_pretty::qpath_to_string(qpath); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), pat.span, E0769, @@ -1543,19 +1541,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi())); let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" }; - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), pat.span, E0638, "`..` required with {descr} marked as non-exhaustive", - ); - err.span_suggestion_verbose( + ) + .with_span_suggestion_verbose( sp_comma, "add `..` at the end of the field list to ignore all other fields", sugg, Applicability::MachineApplicable, - ); - err.emit(); + ) + .emit(); } fn error_field_already_bound( @@ -1564,15 +1562,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident: Ident, other_field: Span, ) -> ErrorGuaranteed { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0025, "field `{}` bound multiple times in the pattern", ident ) - .span_label(span, format!("multiple uses of `{ident}` in pattern")) - .span_label(other_field, format!("first use of `{ident}`")) + .with_span_label(span, format!("multiple uses of `{ident}` in pattern")) + .with_span_label(other_field, format!("first use of `{ident}`")) .emit() } @@ -1603,7 +1601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), spans, E0026, @@ -1700,7 +1698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let path = rustc_hir_pretty::qpath_to_string(qpath); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), pat.span, E0769, @@ -1878,7 +1876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .join(", "); format!("fields {fields}{inaccessible}") }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), pat.span, E0027, @@ -2228,7 +2226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_len: u64, size: u64, ) -> ErrorGuaranteed { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0527, @@ -2237,7 +2235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pluralize!(min_len), size, ) - .span_label(span, format!("expected {} element{}", size, pluralize!(size))) + .with_span_label(span, format!("expected {} element{}", size, pluralize!(size))) .emit() } @@ -2247,7 +2245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_len: u64, size: u64, ) -> ErrorGuaranteed { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0528, @@ -2256,7 +2254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pluralize!(min_len), size, ) - .span_label( + .with_span_label( span, format!("pattern cannot match array of {} element{}", size, pluralize!(size),), ) @@ -2264,7 +2262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0730, @@ -2279,7 +2277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> ErrorGuaranteed { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0529, diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index c3bcdcfa5cd..d6261763772 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -332,15 +332,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if inside_union && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop()) { - let mut err = self.dcx().struct_span_err( + self.dcx().struct_span_err( expr.span, "not automatically applying `DerefMut` on `ManuallyDrop` union field", - ); - err.help( + ) + .with_help( "writing to this reference calls the destructor for the old value", - ); - err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); - err.emit(); + ) + .with_help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor") + .emit(); } } source = adjustment.target; diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 47b9d5f6503..f6b05e1b35a 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -912,7 +912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { drop_order: bool, ) -> MigrationWarningReason { MigrationWarningReason { - auto_traits: auto_trait_reasons.to_sorted_stable_ord(), + auto_traits: auto_trait_reasons.into_sorted_stable_ord(), drop_order, } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 719d85ed3db..c56a028321a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -473,7 +473,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let fcx_coercion_casts = fcx_typeck_results.coercion_casts().to_sorted_stable_ord(); - for local_id in fcx_coercion_casts { + for &local_id in fcx_coercion_casts { self.typeck_results.set_coercion_cast(local_id); } } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 2c6ae91786d..e18b1365d9c 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -273,7 +273,7 @@ pub(crate) fn prepare_session_directory( debug!("successfully copied data from: {}", source_directory.display()); if !allows_links { - sess.dcx().emit_warning(errors::HardLinkFailed { path: &session_dir }); + sess.dcx().emit_warn(errors::HardLinkFailed { path: &session_dir }); } sess.init_incr_comp_session(session_dir, directory_lock); @@ -288,7 +288,7 @@ pub(crate) fn prepare_session_directory( // Try to remove the session directory we just allocated. We don't // know if there's any garbage in it from the failed copy action. if let Err(err) = safe_remove_dir_all(&session_dir) { - sess.dcx().emit_warning(errors::DeletePartial { path: &session_dir, err }); + sess.dcx().emit_warn(errors::DeletePartial { path: &session_dir, err }); } delete_session_dir_lock_file(sess, &lock_file_path); @@ -322,7 +322,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) { ); if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) { - sess.dcx().emit_warning(errors::DeleteFull { path: &incr_comp_session_dir, err }); + sess.dcx().emit_warn(errors::DeleteFull { path: &incr_comp_session_dir, err }); } let lock_file_path = lock_file_path(&*incr_comp_session_dir); @@ -365,7 +365,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) { } Err(e) => { // Warn about the error. However, no need to abort compilation now. - sess.dcx().emit_warning(errors::Finalize { path: &incr_comp_session_dir, err: e }); + sess.dcx().emit_warn(errors::Finalize { path: &incr_comp_session_dir, err: e }); debug!("finalize_session_directory() - error, marking as invalid"); // Drop the file lock, so we can garage collect @@ -500,7 +500,7 @@ fn lock_directory( fn delete_session_dir_lock_file(sess: &Session, lock_file_path: &Path) { if let Err(err) = safe_remove_file(lock_file_path) { - sess.dcx().emit_warning(errors::DeleteLock { path: lock_file_path, err }); + sess.dcx().emit_warn(errors::DeleteLock { path: lock_file_path, err }); } } @@ -724,7 +724,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) { let path = crate_directory.join(directory_name); if let Err(err) = safe_remove_dir_all(&path) { - sess.dcx().emit_warning(errors::InvalidGcFailed { path: &path, err }); + sess.dcx().emit_warn(errors::InvalidGcFailed { path: &path, err }); } } } @@ -830,7 +830,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result< debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = safe_remove_dir_all(&path) { - sess.dcx().emit_warning(errors::FinalizedGcFailed { path: &path, err }); + sess.dcx().emit_warn(errors::FinalizedGcFailed { path: &path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(&path)); } @@ -848,7 +848,7 @@ fn delete_old(sess: &Session, path: &Path) { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = safe_remove_dir_all(path) { - sess.dcx().emit_warning(errors::SessionGcFailed { path: path, err }); + sess.dcx().emit_warn(errors::SessionGcFailed { path: path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(path)); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ce8f5bb69ae..96bfe766c20 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -51,7 +51,7 @@ impl<T: Default> LoadResult<T> { match self { LoadResult::LoadDepGraph(path, err) => { - sess.dcx().emit_warning(errors::LoadDepGraph { path, err }); + sess.dcx().emit_warn(errors::LoadDepGraph { path, err }); Default::default() } LoadResult::DataOutOfDate => { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index bdc935a5e3b..08b7d08bcc0 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -103,7 +103,7 @@ pub fn save_work_product_index( // deleted during invalidation. Some object files don't change their // content, they are just not needed anymore. let previous_work_products = dep_graph.previous_work_products(); - for (id, wp) in previous_work_products.to_sorted_stable_ord().iter() { + for (id, wp) in previous_work_products.to_sorted_stable_ord() { if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); debug_assert!( diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 1450d8a99ab..906233ef53e 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -30,7 +30,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( let _ = saved_files.insert(ext.to_string(), file_name); } Err(err) => { - sess.dcx().emit_warning(errors::CopyWorkProductToCache { + sess.dcx().emit_warn(errors::CopyWorkProductToCache { from: path, to: &path_in_incr_dir, err, @@ -50,7 +50,7 @@ pub(crate) fn delete_workproduct_files(sess: &Session, work_product: &WorkProduc for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() { let path = in_incr_comp_dir_sess(sess, path); if let Err(err) = std_fs::remove_file(&path) { - sess.dcx().emit_warning(errors::DeleteWorkProduct { path: &path, err }); + sess.dcx().emit_warn(errors::DeleteWorkProduct { path: &path, err }); } } } diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index d730ef58deb..dfa3ced9dc1 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -10,7 +10,7 @@ use arrayvec::ArrayVec; use smallvec::{smallvec, SmallVec}; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; use crate::{Idx, IndexVec}; @@ -112,7 +112,7 @@ macro_rules! bit_relations_inherent_impls { /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. /// -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Eq, PartialEq, Hash)] pub struct BitSet<T> { domain_size: usize, @@ -1590,7 +1590,7 @@ impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> { /// /// All operations that involve a row and/or column index will panic if the /// index exceeds the relevant bound. -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Clone, Eq, PartialEq, Hash)] pub struct BitMatrix<R: Idx, C: Idx> { num_rows: usize, @@ -1699,14 +1699,15 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { let (read_start, read_end) = self.range(read); let (write_start, write_end) = self.range(write); let words = &mut self.words[..]; - let mut changed = false; + let mut changed = 0; for (read_index, write_index) in iter::zip(read_start..read_end, write_start..write_end) { let word = words[write_index]; let new_word = word | words[read_index]; words[write_index] = new_word; - changed |= word != new_word; + // See `bitwise` for the rationale. + changed |= word ^ new_word; } - changed + changed != 0 } /// Adds the bits from `with` to the bits from row `write`, and @@ -1715,14 +1716,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { assert!(write.index() < self.num_rows); assert_eq!(with.domain_size(), self.num_columns); let (write_start, write_end) = self.range(write); - let mut changed = false; - for (read_index, write_index) in iter::zip(0..with.words.len(), write_start..write_end) { - let word = self.words[write_index]; - let new_word = word | with.words[read_index]; - self.words[write_index] = new_word; - changed |= word != new_word; - } - changed + bitwise(&mut self.words[write_start..write_end], &with.words, |a, b| a | b) } /// Sets every cell in `row` to true. @@ -2020,7 +2014,7 @@ impl std::fmt::Debug for FiniteBitSet<u32> { /// A fixed-sized bitset type represented by an integer type. Indices outwith than the range /// representable by `T` are considered set. -#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))] +#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] #[derive(Copy, Clone, Eq, PartialEq)] pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T); diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a0768fc7115..aee99063e03 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -247,8 +247,8 @@ impl AddToDiagnostic for RegionOriginNote<'_> { } RegionOriginNote::WithName { span, msg, name, continues } => { label_or_note(span, msg); - diag.set_arg("name", name); - diag.set_arg("continues", continues); + diag.arg("name", name); + diag.arg("continues", continues); } RegionOriginNote::WithRequirement { span, @@ -256,7 +256,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> { expected_found: Some((expected, found)), } => { label_or_note(span, fluent::infer_subtype); - diag.set_arg("requirement", requirement); + diag.arg("requirement", requirement); diag.note_expected_found(&"", expected, &"", found); } @@ -265,7 +265,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> { // handling of region checking when type errors are present is // *terrible*. label_or_note(span, fluent::infer_subtype_2); - diag.set_arg("requirement", requirement); + diag.arg("requirement", requirement); } }; } @@ -298,8 +298,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels { diag.span_label(param_span, fluent::infer_declared_different); diag.span_label(ret_span, fluent::infer_nothing); diag.span_label(span, fluent::infer_data_returned); - diag.set_arg("label_var1_exists", label_var1.is_some()); - diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); } LifetimeMismatchLabels::Normal { hir_equal, @@ -317,16 +317,10 @@ impl AddToDiagnostic for LifetimeMismatchLabels { diag.span_label(ty_sup, fluent::infer_types_declared_different); diag.span_label(ty_sub, fluent::infer_nothing); diag.span_label(span, fluent::infer_data_flows); - diag.set_arg("label_var1_exists", label_var1.is_some()); - diag.set_arg( - "label_var1", - label_var1.map(|x| x.to_string()).unwrap_or_default(), - ); - diag.set_arg("label_var2_exists", label_var2.is_some()); - diag.set_arg( - "label_var2", - label_var2.map(|x| x.to_string()).unwrap_or_default(), - ); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + diag.arg("label_var2_exists", label_var2.is_some()); + diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); } } } @@ -417,7 +411,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { suggestions, Applicability::MaybeIncorrect, ); - diag.set_arg("is_impl", is_impl); + diag.arg("is_impl", is_impl); true }; if mk_suggestion() && self.add_note { @@ -878,8 +872,8 @@ impl AddToDiagnostic for MoreTargeted { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { diag.code(rustc_errors::error_code!(E0772)); - diag.set_primary_message(fluent::infer_more_targeted); - diag.set_arg("ident", self.ident); + diag.primary_message(fluent::infer_more_targeted); + diag.arg("ident", self.ident); } } @@ -1299,7 +1293,7 @@ impl AddToDiagnostic for SuggestTuplePatternMany { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.set_arg("path", self.path); + diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diag.multipart_suggestions( message, diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 68bf36a1615..8e45cc6d80e 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -164,10 +164,10 @@ impl AddToDiagnostic for RegionExplanation<'_> { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.set_arg("pref_kind", self.prefix); - diag.set_arg("suff_kind", self.suffix); - diag.set_arg("desc_kind", self.desc.kind); - diag.set_arg("desc_arg", self.desc.arg); + diag.arg("pref_kind", self.prefix); + diag.arg("suff_kind", self.suffix); + diag.arg("desc_kind", self.desc.kind); + diag.arg("desc_arg", self.desc.arg); let msg = f(diag, fluent::infer_region_explanation.into()); if let Some(span) = self.desc.span { diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 69a96448467..e4b37f05b77 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -41,7 +41,33 @@ impl<'tcx> InferCtxt<'tcx> { where V: TypeFoldable<TyCtxt<'tcx>>, { - self.canonicalize_query_with_mode(value, query_state, &CanonicalizeAllFreeRegions) + let (param_env, value) = value.into_parts(); + let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + self.tcx, + param_env, + query_state, + |tcx, param_env, query_state| { + // FIXME(#118965): We don't canonicalize the static lifetimes that appear in the + // `param_env` beacause they are treated differently by trait selection. + Canonicalizer::canonicalize( + param_env, + None, + tcx, + &CanonicalizeFreeRegionsOtherThanStatic, + query_state, + ) + }, + ); + + Canonicalizer::canonicalize_with_base( + param_env, + value, + Some(self), + self.tcx, + &CanonicalizeAllFreeRegions, + query_state, + ) + .unchecked_map(|(param_env, value)| param_env.and(value)) } /// Canonicalizes a query *response* `V`. When we canonicalize a @@ -96,61 +122,6 @@ impl<'tcx> InferCtxt<'tcx> { &mut query_state, ) } - - /// A variant of `canonicalize_query` that does not - /// canonicalize `'static`. This is useful when - /// the query implementation can perform more efficient - /// handling of `'static` regions (e.g. trait evaluation). - pub fn canonicalize_query_keep_static<V>( - &self, - value: ty::ParamEnvAnd<'tcx, V>, - query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>> - where - V: TypeFoldable<TyCtxt<'tcx>>, - { - self.canonicalize_query_with_mode( - value, - query_state, - &CanonicalizeFreeRegionsOtherThanStatic, - ) - } - - fn canonicalize_query_with_mode<V>( - &self, - value: ty::ParamEnvAnd<'tcx, V>, - query_state: &mut OriginalQueryValues<'tcx>, - canonicalize_region_mode: &dyn CanonicalizeMode, - ) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>> - where - V: TypeFoldable<TyCtxt<'tcx>>, - { - let (param_env, value) = value.into_parts(); - let base = self.tcx.canonical_param_env_cache.get_or_insert( - self.tcx, - param_env, - query_state, - |tcx, param_env, query_state| { - Canonicalizer::canonicalize( - param_env, - None, - tcx, - &CanonicalizeFreeRegionsOtherThanStatic, - query_state, - ) - }, - ); - - Canonicalizer::canonicalize_with_base( - base, - value, - Some(self), - self.tcx, - canonicalize_region_mode, - query_state, - ) - .unchecked_map(|(param_env, value)| param_env.and(value)) - } } /// Controls how we canonicalize "free regions" that are not inference @@ -221,10 +192,10 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { // rust-lang/rust#57464: `impl Trait` can leak local // scopes (in manner violating typeck). Therefore, use // `span_delayed_bug` to allow type error over an ICE. - canonicalizer.tcx.dcx().span_delayed_bug( - rustc_span::DUMMY_SP, - format!("unexpected region in query response: `{r:?}`"), - ); + canonicalizer + .tcx + .dcx() + .delayed_bug(format!("unexpected region in query response: `{r:?}`")); r } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b5a6374ec4b..875e94fcd9f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -60,8 +60,8 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, + error_code, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, + DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -361,7 +361,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( ); } ty::ReError(_) => { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } _ => { // Ugh. This is a painful case: the hidden region is not one @@ -2348,23 +2348,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GenericKind::Param(ref p) => format!("the parameter type `{p}`"), GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"), GenericKind::Alias(ref p) => match p.kind(self.tcx) { - ty::AliasKind::Projection | ty::AliasKind::Inherent => { + ty::Projection | ty::Inherent => { format!("the associated type `{p}`") } - ty::AliasKind::Weak => format!("the type alias `{p}`"), - ty::AliasKind::Opaque => format!("the opaque type `{p}`"), + ty::Weak => format!("the type alias `{p}`"), + ty::Opaque => format!("the opaque type `{p}`"), }, }; - let mut err = self.tcx.dcx().struct_span_err_with_code( - span, - format!("{labeled_user_string} may not live long enough"), - match sub.kind() { - ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), - ty::ReStatic => error_code!(E0310), - _ => error_code!(E0311), - }, - ); + let mut err = self + .tcx + .dcx() + .struct_span_err(span, format!("{labeled_user_string} may not live long enough")); + err.code(match sub.kind() { + ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => error_code!(E0309), + ty::ReStatic => error_code!(E0310), + _ => error_code!(E0311), + }); '_explain: { let (description, span) = match sub.kind() { @@ -2780,7 +2780,7 @@ impl<'tcx> InferCtxt<'tcx> { infer::Nll(..) => bug!("NLL variable found in lexical phase"), }; - struct_span_err!( + struct_span_code_err!( self.tcx.dcx(), var_origin.span(), E0495, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index e13d1d38a89..d3e28446dde 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -60,7 +60,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub fn try_report(&self) -> Option<ErrorGuaranteed> { self.try_report_from_nll() - .map(|mut diag| diag.emit()) + .map(|diag| diag.emit()) .or_else(|| self.try_report_impl_not_conforming_to_trait()) .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_static_impl_trait()) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index ae30cf53c71..02200d6a4aa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; if sub.is_error() || sup.is_error() { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } err } @@ -367,9 +367,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &trace.cause.code().peel_derives() { let span = *span; - let mut err = self.report_concrete_failure(placeholder_origin, sub, sup); - err.span_note(span, "the lifetime requirement is introduced here"); - err + self.report_concrete_failure(placeholder_origin, sub, sup) + .with_span_note(span, "the lifetime requirement is introduced here") } else { unreachable!( "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..." diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fa694f09f17..fcc94687ed2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -38,7 +38,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtx use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; @@ -1434,10 +1434,8 @@ impl<'tcx> InferCtxt<'tcx> { bug!("`{value:?}` is not fully resolved"); } if value.has_infer_regions() { - let guar = self - .tcx - .dcx() - .span_delayed_bug(DUMMY_SP, format!("`{value:?}` is not fully resolved")); + let guar = + self.tcx.dcx().delayed_bug(format!("`{value:?}` is not fully resolved")); Ok(self.tcx.fold_regions(value, |re, _| { if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re } })) diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index c91eb7eddd8..6a684dba8de 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,6 +1,5 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; -use rustc_span::DUMMY_SP; use crate::infer::{InferCtxtUndoLogs, UndoLog}; @@ -40,9 +39,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { fn drop(&mut self) { if !self.opaque_types.is_empty() { - ty::tls::with(|tcx| { - tcx.dcx().span_delayed_bug(DUMMY_SP, format!("{:?}", self.opaque_types)) - }); + ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types))); } } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index dd364312cad..7a85268492b 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -175,10 +175,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.tcx.dcx().span_delayed_bug( - rustc_span::DUMMY_SP, - format!("unresolved inference variable in outlives: {v:?}"), - ); + self.tcx + .dcx() + .delayed_bug(format!("unresolved inference variable in outlives: {v:?}")); // add a bound that never holds VerifyBound::AnyBound(vec![]) } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 8b31a1118cb..4b254fc7df5 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -180,10 +180,9 @@ impl<'tcx> InferCtxt<'tcx> { &mut OriginalQueryValues::default(), ); self.tcx.check_tys_might_be_eq(canonical).map_err(|_| { - self.tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("cannot relate consts of different types (a={a:?}, b={b:?})",), - ) + self.tcx.dcx().delayed_bug(format!( + "cannot relate consts of different types (a={a:?}, b={b:?})", + )) }) }); @@ -511,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { )); } else { match a_ty.kind() { - &ty::Alias(ty::AliasKind::Projection, data) => { + &ty::Alias(ty::Projection, data) => { // FIXME: This does not handle subtyping correctly, we could // instead create a new inference variable for `a_ty`, emitting // `Projection(a_ty, a_infer)` and `a_infer <: b_ty`. @@ -523,10 +522,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { )) } // The old solver only accepts projection predicates for associated types. - ty::Alias( - ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque, - _, - ) => return Err(TypeError::CyclicTy(a_ty)), + ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => { + return Err(TypeError::CyclicTy(a_ty)); + } _ => bug!("generalizated `{a_ty:?} to infer, not an alias"), } } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index d89c205da3f..6f218019dee 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,9 +2,10 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Map; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; @@ -19,7 +20,7 @@ impl<'tcx> InferCtxt<'tcx> { trait_item_def_id: DefId, requirement: &dyn fmt::Display, ) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.tcx.dcx(), error_span, E0276, @@ -42,6 +43,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn report_object_safety_error<'tcx>( tcx: TyCtxt<'tcx>, span: Span, + hir_id: Option<hir::HirId>, trait_def_id: DefId, violations: &[ObjectSafetyViolation], ) -> DiagnosticBuilder<'tcx> { @@ -50,7 +52,7 @@ pub fn report_object_safety_error<'tcx>( hir::Node::Item(item) => Some(item.ident.span), _ => None, }); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( tcx.dcx(), span, E0038, @@ -59,6 +61,24 @@ pub fn report_object_safety_error<'tcx>( ); err.span_label(span, format!("`{trait_str}` cannot be made into an object")); + if let Some(hir_id) = hir_id + && let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id) + && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind + { + let mut hir_id = hir_id; + while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) { + hir_id = ty.hir_id; + } + if tcx.hir().get_parent(hir_id).fn_sig().is_some() { + // Do not suggest `impl Trait` when dealing with things like super-traits. + err.span_suggestion_verbose( + ty.span.until(trait_ref.span), + "consider using an opaque type instead", + "impl ", + Applicability::MaybeIncorrect, + ); + } + } let mut reported_violations = FxIndexSet::default(); let mut multi_span = vec![]; let mut messages = vec![]; @@ -132,7 +152,10 @@ pub fn report_object_safety_error<'tcx>( }; let externally_visible = if !impls.is_empty() && let Some(def_id) = trait_def_id.as_local() - && tcx.effective_visibilities(()).is_exported(def_id) + // We may be executing this during typeck, which would result in cycle + // if we used effective_visibilities query, which looks into opaque types + // (and therefore calls typeck). + && tcx.resolutions(()).effective_visibilities.is_exported(def_id) { true } else { diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index ef00ced67ff..8c7e49b51f9 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -9,7 +9,7 @@ //! The functions in this file should fall back to the default set in their //! origin crate when the `TyCtxt` is not present in TLS. -use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; +use rustc_errors::{Diagnostic, TRACK_DIAGNOSTIC}; use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; @@ -29,7 +29,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { /// This is a callback from `rustc_errors` as it cannot access the implicit state /// in `rustc_middle` otherwise. It is used when diagnostic messages are /// emitted and stores them in the current query, if there is one. -fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { +fn track_diagnostic(diagnostic: Diagnostic, f: &mut dyn FnMut(Diagnostic)) { tls::with_context_opt(|icx| { if let Some(icx) = icx { if let Some(diagnostics) = icx.diagnostics { @@ -103,5 +103,5 @@ pub fn setup_callbacks() { .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); - TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _)); + TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 559874641c3..97956404120 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -254,7 +254,7 @@ fn configure_and_expand( } if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort { - sess.dcx().emit_warning(errors::ProcMacroCratePanicAbort); + sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort); } sess.time("maybe_create_a_macro_crate", || { @@ -735,9 +735,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("MIR_borrow_checking", || { tcx.hir().par_body_owners(|def_id| { - // Run THIR unsafety check because it's responsible for stealing - // and deallocating THIR when enabled. - tcx.ensure().thir_check_unsafety(def_id); + // Run unsafety check because it's responsible for stealing and + // deallocating THIR. + tcx.ensure().check_unsafety(def_id); tcx.ensure().mir_borrowck(def_id) }); }); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 07bbe78dc2d..e66ea6f2ca9 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -108,7 +108,7 @@ impl<'tcx> Queries<'tcx> { pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> { self.parse.compute(|| { - passes::parse(&self.compiler.sess).map_err(|mut parse_error| parse_error.emit()) + passes::parse(&self.compiler.sess).map_err(|parse_error| parse_error.emit()) }) } @@ -213,9 +213,8 @@ impl<'tcx> Queries<'tcx> { // Some other attribute. Some(_) => { - tcx.dcx().emit_warning(RustcErrorUnexpectedAnnotation { - span: tcx.def_span(def_id), - }); + tcx.dcx() + .emit_warn(RustcErrorUnexpectedAnnotation { span: tcx.def_span(def_id) }); } } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c4a1f3a0e51..588139a303c 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -6,8 +6,8 @@ use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, - LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, NextSolverConfig, - OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, + Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; @@ -659,14 +659,12 @@ fn test_unstable_options_tracking_hash() { // tidy-alphabetical-start untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); - untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); - untracked!(dump_mir_spanview, Some(MirSpanview::Statement)); untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into()))); untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json); untracked!(dylib_lto, true); @@ -700,6 +698,7 @@ fn test_unstable_options_tracking_hash() { untracked!(query_dep_graph, true); untracked!(self_profile, SwitchWithOptPath::Enabled(None)); untracked!(self_profile_events, Some(vec![String::new()])); + untracked!(shell_argfiles, true); untracked!(span_debug, true); untracked!(span_free_formats, true); untracked!(temps_dir, Some(String::from("abc"))); @@ -806,7 +805,6 @@ fn test_unstable_options_tracking_hash() { tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); - tracked!(report_delayed_bugs, true); tracked!(sanitizer, SanitizerSet::ADDRESS); tracked!(sanitizer_cfi_canonical_jump_tables, None); tracked!(sanitizer_cfi_generalize_pointers, Some(true)); @@ -822,7 +820,7 @@ fn test_unstable_options_tracking_hash() { tracked!(stack_protector, StackProtector::All); tracked!(teach, true); tracked!(thinlto, Some(true)); - tracked!(thir_unsafeck, true); + tracked!(thir_unsafeck, false); tracked!(tiny_const_eval_limit, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(translate_remapped_path_to_local_path, false); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 92a6445ed09..9fd44e46b31 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -431,7 +431,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C base.retain(|crate_type| { if output::invalid_output_for_target(session, *crate_type) { - session.dcx().emit_warning(errors::UnsupportedCrateTypeForTarget { + session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget { crate_type: *crate_type, target_triple: &session.opts.target_triple, }); @@ -507,16 +507,16 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu let unnamed_output_types = sess.opts.output_types.values().filter(|a| a.is_none()).count(); let ofile = if unnamed_output_types > 1 { - sess.dcx().emit_warning(errors::MultipleOutputTypesAdaption); + sess.dcx().emit_warn(errors::MultipleOutputTypesAdaption); None } else { if !sess.opts.cg.extra_filename.is_empty() { - sess.dcx().emit_warning(errors::IgnoringExtraFilename); + sess.dcx().emit_warn(errors::IgnoringExtraFilename); } Some(out_file.clone()) }; if sess.io.output_dir != None { - sess.dcx().emit_warning(errors::IgnoringOutDir); + sess.dcx().emit_warn(errors::IgnoringOutDir); } let out_filestem = diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8afb5f2d32e..8d2f2aaca55 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2734,10 +2734,13 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { #[allow(rustc::diagnostic_outside_of_impl)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { - kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }), + kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }), .. } = expr { + // asm with `options(raw)` does not do replacement with `{` and `}`. + let raw = options.contains(InlineAsmOptions::RAW); + for (template_sym, template_snippet, template_span) in template_strs.iter() { let template_str = template_sym.as_str(); let find_label_span = |needle: &str| -> Option<Span> { @@ -2763,24 +2766,57 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { for statement in statements { // If there's a comment, trim it from the statement let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]); + + // In this loop, if there is ever a non-label, no labels can come after it. let mut start_idx = 0; - for (idx, _) in statement.match_indices(':') { + 'label_loop: for (idx, _) in statement.match_indices(':') { let possible_label = statement[start_idx..idx].trim(); let mut chars = possible_label.chars(); - let Some(c) = chars.next() else { - // Empty string means a leading ':' in this section, which is not a label - break; + + let Some(start) = chars.next() else { + // Empty string means a leading ':' in this section, which is not a label. + break 'label_loop; }; - // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $ - if (c.is_alphabetic() || matches!(c, '.' | '_')) - && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$')) - { - found_labels.push(possible_label); - } else { - // If we encounter a non-label, there cannot be any further labels, so stop checking - break; + + // Whether a { bracket has been seen and its } hasn't been found yet. + let mut in_bracket = false; + + // A label starts with an ASCII alphabetic character or . or _ + // A label can also start with a format arg, if it's not a raw asm block. + if !raw && start == '{' { + in_bracket = true; + } else if !(start.is_ascii_alphabetic() || matches!(start, '.' | '_')) { + break 'label_loop; + } + + // Labels continue with ASCII alphanumeric characters, _, or $ + for c in chars { + // Inside a template format arg, any character is permitted for the puproses of label detection + // because we assume that it can be replaced with some other valid label string later. + // `options(raw)` asm blocks cannot have format args, so they are excluded from this special case. + if !raw && in_bracket { + if c == '{' { + // Nested brackets are not allowed in format args, this cannot be a label. + break 'label_loop; + } + + if c == '}' { + // The end of the format arg. + in_bracket = false; + } + } else if !raw && c == '{' { + // Start of a format arg. + in_bracket = true; + } else { + if !(c.is_ascii_alphanumeric() || matches!(c, '_' | '$')) { + // The potential label had an invalid character inside it, it cannot be a label. + break 'label_loop; + } + } } + // If all characters passed the label checks, this is likely a label. + found_labels.push(possible_label); start_idx = idx + 1; } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index eccea35c702..841d282a099 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -31,7 +31,7 @@ impl AddToDiagnostic for OverruledAttributeSub { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); - diag.set_arg("id", id); + diag.arg("id", id); } OverruledAttributeSub::NodeSource { span, reason } => { diag.span_label(span, fluent::lint_node_source); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 31d9c0d33fe..ecb7a157f39 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,5 +1,5 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::query::Providers; @@ -72,7 +72,7 @@ struct ClashingExternDeclarations { /// the symbol should be reported as a clashing declaration. // FIXME: Technically, we could just store a &'tcx str here without issue; however, the // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. - seen_decls: FxHashMap<Symbol, hir::OwnerId>, + seen_decls: UnordMap<Symbol, hir::OwnerId>, } /// Differentiate between whether the name for an extern decl came from the link_name attribute or @@ -96,7 +96,7 @@ impl SymbolName { impl ClashingExternDeclarations { pub(crate) fn new() -> Self { - ClashingExternDeclarations { seen_decls: FxHashMap::default() } + ClashingExternDeclarations { seen_decls: Default::default() } } /// Insert a new foreign item into the seen set. If a symbol with the same name already exists @@ -209,12 +209,12 @@ fn structurally_same_type<'tcx>( b: Ty<'tcx>, ckind: types::CItemKind, ) -> bool { - let mut seen_types = FxHashSet::default(); + let mut seen_types = UnordSet::default(); structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind) } fn structurally_same_type_impl<'tcx>( - seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>, + seen_types: &mut UnordSet<(Ty<'tcx>, Ty<'tcx>)>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, a: Ty<'tcx>, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 53d99c7f7f3..e3405aa2e55 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -549,7 +549,9 @@ declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]); impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind { + if let ExprKind::Binary(BinOp { node: BinOpKind::Eq | BinOpKind::Ne, .. }, lhs, rhs) = + expr.kind + { if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); } diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 3eefd1b0e08..bdace8e01f6 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -108,6 +108,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if !matches!(local.pat.kind, hir::PatKind::Wild) { return; } + + if matches!(local.source, rustc_hir::LocalSource::AsyncFn) { + return; + } if let Some(init) = local.init { let init_ty = cx.typeck_results().expr_ty(init); // If the type has a trivial Drop implementation, then it doesn't @@ -126,6 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { suggestion: local.pat.span, multi_suggestion_start: local.span.until(init.span), multi_suggestion_end: init.span.shrink_to_hi(), + is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)), }; if is_sync_lock { let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 5950bc76ade..49821437b76 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1069,7 +1069,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { Some(span.into()), fluent::lint_unknown_gated_lint, |lint| { - lint.set_arg("name", lint_id.lint.name_lower()); + lint.arg("name", lint_id.lint.name_lower()); lint.note(fluent::lint_note); rustc_session::parse::add_feature_diagnostics_for_issue( lint, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 93904fb5c56..a9996e4a155 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -328,6 +328,7 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("disjoint_capture_migration", "rust_2021_incompatible_closure_captures"); store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns"); store.register_renamed("non_fmt_panic", "non_fmt_panics"); + store.register_renamed("unused_tuple_struct_fields", "dead_code"); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use @@ -512,6 +513,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see PR #117984 \ <https://github.com/rust-lang/rust/pull/117984> for more information", ); + store.register_removed( + "coinductive_overlap_in_coherence", + "converted into hard error, see PR #118649 \ + <https://github.com/rust-lang/rust/pull/118649> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ca6408bdf3d..bc9a9d7b745 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,8 +5,8 @@ use std::num::NonZeroU32; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ - AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString, - SuggestionStyle, + AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, DiagnosticMessage, + DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -135,7 +135,7 @@ pub struct BuiltinMissingDebugImpl<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> { fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("debug", self.tcx.def_path_str(self.def_id)); + diag.arg("debug", self.tcx.def_path_str(self.def_id)); } fn msg(&self) -> DiagnosticMessage { @@ -239,7 +239,7 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> { } impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { diag.span_label(self.label, fluent::lint_label); rustc_session::parse::add_feature_diagnostics( diag, @@ -268,12 +268,9 @@ pub struct SuggestChangingAssocTypes<'a, 'b> { } impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { // Access to associates types should use `<T as Bound>::Assoc`, which does not need a // bound. Let's see if this type does that. @@ -281,7 +278,7 @@ impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { // We use a HIR visitor to walk the type. use rustc_hir::intravisit::{self, Visitor}; struct WalkAssocTypes<'a> { - err: &'a mut rustc_errors::Diagnostic, + err: &'a mut Diagnostic, } impl Visitor<'_> for WalkAssocTypes<'_> { fn visit_qpath( @@ -326,12 +323,9 @@ pub struct BuiltinTypeAliasGenericBoundsSuggestion { } impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { diag.multipart_suggestion( fluent::lint_suggestion, @@ -425,8 +419,8 @@ pub struct BuiltinUnpermittedTypeInit<'a> { } impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("ty", self.ty); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("ty", self.ty); diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) { // Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited. @@ -438,7 +432,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { self.sub.add_to_diagnostic(diag); } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { self.msg.clone() } } @@ -449,12 +443,9 @@ pub struct BuiltinUnpermittedTypeInitSub { } impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { let mut err = self.err; loop { @@ -506,12 +497,9 @@ pub struct BuiltinClashingExternSub<'a> { } impl AddToDiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { let mut expected_str = DiagnosticStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); @@ -779,12 +767,9 @@ pub struct HiddenUnicodeCodepointsDiagLabels { } impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); @@ -799,12 +784,9 @@ pub enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { @@ -830,7 +812,7 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { // FIXME: in other suggestions we've reversed the inner spans of doc comments. We // should do the same here to provide the same good suggestions as we do for // literals above. - diag.set_arg( + diag.arg( "escaped", spans .into_iter() @@ -950,20 +932,19 @@ pub struct NonBindingLetSub { pub suggestion: Span, pub multi_suggestion_start: Span, pub multi_suggestion_end: Span, + pub is_assign_desugar: bool, } impl AddToDiagnostic for NonBindingLetSub { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { + let prefix = if self.is_assign_desugar { "let " } else { "" }; diag.span_suggestion_verbose( self.suggestion, fluent::lint_non_binding_let_suggestion, - "_unused", + format!("{prefix}_unused"), Applicability::MachineApplicable, ); diag.multipart_suggestion( @@ -1147,8 +1128,8 @@ pub struct NonFmtPanicUnused { // Used because of two suggestions based on one Option<Span> impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("count", self.count); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("count", self.count); diag.note(fluent::lint_note); if let Some(span) = self.suggestion { diag.span_suggestion( @@ -1166,7 +1147,7 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_non_fmt_panic_unused } } @@ -1224,12 +1205,9 @@ pub enum NonSnakeCaseDiagSub { } impl AddToDiagnostic for NonSnakeCaseDiagSub { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { match self { NonSnakeCaseDiagSub::Label { span } => { @@ -1342,12 +1320,12 @@ pub struct DropTraitConstraintsDiag<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("predicate", self.predicate); - diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("predicate", self.predicate); + diag.arg("needs_drop", self.tcx.def_path_str(self.def_id)); } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_drop_trait_constraints } } @@ -1359,11 +1337,11 @@ pub struct DropGlue<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("needs_drop", self.tcx.def_path_str(self.def_id)); } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_drop_glue } } @@ -1423,12 +1401,9 @@ pub enum OverflowingBinHexSign { } impl AddToDiagnostic for OverflowingBinHexSign { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { match self { OverflowingBinHexSign::Positive => { @@ -1633,9 +1608,9 @@ pub struct ImproperCTypes<'a> { // Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span> impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("ty", self.ty); - diag.set_arg("desc", self.desc); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("ty", self.ty); + diag.arg("desc", self.desc); diag.span_label(self.label, fluent::lint_label); if let Some(help) = self.help { diag.help(help); @@ -1646,7 +1621,7 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_improper_ctypes } } @@ -1776,10 +1751,10 @@ pub enum UnusedDefSuggestion { // Needed because of def_path_str impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { - diag.set_arg("pre", self.pre); - diag.set_arg("post", self.post); - diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { + diag.arg("pre", self.pre); + diag.arg("post", self.post); + diag.arg("def", self.cx.tcx.def_path_str(self.def_id)); // check for #[must_use = "..."] if let Some(note) = self.note { diag.note(note.to_string()); @@ -1789,7 +1764,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_unused_def } } @@ -1859,14 +1834,14 @@ pub struct AsyncFnInTraitDiag { } impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { diag.note(fluent::lint_note); if let Some(sugg) = self.sugg { diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_async_fn_in_trait } } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 08b2bf6af37..3405dd3a916 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -4,7 +4,8 @@ use crate::lints::{ }; use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordMap; use rustc_span::symbol::Symbol; declare_lint! { @@ -194,8 +195,8 @@ impl EarlyLintPass for NonAsciiIdents { } if has_non_ascii_idents && check_confusable_idents { - let mut skeleton_map: FxHashMap<Symbol, (Symbol, Span, bool)> = - FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default()); + let mut skeleton_map: UnordMap<Symbol, (Symbol, Span, bool)> = + UnordMap::with_capacity(symbols.len()); let mut skeleton_buf = String::new(); for (&symbol, &sp) in symbols.iter() { @@ -248,8 +249,8 @@ impl EarlyLintPass for NonAsciiIdents { Verified, } - let mut script_states: FxHashMap<AugmentedScriptSet, ScriptSetUsage> = - FxHashMap::default(); + let mut script_states: FxIndexMap<AugmentedScriptSet, ScriptSetUsage> = + Default::default(); let latin_augmented_script_set = AugmentedScriptSet::for_char('A'); script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified); diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 9fcd70ba0b5..479acd88d71 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -111,17 +111,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc let mut arg_span = arg.span; let mut arg_macro = None; while !span.contains(arg_span) { - let expn = arg_span.ctxt().outer_expn_data(); - if expn.is_root() { + let ctxt = arg_span.ctxt(); + if ctxt.is_root() { break; } + let expn = ctxt.outer_expn_data(); arg_macro = expn.macro_def_id; arg_span = expn.call_site; } #[allow(rustc::diagnostic_outside_of_impl)] cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { - lint.set_arg("name", symbol); + lint.arg("name", symbol); lint.note(fluent::lint_note); lint.note(fluent::lint_more_info_note); if !is_arg_inside_call(arg_span, span) { @@ -180,7 +181,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc fmt_applicability, ); } else if suggest_debug { - lint.set_arg("ty", ty); + lint.arg("ty", ty); lint.span_suggestion_verbose( arg_span.shrink_to_lo(), fluent::lint_debug_suggestion, @@ -191,7 +192,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_panic_any { if let Some((open, close, del)) = find_delimiters(cx, span) { - lint.set_arg("already_suggested", suggest_display || suggest_debug); + lint.arg("already_suggested", suggest_display || suggest_debug); lint.multipart_suggestion( fluent::lint_panic_suggestion, if del == '(' { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 6dade43a183..a86fe2db2b2 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol}; use rustc_target::abi::{Abi, Size, WrappingRange}; use rustc_target::abi::{Integer, TagEncoding, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; -use rustc_type_ir::DynKind; use std::iter; use std::ops::ControlFlow; @@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>( } match ty.kind() { ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env)) - .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))), + .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))), _ => None, } }; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e35d1ee0461..e917e7cb02b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -26,7 +26,6 @@ declare_lint_pass! { BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, - COINDUCTIVE_OVERLAP_IN_COHERENCE, CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, @@ -89,6 +88,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + STATIC_MUT_REF, SUSPICIOUS_AUTO_TRAIT_IMPLS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, @@ -125,7 +125,6 @@ declare_lint_pass! { UNUSED_MACROS, UNUSED_MUT, UNUSED_QUALIFICATIONS, - UNUSED_TUPLE_STRUCT_FIELDS, UNUSED_UNSAFE, UNUSED_VARIABLES, USELESS_DEPRECATED, @@ -697,8 +696,13 @@ declare_lint! { /// Dead code may signal a mistake or unfinished code. To silence the /// warning for individual items, prefix the name with an underscore such /// as `_foo`. If it was intended to expose the item outside of the crate, - /// consider adding a visibility modifier like `pub`. Otherwise consider - /// removing the unused code. + /// consider adding a visibility modifier like `pub`. + /// + /// To preserve the numbering of tuple structs with unused fields, + /// change the unused fields to have unit type or use + /// `PhantomData`. + /// + /// Otherwise consider removing the unused code. pub DEAD_CODE, Warn, "detect unused, unexported items" @@ -733,32 +737,6 @@ declare_lint! { } declare_lint! { - /// The `unused_tuple_struct_fields` lint detects fields of tuple structs - /// that are never read. - /// - /// ### Example - /// - /// ```rust - /// #[warn(unused_tuple_struct_fields)] - /// struct S(i32, i32, i32); - /// let s = S(1, 2, 3); - /// let _ = (s.0, s.2); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Tuple struct fields that are never read anywhere may indicate a - /// mistake or unfinished code. To silence this warning, consider - /// removing the unused field(s) or, to preserve the numbering of the - /// remaining fields, change the unused field(s) to have unit type. - pub UNUSED_TUPLE_STRUCT_FIELDS, - Allow, - "detects tuple struct fields that are never read" -} - -declare_lint! { /// The `unreachable_code` lint detects unreachable code paths. /// /// ### Example @@ -1790,6 +1768,57 @@ declare_lint! { } declare_lint! { + /// The `static_mut_ref` lint checks for shared or mutable references + /// of mutable static inside `unsafe` blocks and `unsafe` functions. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// fn main() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// unsafe { + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// } + /// + /// unsafe fn _foo() { + /// static mut X: i32 = 23; + /// static mut Y: i32 = 24; + /// + /// let y = &X; + /// let ref x = X; + /// let (x, y) = (&X, &Y); + /// foo(&X); + /// } + /// + /// fn foo<'a>(_x: &'a i32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared or mutable references of mutable static are almost always a mistake and + /// can lead to undefined behavior and various other problems in your code. + /// + /// This lint is "warn" by default on editions up to 2021, from 2024 there is + /// a hard error instead. + pub STATIC_MUT_REF, + Warn, + "shared references or mutable references of mutable static is discouraged", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #114447 <https://github.com/rust-lang/rust/issues/114447>", + explain_reason: false, + }; +} + +declare_lint! { /// The `absolute_paths_not_starting_with_crate` lint detects fully /// qualified paths that start with a module name instead of `crate`, /// `self`, or an extern crate name @@ -4390,45 +4419,6 @@ declare_lint! { } declare_lint! { - /// The `coinductive_overlap_in_coherence` lint detects impls which are currently - /// considered not overlapping, but may be considered to overlap if support for - /// coinduction is added to the trait solver. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(coinductive_overlap_in_coherence)] - /// - /// trait CyclicTrait {} - /// impl<T: CyclicTrait> CyclicTrait for T {} - /// - /// trait Trait {} - /// impl<T: CyclicTrait> Trait for T {} - /// // conflicting impl with the above - /// impl Trait for u8 {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// We have two choices for impl which satisfy `u8: Trait`: the blanket impl - /// for generic `T`, and the direct impl for `u8`. These two impls nominally - /// overlap, since we can infer `T = u8` in the former impl, but since the where - /// clause `u8: CyclicTrait` would end up resulting in a cycle (since it depends - /// on itself), the blanket impl is not considered to hold for `u8`. This will - /// change in a future release. - pub COINDUCTIVE_OVERLAP_IN_COHERENCE, - Deny, - "impls that are not considered to overlap may be considered to \ - overlap in the future", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #114040 <https://github.com/rust-lang/rust/issues/114040>", - }; -} - -declare_lint! { /// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed /// diagnostic attributes. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index a25cfe68e0d..eed35326c45 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -9,7 +9,9 @@ pub use self::Level::*; use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{ + HashStable, StableCompare, StableHasher, ToStableHashKey, +}; use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; use rustc_hir::HirId; @@ -541,6 +543,14 @@ impl<HCX> ToStableHashKey<HCX> for LintId { } } +impl StableCompare for LintId { + const CAN_USE_UNSTABLE_SORT: bool = true; + + fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { + self.lint_name_raw().cmp(&other.lint_name_raw()) + } +} + #[derive(Debug)] pub struct AmbiguityErrorDiag { pub msg: String, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index cf3f526400d..76eb6bfaef7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -787,7 +787,9 @@ LLVMRustOptimize( for (auto PluginPath: Plugins) { auto Plugin = PassPlugin::Load(PluginPath.str()); if (!Plugin) { - LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str()); + auto Err = Plugin.takeError(); + auto ErrMsg = llvm::toString(std::move(Err)); + LLVMRustSetLastError(ErrMsg.c_str()); return LLVMRustResult::Failure; } Plugin->registerPassBuilderCallbacks(PB); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index f3e98d68b60..fb908fe2db1 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -5,8 +5,8 @@ use crate::diagnostics::error::{ }; use crate::diagnostics::utils::{ build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, - should_generate_set_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, - FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, + should_generate_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, + FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; @@ -125,15 +125,15 @@ impl DiagnosticDeriveVariantBuilder { } /// Generates calls to `span_label` and similar functions based on the attributes on fields or - /// calls to `set_arg` when no attributes are present. + /// calls to `arg` when no attributes are present. pub(crate) fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let mut body = quote! {}; - // Generate `set_arg` calls first.. - for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) { + // Generate `arg` calls first.. + for binding in variant.bindings().iter().filter(|bi| should_generate_arg(bi.ast())) { body.extend(self.generate_field_code(binding)); } // ..and then subdiagnostic additions. - for binding in variant.bindings().iter().filter(|bi| !should_generate_set_arg(bi.ast())) { + for binding in variant.bindings().iter().filter(|bi| !should_generate_arg(bi.ast())) { body.extend(self.generate_field_attrs_code(binding)); } body @@ -253,7 +253,7 @@ impl DiagnosticDeriveVariantBuilder { let ident = format_ident!("{}", ident); // strip `r#` prefix, if present quote! { - diag.set_arg( + diag.arg( stringify!(#ident), #field_binding ); @@ -312,7 +312,7 @@ impl DiagnosticDeriveVariantBuilder { let name = ident.to_string(); match (&attr.meta, name.as_str()) { // Don't need to do anything - by virtue of the attribute existing, the - // `set_arg` call will not be generated. + // `arg` call will not be generated. (Meta::Path(_), "skip_arg") => return Ok(quote! {}), (Meta::Path(_), "primary_span") => { match self.kind { @@ -320,7 +320,7 @@ impl DiagnosticDeriveVariantBuilder { report_error_if_not_applied_to_span(attr, &info)?; return Ok(quote! { - diag.set_span(#binding); + diag.span(#binding); }); } DiagnosticDeriveKind::LintDiagnostic => { diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 663abecb67c..c029b931e7d 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -6,8 +6,8 @@ use crate::diagnostics::error::{ use crate::diagnostics::utils::{ build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident, report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, - should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, - HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, + should_generate_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, + SetOnce, SpannedOption, SubdiagnosticKind, }; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -214,7 +214,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } /// Generates the code for a field with no attributes. - fn generate_field_set_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { + fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { let diag = &self.parent.diag; let field = binding_info.ast(); @@ -225,7 +225,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let ident = format_ident!("{}", ident); // strip `r#` prefix, if present quote! { - #diag.set_arg( + #diag.arg( stringify!(#ident), #field_binding ); @@ -505,7 +505,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .variant .bindings() .iter() - .filter(|binding| !should_generate_set_arg(binding.ast())) + .filter(|binding| !should_generate_arg(binding.ast())) .map(|binding| self.generate_field_attr_code(binding, kind_stats)) .collect(); @@ -593,8 +593,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .variant .bindings() .iter() - .filter(|binding| should_generate_set_arg(binding.ast())) - .map(|binding| self.generate_field_set_arg(binding)) + .filter(|binding| should_generate_arg(binding.ast())) + .map(|binding| self.generate_field_arg(binding)) .collect(); let formatting_init = &self.formatting_init; diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 2700f02e33a..4684306e235 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -584,7 +584,7 @@ pub(super) enum SubdiagnosticKind { suggestion_kind: SuggestionKind, applicability: SpannedOption<Applicability>, /// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation - /// of formatting and diagnostic emission so that `set_arg` calls can happen in-between.. + /// of formatting and diagnostic emission so that `arg` calls can happen in-between.. code_field: syn::Ident, /// Initialization logic for `code_field`'s variable, e.g. /// `let __formatted_code = /* whatever */;` @@ -863,9 +863,9 @@ impl quote::IdentFragment for SubdiagnosticKind { } } -/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic +/// Returns `true` if `field` should generate a `arg` call rather than any other diagnostic /// call (like `span_label`). -pub(super) fn should_generate_set_arg(field: &Field) -> bool { +pub(super) fn should_generate_arg(field: &Field) -> bool { // Perhaps this should be an exhaustive list... field.attrs.iter().all(|attr| is_doc_comment(attr)) } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index f558b74be9a..f5d942b924e 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -56,6 +56,8 @@ decl_derive!( hash_stable::hash_stable_no_context_derive ); +decl_derive!([Decodable_Generic] => serialize::decodable_generic_derive); +decl_derive!([Encodable_Generic] => serialize::encodable_generic_derive); decl_derive!([Decodable] => serialize::decodable_derive); decl_derive!([Encodable] => serialize::encodable_derive); decl_derive!([TyDecodable] => serialize::type_decodable_derive); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 047066ac681..9ca7ce09ba6 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -32,6 +32,14 @@ pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; + s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_span::SpanDecoder}); + s.add_bounds(synstructure::AddBounds::Generics); + + decodable_body(s, decoder_ty) +} + +pub fn decodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder}); s.add_bounds(synstructure::AddBounds::Generics); @@ -130,6 +138,14 @@ pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let encoder_ty = quote! { __E }; + s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder}); + s.add_bounds(synstructure::AddBounds::Generics); + + encodable_body(s, encoder_ty, false) +} + +pub fn encodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder}); s.add_bounds(synstructure::AddBounds::Generics); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index a3da8c14f63..bb02a8a1e47 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -196,6 +196,10 @@ impl CStore { CrateMetadataRef { cdata, cstore: self } } + pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata { + self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}")) + } + fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) { assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry"); self.metas[cnum] = Some(Box::new(data)); @@ -207,6 +211,12 @@ impl CStore { .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data))) } + fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> { + self.metas + .iter_enumerated_mut() + .filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data))) + } + fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) { if !deps.contains(&cnum) { let data = self.get_crate_data(cnum); @@ -586,11 +596,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { match result { (LoadResult::Previous(cnum), None) => { - let data = self.cstore.get_crate_data(cnum); + let data = self.cstore.get_crate_data_mut(cnum); if data.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; } - data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind)); + data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind)); if let Some(private_dep) = private_dep { data.update_and_private_dep(private_dep); } @@ -637,17 +647,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { })) } - fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) { - let cmeta = self.cstore.get_crate_data(cnum); - if cmeta.update_extern_crate(extern_crate) { - // Propagate the extern crate info to dependencies if it was updated. - let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; - for dep_cnum in cmeta.dependencies() { - self.update_extern_crate(dep_cnum, extern_crate); - } - } - } - // Go through the crate metadata and load any crates that it references fn resolve_crate_deps( &mut self, @@ -726,17 +725,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let mut runtime_found = false; let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); + let mut panic_runtimes = Vec::new(); for (cnum, data) in self.cstore.iter_crate_data() { needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); if data.is_panic_runtime() { // Inject a dependency from all #![needs_panic_runtime] to this // #![panic_runtime] crate. - self.inject_dependency_if(cnum, "a panic runtime", &|data| { - data.needs_panic_runtime() - }); + panic_runtimes.push(cnum); runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit; } } + for cnum in panic_runtimes { + self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); + } // If an explicitly linked and matching panic runtime was found, or if // we just don't need one at all, then we're done here and there's @@ -917,7 +918,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } fn inject_dependency_if( - &self, + &mut self, krate: CrateNum, what: &str, needs_dep: &dyn Fn(&CrateMetadata) -> bool, @@ -947,7 +948,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // crate provided for this compile, but in order for this compilation to // be successfully linked we need to inject a dependency (to order the // crates on the command line correctly). - for (cnum, data) in self.cstore.iter_crate_data() { + for (cnum, data) in self.cstore.iter_crate_data_mut() { if needs_dep(data) { info!("injecting a dep from {} to {}", cnum, krate); data.add_dependency(krate); @@ -1031,7 +1032,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let cnum = self.resolve_crate(name, item.span, dep_kind)?; let path_len = definitions.def_path(def_id).data.len(); - self.update_extern_crate( + self.cstore.update_extern_crate( cnum, ExternCrate { src: ExternCrateSource::Extern(def_id.to_def_id()), @@ -1049,7 +1050,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> { let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?; - self.update_extern_crate( + self.cstore.update_extern_crate( cnum, ExternCrate { src: ExternCrateSource::Path, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index e13068cb6f9..27c26d31781 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -500,10 +500,10 @@ pub(crate) struct MultipleCandidates { impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for MultipleCandidates { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_multiple_candidates); - diag.set_arg("crate_name", self.crate_name); - diag.set_arg("flavor", self.flavor); + diag.arg("crate_name", self.crate_name); + diag.arg("flavor", self.flavor); diag.code(error_code!(E0464)); - diag.set_span(self.span); + diag.span(self.span); for (i, candidate) in self.candidates.iter().enumerate() { diag.note(format!("candidate #{}: {}", i + 1, candidate.display())); } @@ -596,10 +596,10 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_invalid_meta_files); - diag.set_arg("crate_name", self.crate_name); - diag.set_arg("add_info", self.add_info); + diag.arg("crate_name", self.crate_name); + diag.arg("add_info", self.add_info); diag.code(error_code!(E0786)); - diag.set_span(self.span); + diag.span(self.span); for crate_rejection in self.crate_rejections { diag.note(crate_rejection); } @@ -623,12 +623,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for CannotFindCrate { #[track_caller] fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::metadata_cannot_find_crate); - diag.set_arg("crate_name", self.crate_name); - diag.set_arg("current_crate", self.current_crate); - diag.set_arg("add_info", self.add_info); - diag.set_arg("locator_triple", self.locator_triple.triple()); + diag.arg("crate_name", self.crate_name); + diag.arg("current_crate", self.current_crate); + diag.arg("add_info", self.add_info); + diag.arg("locator_triple", self.locator_triple.triple()); diag.code(error_code!(E0463)); - diag.set_span(self.span); + diag.span(self.span); if (self.crate_name == sym::std || self.crate_name == sym::core) && self.locator_triple != TargetTriple::from_triple(config::host_triple()) { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2de29db9e5c..49e849964be 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -8,7 +8,7 @@ use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::owned_slice::OwnedSlice; -use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc, OnceLock}; +use rustc_data_structures::sync::{Lock, Lrc, OnceLock}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; @@ -26,12 +26,11 @@ use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_session::Session; use rustc_span::symbol::kw; -use rustc_span::{BytePos, Pos, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; use std::iter::TrustedLen; use std::path::Path; -use std::sync::atomic::Ordering; use std::{io, iter, mem}; pub(super) use cstore_impl::provide; @@ -96,15 +95,15 @@ pub(crate) struct CrateMetadata { /// IDs as they are seen from the current compilation session. cnum_map: CrateNumMap, /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime. - dependencies: AppendOnlyVec<CrateNum>, + dependencies: Vec<CrateNum>, /// How to link (or not link) this crate to the currently compiled crate. - dep_kind: Lock<CrateDepKind>, + dep_kind: CrateDepKind, /// Filesystem location of this crate. source: Lrc<CrateSource>, /// Whether or not this crate should be consider a private dependency. /// Used by the 'exported_private_dependencies' lint, and for determining /// whether to emit suggestions that reference this crate. - private_dep: AtomicBool, + private_dep: bool, /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`. host_hash: Option<Svh>, @@ -118,7 +117,7 @@ pub(crate) struct CrateMetadata { // --- Data used only for improving diagnostics --- /// Information about the `extern crate` item or path that caused this crate to be loaded. /// If this is `None`, then the crate was injected (e.g., by the allocator). - extern_crate: Lock<Option<ExternCrate>>, + extern_crate: Option<ExternCrate>, } /// Holds information about a rustc_span::SourceFile imported from another crate. @@ -409,21 +408,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum { - let cnum = CrateNum::from_u32(d.read_u32()); - d.map_encoded_cnum_to_current(cnum) - } -} - -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex { - DefIndex::from_u32(d.read_u32()) - } -} - impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex { #[inline] fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex { @@ -431,19 +415,29 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex { } } -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ast::AttrId { - #[inline] - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ast::AttrId { - let sess = d.sess.expect("can't decode AttrId without Session"); +impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { + fn decode_attr_id(&mut self) -> rustc_span::AttrId { + let sess = self.sess.expect("can't decode AttrId without Session"); sess.parse_sess.attr_id_generator.mk_attr_id() } -} -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext { - let cdata = decoder.cdata(); + fn decode_crate_num(&mut self) -> CrateNum { + let cnum = CrateNum::from_u32(self.read_u32()); + self.map_encoded_cnum_to_current(cnum) + } - let Some(sess) = decoder.sess else { + fn decode_def_index(&mut self) -> DefIndex { + DefIndex::from_u32(self.read_u32()) + } + + fn decode_def_id(&mut self) -> DefId { + DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } + } + + fn decode_syntax_context(&mut self) -> SyntaxContext { + let cdata = self.cdata(); + + let Some(sess) = self.sess else { bug!( "Cannot decode SyntaxContext without Session.\ You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." @@ -451,7 +445,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { }; let cname = cdata.root.name(); - rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| { + rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id); cdata .root @@ -461,21 +455,19 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { .decode((cdata, sess)) }) } -} -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId { - let local_cdata = decoder.cdata(); + fn decode_expn_id(&mut self) -> ExpnId { + let local_cdata = self.cdata(); - let Some(sess) = decoder.sess else { + let Some(sess) = self.sess else { bug!( "Cannot decode ExpnId without Session. \ You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`." ); }; - let cnum = CrateNum::decode(decoder); - let index = u32::decode(decoder); + let cnum = CrateNum::decode(self); + let index = u32::decode(self); let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| { let ExpnId { krate: cnum, local_id: index } = expn_id; @@ -503,27 +495,51 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId { }); expn_id } -} -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { - fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span { - let start = decoder.position(); - let tag = SpanTag(decoder.peek_byte()); + fn decode_span(&mut self) -> Span { + let start = self.position(); + let tag = SpanTag(self.peek_byte()); let data = if tag.kind() == SpanKind::Indirect { // Skip past the tag we just peek'd. - decoder.read_u8(); - let offset_or_position = decoder.read_usize(); + self.read_u8(); + let offset_or_position = self.read_usize(); let position = if tag.is_relative_offset() { start - offset_or_position } else { offset_or_position }; - decoder.with_position(position, SpanData::decode) + self.with_position(position, SpanData::decode) } else { - SpanData::decode(decoder) + SpanData::decode(self) }; Span::new(data.lo, data.hi, data.ctxt, data.parent) } + + fn decode_symbol(&mut self) -> Symbol { + let tag = self.read_u8(); + + match tag { + SYMBOL_STR => { + let s = self.read_str(); + Symbol::intern(s) + } + SYMBOL_OFFSET => { + // read str offset + let pos = self.read_usize(); + + // move to str offset and read + self.opaque.with_position(pos, |d| { + let s = d.read_str(); + Symbol::intern(s) + }) + } + SYMBOL_PREINTERNED => { + let symbol_index = self.read_u32(); + Symbol::new_from_decoded(symbol_index) + } + _ => unreachable!(), + } + } } impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData { @@ -631,34 +647,6 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData { } } -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol { - fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { - let tag = d.read_u8(); - - match tag { - SYMBOL_STR => { - let s = d.read_str(); - Symbol::intern(s) - } - SYMBOL_OFFSET => { - // read str offset - let pos = d.read_usize(); - - // move to str offset and read - d.opaque.with_position(pos, |d| { - let s = d.read_str(); - Symbol::intern(s) - }) - } - SYMBOL_PREINTERNED => { - let symbol_index = d.read_u32(); - Symbol::new_from_decoded(symbol_index) - } - _ => unreachable!(), - } - } -} - impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) @@ -1818,11 +1806,11 @@ impl CrateMetadata { cnum, cnum_map, dependencies, - dep_kind: Lock::new(dep_kind), + dep_kind, source: Lrc::new(source), - private_dep: AtomicBool::new(private_dep), + private_dep, host_hash, - extern_crate: Lock::new(None), + extern_crate: None, hygiene_context: Default::default(), def_key_cache: Default::default(), }; @@ -1839,18 +1827,18 @@ impl CrateMetadata { } pub(crate) fn dependencies(&self) -> impl Iterator<Item = CrateNum> + '_ { - self.dependencies.iter() + self.dependencies.iter().copied() } - pub(crate) fn add_dependency(&self, cnum: CrateNum) { + pub(crate) fn add_dependency(&mut self, cnum: CrateNum) { self.dependencies.push(cnum); } - pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool { - let mut extern_crate = self.extern_crate.borrow_mut(); - let update = Some(new_extern_crate.rank()) > extern_crate.as_ref().map(ExternCrate::rank); + pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool { + let update = + Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank); if update { - *extern_crate = Some(new_extern_crate); + self.extern_crate = Some(new_extern_crate); } update } @@ -1860,15 +1848,15 @@ impl CrateMetadata { } pub(crate) fn dep_kind(&self) -> CrateDepKind { - *self.dep_kind.lock() + self.dep_kind } - pub(crate) fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) { - self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind)) + pub(crate) fn set_dep_kind(&mut self, dep_kind: CrateDepKind) { + self.dep_kind = dep_kind; } - pub(crate) fn update_and_private_dep(&self, private_dep: bool) { - self.private_dep.fetch_and(private_dep, Ordering::SeqCst); + pub(crate) fn update_and_private_dep(&mut self, private_dep: bool) { + self.private_dep &= private_dep; } pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index bb8f4af8e97..912c2f36eb3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -19,7 +19,7 @@ use rustc_middle::query::LocalCrate; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; -use rustc_session::cstore::CrateStore; +use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::{kw, Symbol}; @@ -290,13 +290,7 @@ provide! { tcx, def_id, other, cdata, cross_crate_inlinable => { cdata.cross_crate_inlinable(def_id.index) } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } - is_private_dep => { - // Parallel compiler needs to synchronize type checking and linting (which use this flag) - // so that they happen strictly crate loading. Otherwise, the full list of available - // impls aren't loaded yet. - use std::sync::atomic::Ordering; - cdata.private_dep.load(Ordering::Acquire) - } + is_private_dep => { cdata.private_dep } is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } @@ -305,10 +299,7 @@ provide! { tcx, def_id, other, cdata, is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } - extern_crate => { - let r = *cdata.extern_crate.lock(); - r.map(|c| &*tcx.arena.alloc(c)) - } + extern_crate => { cdata.extern_crate.map(|c| &*tcx.arena.alloc(c)) } is_no_builtins => { cdata.root.no_builtins } symbol_mangling_version => { cdata.root.symbol_mangling_version } reachable_non_generics => { @@ -339,10 +330,7 @@ provide! { tcx, def_id, other, cdata, implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } - dep_kind => { - let r = *cdata.dep_kind.lock(); - r - } + dep_kind => { cdata.dep_kind } module_children => { tcx.arena.alloc_from_iter(cdata.get_module_children(def_id.index, tcx.sess)) } @@ -357,8 +345,7 @@ provide! { tcx, def_id, other, cdata, missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { - let r = matches!(*cdata.extern_crate.borrow(), Some(extern_crate) if !extern_crate.is_direct()); - r + matches!(cdata.extern_crate, Some(extern_crate) if !extern_crate.is_direct()) } used_crate_source => { Lrc::clone(&cdata.source) } @@ -581,6 +568,19 @@ impl CStore { ) -> Span { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } + + pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) { + let cmeta = self.get_crate_data_mut(cnum); + if cmeta.update_extern_crate(extern_crate) { + // Propagate the extern crate info to dependencies if it was updated. + let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; + let dependencies = std::mem::take(&mut cmeta.dependencies); + for &dep_cnum in &dependencies { + self.update_extern_crate(dep_cnum, extern_crate); + } + self.get_crate_data_mut(cnum).dependencies = dependencies; + } + } } impl CrateStore for CStore { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5b296c098bc..a458b528a97 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2,10 +2,8 @@ use crate::errors::{FailCreateFileEncoder, FailWriteFile}; use crate::rmeta::*; use rustc_ast::Attribute; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::{Mmap, MmapMut}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; @@ -27,7 +25,7 @@ use rustc_session::config::{CrateType, OptLevel}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::symbol::sym; use rustc_span::{ - ExternalSource, FileName, SourceFile, SpanData, StableSourceFileId, SyntaxContext, + ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext, }; use std::borrow::Borrow; use std::collections::hash_map::Entry; @@ -125,70 +123,90 @@ impl<'a, 'tcx, I, T> Encodable<EncodeContext<'a, 'tcx>> for LazyTable<I, T> { } } -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum { +impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnIndex { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - if *self != LOCAL_CRATE && s.is_proc_macro { - panic!("Attempted to encode non-local CrateNum {self:?} for proc-macro crate"); - } s.emit_u32(self.as_u32()); } } -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - s.emit_u32(self.as_u32()); +impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { + fn encode_crate_num(&mut self, crate_num: CrateNum) { + if crate_num != LOCAL_CRATE && self.is_proc_macro { + panic!("Attempted to encode non-local CrateNum {crate_num:?} for proc-macro crate"); + } + self.emit_u32(crate_num.as_u32()); } -} -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnIndex { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - s.emit_u32(self.as_u32()); + fn encode_def_index(&mut self, def_index: DefIndex) { + self.emit_u32(def_index.as_u32()); } -} -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_ctxt, s); + fn encode_def_id(&mut self, def_id: DefId) { + def_id.krate.encode(self); + def_id.index.encode(self); } -} -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - if self.krate == LOCAL_CRATE { + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { + rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_ctxt, self); + } + + fn encode_expn_id(&mut self, expn_id: ExpnId) { + if expn_id.krate == LOCAL_CRATE { // We will only write details for local expansions. Non-local expansions will fetch // data from the corresponding crate's metadata. // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external // metadata from proc-macro crates. - s.hygiene_ctxt.schedule_expn_data_for_encoding(*self); + self.hygiene_ctxt.schedule_expn_data_for_encoding(expn_id); } - self.krate.encode(s); - self.local_id.encode(s); + expn_id.krate.encode(self); + expn_id.local_id.encode(self); } -} -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - match s.span_shorthands.entry(*self) { + fn encode_span(&mut self, span: Span) { + match self.span_shorthands.entry(span) { Entry::Occupied(o) => { // If an offset is smaller than the absolute position, we encode with the offset. // This saves space since smaller numbers encode in less bits. let last_location = *o.get(); // This cannot underflow. Metadata is written with increasing position(), so any // previously saved offset must be smaller than the current position. - let offset = s.opaque.position() - last_location; + let offset = self.opaque.position() - last_location; if offset < last_location { - SpanTag::indirect(true).encode(s); - offset.encode(s); + SpanTag::indirect(true).encode(self); + offset.encode(self); } else { - SpanTag::indirect(false).encode(s); - last_location.encode(s); + SpanTag::indirect(false).encode(self); + last_location.encode(self); } } Entry::Vacant(v) => { - let position = s.opaque.position(); + let position = self.opaque.position(); v.insert(position); // Data is encoded with a SpanTag prefix (see below). - self.data().encode(s); + span.data().encode(self); + } + } + } + + fn encode_symbol(&mut self, symbol: Symbol) { + // if symbol preinterned, emit tag and symbol index + if symbol.is_preinterned() { + self.opaque.emit_u8(SYMBOL_PREINTERNED); + self.opaque.emit_u32(symbol.as_u32()); + } else { + // otherwise write it as string or as offset to it + match self.symbol_table.entry(symbol) { + Entry::Vacant(o) => { + self.opaque.emit_u8(SYMBOL_STR); + let pos = self.opaque.position(); + o.insert(pos); + self.emit_str(symbol.as_str()); + } + Entry::Occupied(o) => { + let x = *o.get(); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); + } } } } @@ -337,31 +355,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData { } } -impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { - // if symbol preinterned, emit tag and symbol index - if self.is_preinterned() { - s.opaque.emit_u8(SYMBOL_PREINTERNED); - s.opaque.emit_u32(self.as_u32()); - } else { - // otherwise write it as string or as offset to it - match s.symbol_table.entry(*self) { - Entry::Vacant(o) => { - s.opaque.emit_u8(SYMBOL_STR); - let pos = s.opaque.position(); - o.insert(pos); - s.emit_str(self.as_str()); - } - Entry::Occupied(o) => { - let x = *o.get(); - s.emit_u8(SYMBOL_OFFSET); - s.emit_usize(x); - } - } - } - } -} - impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for [u8] { fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) { Encoder::emit_usize(e, self.len()); @@ -1914,14 +1907,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { empty_proc_macro!(self); let tcx = self.tcx; let lib_features = tcx.lib_features(LOCAL_CRATE); - self.lazy_array(lib_features.to_vec()) + self.lazy_array(lib_features.to_sorted_vec()) } fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> { empty_proc_macro!(self); let tcx = self.tcx; let implications = tcx.stability_implications(LOCAL_CRATE); - self.lazy_array(implications.iter().map(|(k, v)| (*k, *v))) + let sorted = implications.to_sorted_stable_ord(); + self.lazy_array(sorted.into_iter().map(|(k, v)| (*k, *v))) } fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> { @@ -2033,14 +2027,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> { empty_proc_macro!(self); let tcx = self.tcx; - let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect(); - tcx.with_stable_hashing_context(|mut ctx| { - all_impls.sort_by_cached_key(|&(&simp, _)| { - let mut hasher = StableHasher::new(); - simp.hash_stable(&mut ctx, &mut hasher); - hasher.finish::<Fingerprint>() - }) + let all_impls = tcx.with_stable_hashing_context(|hcx| { + tcx.crate_inherent_impls(()).incoherent_impls.to_sorted(&hcx, true) }); + let all_impls: Vec<_> = all_impls .into_iter() .map(|(&simp, impls)| { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 54ee50c2358..2f775882693 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -12,7 +12,7 @@ use rustc_attr as attr; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; @@ -459,7 +459,7 @@ define_tables! { macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, proc_macro: Table<DefIndex, MacroKind>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, - trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>, + trait_impl_trait_tys: Table<DefIndex, LazyValue<DefIdMap<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)>>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fd494a10d..0ab09dadf58 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -103,7 +103,7 @@ macro_rules! arena_types { [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, [decode] trait_impl_trait_tys: - rustc_data_structures::fx::FxHashMap< + rustc_data_structures::unord::UnordMap< rustc_hir::def_id::DefId, rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>> >, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index ae432a04065..c5e4dfaf19e 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -312,16 +312,17 @@ pub fn struct_lint_level( // create a `DiagnosticBuilder` and continue as we would for warnings. rustc_errors::Level::Expect(expect_id) } - Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)), - Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None), - Level::Deny | Level::Forbid => rustc_errors::Level::Error { lint: true }, + Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::ForceWarning(Some(expect_id)), + Level::ForceWarn(None) => rustc_errors::Level::ForceWarning(None), + Level::Warn => rustc_errors::Level::Warning, + Level::Deny | Level::Forbid => rustc_errors::Level::Error, }; let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, ""); if let Some(span) = span { - err.set_span(span); + err.span(span); } - err.set_is_lint(); + err.is_lint(); // If this code originates in a foreign macro, aka something that this crate // did not itself author, then it's likely that there's nothing this crate @@ -348,25 +349,21 @@ pub fn struct_lint_level( // Delay evaluating and setting the primary message until after we've // suppressed the lint due to macros. - err.set_primary_message(msg); + err.primary_message(msg); + + let name = lint.name_lower(); + err.code(DiagnosticId::Lint { name, has_future_breakage }); // Lint diagnostics that are covered by the expect level will not be emitted outside // the compiler. It is therefore not necessary to add any information for the user. // This will therefore directly call the decorate function which will in turn emit // the `Diagnostic`. if let Level::Expect(_) = level { - let name = lint.name_lower(); - err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false }); - decorate(&mut err); err.emit(); return; } - let name = lint.name_lower(); - let is_force_warn = matches!(level, Level::ForceWarn(_)); - err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); - if let Some(future_incompatible) = future_incompatible { let explanation = match future_incompatible.reason { FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 8c1b1ff12e9..bdb2270611a 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -4,7 +4,7 @@ pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; pub mod lib_features { - use rustc_data_structures::fx::FxHashMap; + use rustc_data_structures::unord::UnordMap; use rustc_span::{symbol::Symbol, Span}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -16,15 +16,16 @@ pub mod lib_features { #[derive(HashStable, Debug, Default)] pub struct LibFeatures { - pub stability: FxHashMap<Symbol, (FeatureStability, Span)>, + pub stability: UnordMap<Symbol, (FeatureStability, Span)>, } impl LibFeatures { - pub fn to_vec(&self) -> Vec<(Symbol, FeatureStability)> { - let mut all_features: Vec<_> = - self.stability.iter().map(|(&sym, &(stab, _))| (sym, stab)).collect(); - all_features.sort_unstable_by(|(a, _), (b, _)| a.as_str().cmp(b.as_str())); - all_features + pub fn to_sorted_vec(&self) -> Vec<(Symbol, FeatureStability)> { + self.stability + .to_sorted_stable_ord() + .iter() + .map(|(&sym, &(stab, _))| (sym, stab)) + .collect() } } } diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index b4dd8f6f4a7..5d6a7f75df8 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -7,12 +7,11 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html use crate::ty::TyCtxt; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::{HirIdMap, Node}; use rustc_macros::HashStable; -use rustc_query_system::ich::StableHashingContext; use rustc_span::{Span, DUMMY_SP}; use std::fmt; @@ -205,7 +204,7 @@ impl Scope { pub type ScopeDepth = u32; /// The region scope tree encodes information about region relationships. -#[derive(Default, Debug)] +#[derive(Default, Debug, HashStable)] pub struct ScopeTree { /// If not empty, this body is the root of this region hierarchy. pub root_body: Option<hir::HirId>, @@ -306,7 +305,7 @@ pub struct ScopeTree { /// The reason is that semantically, until the `box` expression returns, /// the values are still owned by their containing expressions. So /// we'll see that `&x`. - pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>, + pub yield_in_scope: UnordMap<Scope, Vec<YieldData>>, } /// Identifies the reason that a given expression is an rvalue candidate @@ -404,23 +403,3 @@ impl ScopeTree { self.yield_in_scope.get(&scope).map(Deref::deref) } } - -impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ScopeTree { - root_body, - ref parent_map, - ref var_map, - ref destruction_scopes, - ref rvalue_candidates, - ref yield_in_scope, - } = *self; - - root_body.hash_stable(hcx, hasher); - parent_map.hash_stable(hcx, hasher); - var_map.hash_stable(hcx, hasher); - destruction_scopes.hash_stable(hcx, hasher); - rvalue_candidates.hash_stable(hcx, hasher); - yield_in_scope.hash_stable(hcx, hasher); - } -} diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index c59704fc023..610afd95f3c 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -2,7 +2,7 @@ use crate::ty; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_hir::{ItemLocalId, OwnerId}; @@ -51,7 +51,7 @@ pub enum ObjectLifetimeDefault { pub struct ResolveBoundVars { /// Maps from every use of a named (not anonymous) lifetime to a /// `Region` describing how that region is bound - pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, ResolvedArg>>, + pub defs: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, ResolvedArg>>, - pub late_bound_vars: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>, + pub late_bound_vars: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>>, } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index b2d1124b2ed..90b479cf2f4 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -8,11 +8,11 @@ use rustc_ast::NodeId; use rustc_attr::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::{self as hir, HirId}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; @@ -61,10 +61,10 @@ impl DeprecationEntry { pub struct Index { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. - pub stab_map: FxHashMap<LocalDefId, Stability>, - pub const_stab_map: FxHashMap<LocalDefId, ConstStability>, - pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>, - pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>, + pub stab_map: LocalDefIdMap<Stability>, + pub const_stab_map: LocalDefIdMap<ConstStability>, + pub default_body_stab_map: LocalDefIdMap<DefaultBodyStability>, + pub depr_map: LocalDefIdMap<DeprecationEntry>, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -77,7 +77,7 @@ pub struct Index { /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of /// unstable feature" error for a feature that was implied. - pub implications: FxHashMap<Symbol, Symbol>, + pub implications: UnordMap<Symbol, Symbol>, } impl Index { diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index a92b85a716f..4047891d769 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -14,7 +14,6 @@ use either::{Left, Right}; use rustc_ast::Mutability; use rustc_data_structures::intern::Interned; -use rustc_span::DUMMY_SP; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ @@ -314,9 +313,7 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { /// available to the compiler to do so. pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { Self::uninit_inner(size, align, || { - ty::tls::with(|tcx| { - tcx.dcx().span_delayed_bug(DUMMY_SP, "exhausted memory during interpretation") - }); + ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation")); InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into() }) } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e6536074f35..1b4e9c28635 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -2,14 +2,10 @@ use super::{AllocId, AllocRange, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; -use crate::query::TyCtxtAt; use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; use rustc_data_structures::sync::Lock; -use rustc_errors::{ - struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, - IntoDiagnosticArg, -}; +use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; @@ -90,10 +86,6 @@ pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; /// This is needed in `thir::pattern::lower_inline_const`. pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>; -pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { - struct_span_err!(tcx.dcx(), tcx.span, E0080, "{}", msg) -} - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(InterpErrorInfo<'_>, 8); diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 2db56008553..0da3524e055 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,12 +142,11 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, - InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, - MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, - ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, - ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, + EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, + InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, + ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, + UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, }; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5c425fef27e..36f5ba161d5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -55,7 +55,6 @@ pub mod mono; pub mod patch; pub mod pretty; mod query; -pub mod spanview; mod statement; mod syntax; pub mod tcx; @@ -250,6 +249,9 @@ pub struct CoroutineInfo<'tcx> { /// The yield type of the function, if it is a coroutine. pub yield_ty: Option<Ty<'tcx>>, + /// The resume type of the function, if it is a coroutine. + pub resume_ty: Option<Ty<'tcx>>, + /// Coroutine drop glue. pub coroutine_drop: Option<Body<'tcx>>, @@ -261,6 +263,23 @@ pub struct CoroutineInfo<'tcx> { pub coroutine_kind: CoroutineKind, } +impl<'tcx> CoroutineInfo<'tcx> { + // Sets up `CoroutineInfo` for a pre-coroutine-transform MIR body. + pub fn initial( + coroutine_kind: CoroutineKind, + yield_ty: Ty<'tcx>, + resume_ty: Ty<'tcx>, + ) -> CoroutineInfo<'tcx> { + CoroutineInfo { + coroutine_kind, + yield_ty: Some(yield_ty), + resume_ty: Some(resume_ty), + coroutine_drop: None, + coroutine_layout: None, + } + } +} + /// The lowered representation of a single function. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct Body<'tcx> { @@ -365,7 +384,7 @@ impl<'tcx> Body<'tcx> { arg_count: usize, var_debug_info: Vec<VarDebugInfo<'tcx>>, span: Span, - coroutine_kind: Option<CoroutineKind>, + coroutine: Option<Box<CoroutineInfo<'tcx>>>, tainted_by_errors: Option<ErrorGuaranteed>, ) -> Self { // We need `arg_count` locals, and one for the return place. @@ -382,14 +401,7 @@ impl<'tcx> Body<'tcx> { source, basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, - coroutine: coroutine_kind.map(|coroutine_kind| { - Box::new(CoroutineInfo { - yield_ty: None, - coroutine_drop: None, - coroutine_layout: None, - coroutine_kind, - }) - }), + coroutine, local_decls, user_type_annotations, arg_count, @@ -552,6 +564,11 @@ impl<'tcx> Body<'tcx> { } #[inline] + pub fn resume_ty(&self) -> Option<Ty<'tcx>> { + self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty) + } + + #[inline] pub fn coroutine_layout(&self) -> Option<&CoroutineLayout<'tcx>> { self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_layout.as_ref()) } @@ -720,7 +737,7 @@ pub struct SourceInfo { pub span: Span, /// The source scope, keeping track of which bindings can be - /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. + /// seen by debuginfo, active lint levels, etc. pub scope: SourceScope, } @@ -942,7 +959,7 @@ pub struct LocalDecl<'tcx> { /// Extra information about a some locals that's used for diagnostics and for /// classifying variables into local variables, statics, etc, which is needed e.g. -/// for unsafety checking. +/// for borrow checking. /// /// Not used for non-StaticRef temporaries, the return place, or anonymous /// function parameters. @@ -1299,6 +1316,7 @@ impl<'tcx> BasicBlockData<'tcx> { } /// Does the block have no statements and an unreachable terminator? + #[inline] pub fn is_empty_unreachable(&self) -> bool { self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) } @@ -1568,6 +1586,7 @@ impl Location { /// /// Note that if this location represents a terminator, then the /// resulting location would be out of bounds and invalid. + #[inline] pub fn successor_within_block(&self) -> Location { Location { block: self.block, statement_index: self.statement_index + 1 } } @@ -1604,6 +1623,7 @@ impl Location { false } + #[inline] pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool { if self.block == other.block { self.statement_index <= other.statement_index @@ -1623,6 +1643,7 @@ pub enum DefLocation { } impl DefLocation { + #[inline] pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>) -> bool { match self { DefLocation::Argument => true, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 0b487eae36d..a1e5d73a0fd 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -5,7 +5,6 @@ use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; -use super::spanview::write_mir_fn_spanview; use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, @@ -141,16 +140,6 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, body, false, &mut file)?; }; } - - if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview { - let _: io::Result<()> = try { - let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body); - let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?; - if body.source.def_id().is_local() { - write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?; - } - }; - } } /// Returns the file basename portion (without extension) of a filename path diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs deleted file mode 100644 index cb9fc0d37f2..00000000000 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ /dev/null @@ -1,642 +0,0 @@ -use rustc_middle::hir; -use rustc_middle::mir::*; -use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos}; - -use std::cmp; -use std::io::{self, Write}; - -pub const TOOLTIP_INDENT: &str = " "; - -const CARET: char = '\u{2038}'; // Unicode `CARET` -const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET` -const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` -const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">"; -const HEADER: &str = r#"<!DOCTYPE html> -<html lang="en"> -<head> -<meta charset="utf-8">"#; -const START_BODY: &str = r#"</head> -<body>"#; -const FOOTER: &str = r#"</body> -</html>"#; - -const STYLE_SECTION: &str = r#"<style> - .line { - counter-increment: line; - } - .line:before { - content: counter(line) ": "; - font-family: Menlo, Monaco, monospace; - font-style: italic; - width: 3.8em; - display: inline-block; - text-align: right; - filter: opacity(50%); - -webkit-user-select: none; - } - .code { - color: #dddddd; - background-color: #222222; - font-family: Menlo, Monaco, monospace; - line-height: 1.4em; - border-bottom: 2px solid #222222; - white-space: pre; - display: inline-block; - } - .odd { - background-color: #55bbff; - color: #223311; - } - .even { - background-color: #ee7756; - color: #551133; - } - .code { - --index: calc(var(--layer) - 1); - padding-top: calc(var(--index) * 0.15em); - filter: - hue-rotate(calc(var(--index) * 25deg)) - saturate(calc(100% - (var(--index) * 2%))) - brightness(calc(100% - (var(--index) * 1.5%))); - } - .annotation { - color: #4444ff; - font-family: monospace; - font-style: italic; - display: none; - -webkit-user-select: none; - } - body:active .annotation { - /* requires holding mouse down anywhere on the page */ - display: inline-block; - } - span:hover .annotation { - /* requires hover over a span ONLY on its first line */ - display: inline-block; - } -</style>"#; - -/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. -#[derive(Clone, Debug)] -pub struct SpanViewable { - pub bb: BasicBlock, - pub span: Span, - pub id: String, - pub tooltip: String, -} - -/// Write a spanview HTML+CSS file to analyze MIR element spans. -pub fn write_mir_fn_spanview<'tcx, W>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - spanview: MirSpanview, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let def_id = body.source.def_id(); - let hir_body = hir_body(tcx, def_id); - if hir_body.is_none() { - return Ok(()); - } - let body_span = hir_body.unwrap().value.span; - let mut span_viewables = Vec::new(); - for (bb, data) in body.basic_blocks.iter_enumerated() { - match spanview { - MirSpanview::Statement => { - for (i, statement) in data.statements.iter().enumerate() { - if let Some(span_viewable) = - statement_span_viewable(tcx, body_span, bb, i, statement) - { - span_viewables.push(span_viewable); - } - } - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Terminator => { - if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - MirSpanview::Block => { - if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { - span_viewables.push(span_viewable); - } - } - } - } - write_document(tcx, fn_span(tcx, def_id), span_viewables, title, w)?; - Ok(()) -} - -/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated -/// list `SpanViewable`s. -pub fn write_document<'tcx, W>( - tcx: TyCtxt<'tcx>, - spanview_span: Span, - mut span_viewables: Vec<SpanViewable>, - title: &str, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let mut from_pos = spanview_span.lo(); - let end_pos = spanview_span.hi(); - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(from_pos); - let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); - debug!( - "spanview_span={:?}; source is:\n{}{}", - spanview_span, - indent_to_initial_start_col, - source_map.span_to_snippet(spanview_span).expect("function should have printable source") - ); - writeln!(w, "{HEADER}")?; - writeln!(w, "<title>{title}</title>")?; - writeln!(w, "{STYLE_SECTION}")?; - writeln!(w, "{START_BODY}")?; - write!( - w, - r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#, - start.line - 1, - indent_to_initial_start_col, - )?; - span_viewables.sort_unstable_by(|a, b| { - let a = a.span; - let b = b.span; - if a.lo() == b.lo() { - // Sort hi() in reverse order so shorter spans are attempted after longer spans. - // This should give shorter spans a higher "layer", so they are not covered by - // the longer spans. - b.hi().partial_cmp(&a.hi()) - } else { - a.lo().partial_cmp(&b.lo()) - } - .unwrap() - }); - let mut ordered_viewables = &span_viewables[..]; - const LOWEST_VIEWABLE_LAYER: usize = 1; - let mut alt = false; - while ordered_viewables.len() > 0 { - debug!( - "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", - from_pos.to_usize(), - end_pos.to_usize(), - ordered_viewables.len() - ); - let curr_id = &ordered_viewables[0].id; - let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - end_pos, - ordered_viewables, - alt, - LOWEST_VIEWABLE_LAYER, - w, - )?; - debug!( - "DONE calling write_next_viewable, with new from_pos={}, \ - and remaining viewables len={}", - next_from_pos.to_usize(), - next_ordered_viewables.len() - ); - assert!( - from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_ordered_viewables.len() != ordered_viewables.len() { - ordered_viewables = next_ordered_viewables; - if let Some(next_ordered_viewable) = ordered_viewables.first() { - if &next_ordered_viewable.id != curr_id { - alt = !alt; - } - } - } - } - if from_pos < end_pos { - write_coverage_gap(tcx, from_pos, end_pos, w)?; - } - writeln!(w, r#"</span></div>"#)?; - writeln!(w, "{FOOTER}")?; - Ok(()) -} - -/// Format a string showing the start line and column, and end line and column within a file. -pub fn source_range_no_file(tcx: TyCtxt<'_>, span: Span) -> String { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = source_map.lookup_char_pos(span.hi()); - format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) -} - -fn statement_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - i: usize, - statement: &Statement<'tcx>, -) -> Option<SpanViewable> { - let span = statement.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}[{}]", bb.index(), i); - let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn terminator_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option<SpanViewable> { - let term = data.terminator(); - let span = term.source_info.span; - if !body_span.contains(span) { - return None; - } - let id = format!("{}:{}", bb.index(), term.kind.name()); - let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn block_span_viewable<'tcx>( - tcx: TyCtxt<'tcx>, - body_span: Span, - bb: BasicBlock, - data: &BasicBlockData<'tcx>, -) -> Option<SpanViewable> { - let span = compute_block_span(data, body_span); - if !body_span.contains(span) { - return None; - } - let id = format!("{}", bb.index()); - let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { bb, span, id, tooltip }) -} - -fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span { - let mut span = data.terminator().source_info.span; - for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { - // Only combine Spans from the root context, and within the function's body_span. - if statement_span.ctxt().is_root() && body_span.contains(statement_span) { - span = span.to(statement_span); - } - } - span -} - -/// Recursively process each ordered span. Spans that overlap will have progressively varying -/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will -/// have alternating style choices, to help distinguish between them if, visually adjacent. -/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true -/// and false, for each adjacent non-overlapping span. Source code between the spans (code -/// that is not in any coverage region) has neutral styling. -fn write_next_viewable_with_overlaps<'tcx, 'b, W>( - tcx: TyCtxt<'tcx>, - mut from_pos: BytePos, - mut to_pos: BytePos, - ordered_viewables: &'b [SpanViewable], - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<(BytePos, &'b [SpanViewable])> -where - W: Write, -{ - let debug_indent = " ".repeat(layer); - let (viewable, mut remaining_viewables) = - ordered_viewables.split_first().expect("ordered_viewables should have some"); - - if from_pos < viewable.span.lo() { - debug!( - "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ - of {:?}), with to_pos={}", - debug_indent, - from_pos.to_usize(), - viewable.span.lo().to_usize(), - viewable.span, - to_pos.to_usize() - ); - let hi = cmp::min(viewable.span.lo(), to_pos); - write_coverage_gap(tcx, from_pos, hi, w)?; - from_pos = hi; - if from_pos < viewable.span.lo() { - debug!( - "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", - debug_indent, - from_pos.to_usize() - ); - return Ok((from_pos, ordered_viewables)); - } - } - - if from_pos < viewable.span.hi() { - // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing - // with room to print the tail. - to_pos = cmp::min(viewable.span.hi(), to_pos); - debug!( - "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", - debug_indent, - viewable.span.hi().to_usize(), - to_pos.to_usize() - ); - } - - let mut subalt = false; - while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { - let overlapping_viewable = &remaining_viewables[0]; - debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); - - let span = - trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); - let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { - // `viewable` is not yet fully rendered, so start writing the span, up to either the - // `to_pos` or the next `overlapping_viewable`, whichever comes first. - debug!( - "{}make html_snippet (may not write it if early exit) for partial span {:?} \ - of viewable.span {:?}", - debug_indent, span, viewable.span - ); - from_pos = span.hi(); - make_html_snippet(tcx, span, Some(viewable)) - } else { - None - }; - - // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. - // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early - // exit, there should be another opportunity to write the tail marker. - if !span.is_empty() { - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - some_html_snippet = None; - } - - if from_pos < overlapping_viewable.span.lo() { - debug!( - "{}EARLY RETURN: from_pos={} has not yet reached the \ - overlapping_viewable.span {:?}", - debug_indent, - from_pos.to_usize(), - overlapping_viewable.span - ); - // must have reached `to_pos` before reaching the start of the - // `overlapping_viewable.span` - return Ok((from_pos, ordered_viewables)); - } - - if from_pos == to_pos - && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) - { - debug!( - "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ - empty, or not from_pos", - debug_indent, - to_pos.to_usize(), - overlapping_viewable.span - ); - // `to_pos` must have occurred before the overlapping viewable. Return - // `ordered_viewables` so we can continue rendering the `viewable`, from after the - // `to_pos`. - return Ok((from_pos, ordered_viewables)); - } - - if let Some(ref html_snippet) = some_html_snippet { - debug!( - "{}write html_snippet for that partial span of viewable.span {:?}", - debug_indent, viewable.span - ); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - - debug!( - "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ - and viewables len={}", - debug_indent, - from_pos.to_usize(), - to_pos.to_usize(), - remaining_viewables.len() - ); - // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. - let curr_id = &remaining_viewables[0].id; - let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( - tcx, - from_pos, - to_pos, - remaining_viewables, - subalt, - layer + 1, - w, - )?; - debug!( - "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ - viewables len={}", - debug_indent, - next_from_pos.to_usize(), - next_remaining_viewables.len() - ); - assert!( - from_pos != next_from_pos - || remaining_viewables.len() != next_remaining_viewables.len(), - "write_next_viewable_with_overlaps() must make a state change" - ); - from_pos = next_from_pos; - if next_remaining_viewables.len() != remaining_viewables.len() { - remaining_viewables = next_remaining_viewables; - if let Some(next_ordered_viewable) = remaining_viewables.first() { - if &next_ordered_viewable.id != curr_id { - subalt = !subalt; - } - } - } - } - if from_pos <= viewable.span.hi() { - let span = trim_span(viewable.span, from_pos, to_pos); - debug!( - "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", - debug_indent, span, viewable.span - ); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(viewable)) { - from_pos = span.hi(); - write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; - } - } - debug!("{}RETURN: No more overlap", debug_indent); - Ok(( - from_pos, - if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, - )) -} - -#[inline(always)] -fn write_coverage_gap<W>(tcx: TyCtxt<'_>, lo: BytePos, hi: BytePos, w: &mut W) -> io::Result<()> -where - W: Write, -{ - let span = Span::with_root_ctxt(lo, hi); - if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { - write_span(html_snippet, "", false, 0, w) - } else { - Ok(()) - } -} - -fn write_span<W>( - html_snippet: &str, - tooltip: &str, - alt: bool, - layer: usize, - w: &mut W, -) -> io::Result<()> -where - W: Write, -{ - let maybe_alt_class = if layer > 0 { if alt { " odd" } else { " even" } } else { "" }; - let maybe_title_attr = if !tooltip.is_empty() { - format!(" title=\"{}\"", escape_attr(tooltip)) - } else { - "".to_owned() - }; - if layer == 1 { - write!(w, "<span>")?; - } - for (i, line) in html_snippet.lines().enumerate() { - if i > 0 { - write!(w, "{NEW_LINE_SPAN}")?; - } - write!( - w, - r#"<span class="code{maybe_alt_class}" style="--layer: {layer}"{maybe_title_attr}>{line}</span>"# - )?; - } - // Check for and translate trailing newlines, because `str::lines()` ignores them - if html_snippet.ends_with('\n') { - write!(w, "{NEW_LINE_SPAN}")?; - } - if layer == 1 { - write!(w, "</span>")?; - } - Ok(()) -} - -fn make_html_snippet( - tcx: TyCtxt<'_>, - span: Span, - some_viewable: Option<&SpanViewable>, -) -> Option<String> { - let source_map = tcx.sess.source_map(); - let snippet = source_map - .span_to_snippet(span) - .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); - let html_snippet = if let Some(viewable) = some_viewable { - let is_head = span.lo() == viewable.span.lo(); - let is_tail = span.hi() == viewable.span.hi(); - let mut labeled_snippet = if is_head { - format!(r#"<span class="annotation">{}{}</span>"#, viewable.id, ANNOTATION_LEFT_BRACKET) - } else { - "".to_owned() - }; - if span.is_empty() { - if is_head && is_tail { - labeled_snippet.push(CARET); - } - } else { - labeled_snippet.push_str(&escape_html(&snippet)); - }; - if is_tail { - labeled_snippet.push_str(&format!( - r#"<span class="annotation">{}{}</span>"#, - ANNOTATION_RIGHT_BRACKET, viewable.id - )); - } - labeled_snippet - } else { - escape_html(&snippet) - }; - if html_snippet.is_empty() { None } else { Some(html_snippet) } -} - -fn tooltip<'tcx>( - tcx: TyCtxt<'tcx>, - spanview_id: &str, - span: Span, - statements: Vec<Statement<'tcx>>, - terminator: &Option<Terminator<'tcx>>, -) -> String { - let source_map = tcx.sess.source_map(); - let mut text = Vec::new(); - text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); - for statement in statements { - let source_range = source_range_no_file(tcx, statement.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - statement.kind.name(), - statement - )); - } - if let Some(term) = terminator { - let source_range = source_range_no_file(tcx, term.source_info.span); - text.push(format!( - "\n{}{}: {}: {:?}", - TOOLTIP_INDENT, - source_range, - term.kind.name(), - term.kind - )); - } - text.join("") -} - -fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { - trim_span_hi(trim_span_lo(span, from_pos), to_pos) -} - -fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { - if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } -} - -fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { - if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } -} - -fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { - let fn_decl_span = tcx.def_span(def_id); - if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) { - if fn_decl_span.eq_ctxt(body_span) { fn_decl_span.to(body_span) } else { body_span } - } else { - fn_decl_span - } -} - -fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> { - let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id)) -} - -fn escape_html(s: &str) -> String { - s.replace('&', "&").replace('<', "<").replace('>', ">") -} - -fn escape_attr(s: &str) -> String { - s.replace('&', "&") - .replace('\"', """) - .replace('\'', "'") - .replace('<', "<") - .replace('>', ">") -} diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 7be6deb6141..385237b357b 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -26,6 +26,7 @@ impl SwitchTargets { } /// Inverse of `SwitchTargets::static_if`. + #[inline] pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> { if let &[value] = &self.values[..] && let &[then, else_] = &self.targets[..] @@ -37,6 +38,7 @@ impl SwitchTargets { } /// Returns the fallback target that is jumped to when none of the values match the operand. + #[inline] pub fn otherwise(&self) -> BasicBlock { *self.targets.last().unwrap() } @@ -47,15 +49,18 @@ impl SwitchTargets { /// including the `otherwise` fallback target. /// /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. + #[inline] pub fn iter(&self) -> SwitchTargetsIter<'_> { SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) } } /// Returns a slice with all possible jump targets (including the fallback target). + #[inline] pub fn all_targets(&self) -> &[BasicBlock] { &self.targets } + #[inline] pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] { &mut self.targets } @@ -63,6 +68,7 @@ impl SwitchTargets { /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the /// specific value. This cannot fail, as it'll return the `otherwise` /// branch if there's not a specific match for the value. + #[inline] pub fn target_for_value(&self, value: u128) -> BasicBlock { self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise()) } @@ -75,10 +81,12 @@ pub struct SwitchTargetsIter<'a> { impl<'a> Iterator for SwitchTargetsIter<'a> { type Item = (u128, BasicBlock); + #[inline] fn next(&mut self) -> Option<Self::Item> { self.inner.next().map(|(val, bb)| (*val, *bb)) } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() } @@ -330,28 +338,34 @@ pub type SuccessorsMut<'a> = iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; impl<'tcx> Terminator<'tcx> { + #[inline] pub fn successors(&self) -> Successors<'_> { self.kind.successors() } + #[inline] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { self.kind.successors_mut() } + #[inline] pub fn unwind(&self) -> Option<&UnwindAction> { self.kind.unwind() } + #[inline] pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { self.kind.unwind_mut() } } impl<'tcx> TerminatorKind<'tcx> { + #[inline] pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } } + #[inline] pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { @@ -392,6 +406,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { @@ -430,6 +445,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn unwind(&self) -> Option<&UnwindAction> { match *self { TerminatorKind::Goto { .. } @@ -449,6 +465,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { match *self { TerminatorKind::Goto { .. } @@ -468,6 +485,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> { match self { TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)), @@ -475,6 +493,7 @@ impl<'tcx> TerminatorKind<'tcx> { } } + #[inline] pub fn as_goto(&self) -> Option<BasicBlock> { match self { TerminatorKind::Goto { target } => Some(*target), diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 132ecf91af1..2ccf5a9f6f7 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -996,6 +996,12 @@ macro_rules! super_body { TyContext::YieldTy(SourceInfo::outermost(span)) ); } + if let Some(resume_ty) = $(& $mutability)? gen.resume_ty { + $self.visit_ty( + resume_ty, + TyContext::ResumeTy(SourceInfo::outermost(span)) + ); + } } for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) { @@ -1244,6 +1250,8 @@ pub enum TyContext { YieldTy(SourceInfo), + ResumeTy(SourceInfo), + /// A type found at some location. Location(Location), } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 11376345052..945f17d5df2 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -40,7 +40,7 @@ pub trait Key: Sized { None } - fn ty_adt_id(&self) -> Option<DefId> { + fn ty_def_id(&self) -> Option<DefId> { None } } @@ -406,9 +406,10 @@ impl<'tcx> Key for Ty<'tcx> { DUMMY_SP } - fn ty_adt_id(&self) -> Option<DefId> { - match self.kind() { + fn ty_def_id(&self) -> Option<DefId> { + match *self.kind() { ty::Adt(adt, _) => Some(adt.did()), + ty::Coroutine(def_id, ..) => Some(def_id), _ => None, } } @@ -452,6 +453,10 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) } + + fn ty_def_id(&self) -> Option<DefId> { + self.value.ty_def_id() + } } impl Key for Symbol { @@ -550,7 +555,7 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { DUMMY_SP } - fn ty_adt_id(&self) -> Option<DefId> { + fn ty_def_id(&self) -> Option<DefId> { match self.1.value.kind() { ty::Adt(adt, _) => Some(adt.did()), _ => None, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3a54f5f6b3d..0e3b9984423 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -57,11 +57,11 @@ use rustc_ast as ast; use rustc_ast::expand::{allocator::AllocatorKind, StrippedCfgItem}; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, DocLinkResMap}; @@ -264,7 +264,7 @@ rustc_queries! { } query collect_return_position_impl_trait_in_trait_tys(key: DefId) - -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> + -> Result<&'tcx DefIdMap<ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> { desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" } cache_on_disk_if { key.is_local() } @@ -611,7 +611,7 @@ rustc_queries! { desc { "erasing regions from `{}`", ty } } - query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> { + query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> { arena_cache desc { "getting wasm import module map" } } @@ -869,15 +869,14 @@ rustc_queries! { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } - /// The result of unsafety-checking this `LocalDefId`. - query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { + /// The result of unsafety-checking this `LocalDefId` with the old checker. + query mir_unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } } - /// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be - /// used with `-Zthir-unsafeck`. - query thir_check_unsafety(key: LocalDefId) { + /// Unsafety-check this `LocalDefId`. + query check_unsafety(key: LocalDefId) { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } } @@ -938,10 +937,6 @@ rustc_queries! { desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } } - query check_mod_item_types(key: LocalModDefId) -> () { - desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) } - } - query check_mod_privacy(key: LocalModDefId) -> () { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } @@ -1392,6 +1387,8 @@ rustc_queries! { ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } + // we emit our own error during query cycle handling + cycle_delay_bug } /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. @@ -1542,7 +1539,7 @@ rustc_queries! { /// added or removed in any upstream crate. Instead use the narrower /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even /// better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<GenericArgsRef<'tcx>, CrateNum>> { + query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> { arena_cache desc { "collecting available upstream monomorphizations" } } @@ -1555,7 +1552,7 @@ rustc_queries! { /// You likely want to call `Instance::upstream_monomorphization()` /// instead of invoking this query directly. query upstream_monomorphizations_for(def_id: DefId) - -> Option<&'tcx FxHashMap<GenericArgsRef<'tcx>, CrateNum>> + -> Option<&'tcx UnordMap<GenericArgsRef<'tcx>, CrateNum>> { desc { |tcx| "collecting available upstream monomorphizations for `{}`", @@ -1667,7 +1664,7 @@ rustc_queries! { desc { "resolving lifetimes" } } query named_variable_map(_: hir::OwnerId) -> - Option<&'tcx FxHashMap<ItemLocalId, ResolvedArg>> { + Option<&'tcx FxIndexMap<ItemLocalId, ResolvedArg>> { desc { "looking up a named region" } } query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> { @@ -1683,7 +1680,7 @@ rustc_queries! { separate_provide_extern } query late_bound_vars_map(_: hir::OwnerId) - -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> { + -> Option<&'tcx FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>> { desc { "looking up late bound vars" } } @@ -1739,7 +1736,7 @@ rustc_queries! { separate_provide_extern arena_cache } - query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> { + query stability_implications(_: CrateNum) -> &'tcx UnordMap<Symbol, Symbol> { arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } separate_provide_extern @@ -1791,7 +1788,7 @@ rustc_queries! { } /// Collects the "trimmed", shortest accessible paths to all items for diagnostics. /// See the [provider docs](`rustc_middle::ty::print::trimmed_def_paths`) for more info. - query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> { + query trimmed_def_paths(_: ()) -> &'tcx DefIdMap<Symbol> { arena_cache desc { "calculating trimmed def paths" } } @@ -2082,7 +2079,7 @@ rustc_queries! { desc { "computing autoderef types for `{}`", goal.value.value } } - query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> { + query supported_target_features(_: CrateNum) -> &'tcx UnordMap<String, Option<Symbol>> { arena_cache eval_always desc { "looking up supported target features" } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 0577d22d850..31db4ba62fb 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; use rustc_data_structures::unhash::UnhashMap; -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::{Idx, IndexVec}; @@ -22,7 +22,8 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::SourceMap; use rustc_span::{ - BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, StableSourceFileId, + BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, + StableSourceFileId, }; use rustc_span::{CachingSourceMapView, Symbol}; use std::collections::hash_map::Entry; @@ -582,10 +583,10 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> { } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let syntax_contexts = decoder.syntax_contexts; - rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| { +impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { + fn decode_syntax_context(&mut self) -> SyntaxContext { + let syntax_contexts = self.syntax_contexts; + rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| { // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. // We look up the position of the associated `SyntaxData` and decode it. let pos = syntax_contexts.get(&id).unwrap(); @@ -595,11 +596,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { }) }) } -} -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let hash = ExpnHash::decode(decoder); + fn decode_expn_id(&mut self) -> ExpnId { + let hash = ExpnHash::decode(self); if hash.is_root() { return ExpnId::root(); } @@ -608,23 +607,23 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { return expn_id; } - let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); + let krate = self.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id()); let expn_id = if krate == LOCAL_CRATE { // We look up the position of the associated `ExpnData` and decode it. - let pos = decoder + let pos = self .expn_data .get(&hash) - .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data)); + .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, self.expn_data)); - let data: ExpnData = decoder - .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); + let data: ExpnData = + self.with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA)); let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash); #[cfg(debug_assertions)] { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - let local_hash = decoder.tcx.with_stable_hashing_context(|mut hcx| { + let local_hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); hasher.finish() @@ -634,9 +633,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { expn_id } else { - let index_guess = decoder.foreign_expn_data[&hash]; - decoder.tcx.cstore_untracked().expn_hash_to_expn_id( - decoder.tcx.sess, + let index_guess = self.foreign_expn_data[&hash]; + self.tcx.cstore_untracked().expn_hash_to_expn_id( + self.tcx.sess, krate, index_guess, hash, @@ -646,21 +645,19 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { debug_assert_eq!(expn_id.krate, krate); expn_id } -} -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { - fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self { - let ctxt = SyntaxContext::decode(decoder); - let parent = Option::<LocalDefId>::decode(decoder); - let tag: u8 = Decodable::decode(decoder); + fn decode_span(&mut self) -> Span { + let ctxt = SyntaxContext::decode(self); + let parent = Option::<LocalDefId>::decode(self); + let tag: u8 = Decodable::decode(self); if tag == TAG_PARTIAL_SPAN { return Span::new(BytePos(0), BytePos(0), ctxt, parent); } else if tag == TAG_RELATIVE_SPAN { - let dlo = u32::decode(decoder); - let dto = u32::decode(decoder); + let dlo = u32::decode(self); + let dto = u32::decode(self); - let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked(); + let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); let span = Span::new( enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto), @@ -673,87 +670,81 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { debug_assert_eq!(tag, TAG_FULL_SPAN); } - let file_lo_index = SourceFileIndex::decode(decoder); - let line_lo = usize::decode(decoder); - let col_lo = RelativeBytePos::decode(decoder); - let len = BytePos::decode(decoder); + let file_lo_index = SourceFileIndex::decode(self); + let line_lo = usize::decode(self); + let col_lo = RelativeBytePos::decode(self); + let len = BytePos::decode(self); - let file_lo = decoder.file_index_to_file(file_lo_index); + let file_lo = self.file_index_to_file(file_lo_index); let lo = file_lo.lines()[line_lo - 1] + col_lo; let lo = file_lo.absolute_position(lo); let hi = lo + len; Span::new(lo, hi, ctxt, parent) } -} -// copy&paste impl from rustc_metadata -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol { + // copy&paste impl from rustc_metadata #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - let tag = d.read_u8(); + fn decode_symbol(&mut self) -> Symbol { + let tag = self.read_u8(); match tag { SYMBOL_STR => { - let s = d.read_str(); + let s = self.read_str(); Symbol::intern(s) } SYMBOL_OFFSET => { // read str offset - let pos = d.read_usize(); + let pos = self.read_usize(); // move to str offset and read - d.opaque.with_position(pos, |d| { + self.opaque.with_position(pos, |d| { let s = d.read_str(); Symbol::intern(s) }) } SYMBOL_PREINTERNED => { - let symbol_index = d.read_u32(); + let symbol_index = self.read_u32(); Symbol::new_from_decoded(symbol_index) } _ => unreachable!(), } } -} -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - let stable_id = StableCrateId::decode(d); - let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id); + fn decode_crate_num(&mut self) -> CrateNum { + let stable_id = StableCrateId::decode(self); + let cnum = self.tcx.stable_crate_id_to_crate_num(stable_id); cnum } -} -// This impl makes sure that we get a runtime error when we try decode a -// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic -// because we would not know how to transform the `DefIndex` to the current -// context. -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex { - fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex { + // This impl makes sure that we get a runtime error when we try decode a + // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic + // because we would not know how to transform the `DefIndex` to the current + // context. + fn decode_def_index(&mut self) -> DefIndex { panic!("trying to decode `DefIndex` outside the context of a `DefId`") } -} -// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two -// compilation sessions. We use the `DefPathHash`, which is stable across -// sessions, to map the old `DefId` to the new one. -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two + // compilation sessions. We use the `DefPathHash`, which is stable across + // sessions, to map the old `DefId` to the new one. + fn decode_def_id(&mut self) -> DefId { // Load the `DefPathHash` which is was we encoded the `DefId` as. - let def_path_hash = DefPathHash::decode(d); + let def_path_hash = DefPathHash::decode(self); // Using the `DefPathHash`, we can lookup the new `DefId`. // Subtle: We only encode a `DefId` as part of a query result. // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { + self.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { panic!("Failed to convert DefPathHash {def_path_hash:?}") }) } + + fn decode_attr_id(&mut self) -> rustc_span::AttrId { + panic!("cannot decode `AttrId` with `CacheDecoder`"); + } } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> { @@ -764,7 +755,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> } impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> - for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>> + for &'tcx UnordMap<DefId, ty::EarlyBinder<Ty<'tcx>>> { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { @@ -859,87 +850,93 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for SyntaxContext { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s); +impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { + rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_context, self); } -} -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for ExpnId { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.hygiene_context.schedule_expn_data_for_encoding(*self); - self.expn_hash().encode(s); + fn encode_expn_id(&mut self, expn_id: ExpnId) { + self.hygiene_context.schedule_expn_data_for_encoding(expn_id); + expn_id.expn_hash().encode(self); } -} -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - let span_data = self.data_untracked(); - span_data.ctxt.encode(s); - span_data.parent.encode(s); + fn encode_span(&mut self, span: Span) { + let span_data = span.data_untracked(); + span_data.ctxt.encode(self); + span_data.parent.encode(self); if span_data.is_dummy() { - return TAG_PARTIAL_SPAN.encode(s); + return TAG_PARTIAL_SPAN.encode(self); } if let Some(parent) = span_data.parent { - let enclosing = s.tcx.source_span_untracked(parent).data_untracked(); + let enclosing = self.tcx.source_span_untracked(parent).data_untracked(); if enclosing.contains(span_data) { - TAG_RELATIVE_SPAN.encode(s); - (span_data.lo - enclosing.lo).to_u32().encode(s); - (span_data.hi - enclosing.lo).to_u32().encode(s); + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo - enclosing.lo).to_u32().encode(self); + (span_data.hi - enclosing.lo).to_u32().encode(self); return; } } - let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); + let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo); let partial_span = match &pos { Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), None => true, }; if partial_span { - return TAG_PARTIAL_SPAN.encode(s); + return TAG_PARTIAL_SPAN.encode(self); } let (file_lo, line_lo, col_lo) = pos.unwrap(); let len = span_data.hi - span_data.lo; - let source_file_index = s.source_file_index(file_lo); + let source_file_index = self.source_file_index(file_lo); - TAG_FULL_SPAN.encode(s); - source_file_index.encode(s); - line_lo.encode(s); - col_lo.encode(s); - len.encode(s); + TAG_FULL_SPAN.encode(self); + source_file_index.encode(self); + line_lo.encode(self); + col_lo.encode(self); + len.encode(self); } -} -// copy&paste impl from rustc_metadata -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Symbol { - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { + // copy&paste impl from rustc_metadata + fn encode_symbol(&mut self, symbol: Symbol) { // if symbol preinterned, emit tag and symbol index - if self.is_preinterned() { - s.encoder.emit_u8(SYMBOL_PREINTERNED); - s.encoder.emit_u32(self.as_u32()); + if symbol.is_preinterned() { + self.encoder.emit_u8(SYMBOL_PREINTERNED); + self.encoder.emit_u32(symbol.as_u32()); } else { // otherwise write it as string or as offset to it - match s.symbol_table.entry(*self) { + match self.symbol_table.entry(symbol) { Entry::Vacant(o) => { - s.encoder.emit_u8(SYMBOL_STR); - let pos = s.encoder.position(); + self.encoder.emit_u8(SYMBOL_STR); + let pos = self.encoder.position(); o.insert(pos); - s.emit_str(self.as_str()); + self.emit_str(symbol.as_str()); } Entry::Occupied(o) => { let x = *o.get(); - s.emit_u8(SYMBOL_OFFSET); - s.emit_usize(x); + self.emit_u8(SYMBOL_OFFSET); + self.emit_usize(x); } } } } + + fn encode_crate_num(&mut self, crate_num: CrateNum) { + self.tcx.stable_crate_id(crate_num).encode(self); + } + + fn encode_def_id(&mut self, def_id: DefId) { + self.tcx.def_path_hash(def_id).encode(self); + } + + fn encode_def_index(&mut self, _def_index: DefIndex) { + bug!("encoding `DefIndex` without context"); + } } impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { @@ -966,26 +963,6 @@ impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for CrateNum { - #[inline] - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.tcx.stable_crate_id(*self).encode(s); - } -} - -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefId { - #[inline] - fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) { - s.tcx.def_path_hash(*self).encode(s); - } -} - -impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefIndex { - fn encode(&self, _: &mut CacheEncoder<'a, 'tcx>) { - bug!("encoding `DefIndex` without context"); - } -} - macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { #[inline] diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index d2ff1e3c094..a41d4f1ad58 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, pub hash_result: HashResult<C::Value>, pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value, + fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value, pub format_value: fn(&C::Value) -> String, } @@ -551,7 +551,7 @@ macro_rules! define_feedable { // We have an inconsistency. This can happen if one of the two // results is tainted by errors. In this case, delay a bug to // ensure compilation is doomed, and keep the `old` value. - tcx.dcx().span_delayed_bug(DUMMY_SP, format!( + tcx.dcx().delayed_bug(format!( "Trying to feed an already recorded value for query {} key={key:?}:\n\ old value: {old:?}\nnew value: {value:?}", stringify!($name), diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b6759d35210..b4b8387c262 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -86,8 +86,6 @@ macro_rules! thir_with_elements { } } -pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0); - thir_with_elements! { body_type: BodyTy<'tcx>, @@ -519,20 +517,13 @@ pub struct FruInfo<'tcx> { #[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { pub pattern: Box<Pat<'tcx>>, - pub guard: Option<Guard<'tcx>>, + pub guard: Option<ExprId>, pub body: ExprId, pub lint_level: LintLevel, pub scope: region::Scope, pub span: Span, } -/// A `match` guard. -#[derive(Clone, Debug, HashStable)] -pub enum Guard<'tcx> { - If(ExprId), - IfLet(Box<Pat<'tcx>>, ExprId), -} - #[derive(Copy, Clone, Debug, HashStable)] pub enum LogicalOp { /// The `&&` operator. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index ade3ea289cc..4847a7bea91 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,5 +1,5 @@ use super::{ - AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, Guard, InlineAsmExpr, InlineAsmOperand, Pat, + AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; @@ -213,13 +213,8 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, arm: &'thir Arm<'tcx>, ) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} + if let Some(expr) = arm.guard { + visitor.visit_expr(&visitor.thir()[expr]) } visitor.visit_pat(&arm.pattern); visitor.visit_expr(&visitor.thir()[arm.body]); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 09b0a0dfbf3..af601a0d702 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -289,7 +289,7 @@ pub enum ObligationCauseCode<'tcx> { /// Type of each variable must be `Sized`. VariableType(hir::HirId), /// Argument type must be `Sized`. - SizedArgumentType(Option<Span>), + SizedArgumentType(Option<hir::HirId>), /// Return type must be `Sized`. SizedReturnType, /// Yield type must be `Sized`. diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 2ac3cddfa15..dd41cb5a61f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -293,12 +293,16 @@ impl<'tcx> InstanceDef<'tcx> { fn fmt_instance( f: &mut fmt::Formatter<'_>, instance: &Instance<'_>, - type_length: rustc_session::Limit, + type_length: Option<rustc_session::Limit>, ) -> fmt::Result { ty::tls::with(|tcx| { let args = tcx.lift(instance.args).expect("could not lift for printing"); - let mut cx = FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length); + let mut cx = if let Some(type_length) = type_length { + FmtPrinter::new_with_limit(tcx, Namespace::ValueNS, type_length) + } else { + FmtPrinter::new(tcx, Namespace::ValueNS) + }; cx.print_def_path(instance.def_id(), args)?; let s = cx.into_buffer(); f.write_str(&s) @@ -324,13 +328,13 @@ pub struct ShortInstance<'a, 'tcx>(pub &'a Instance<'tcx>, pub usize); impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_instance(f, self.0, rustc_session::Limit(self.1)) + fmt_instance(f, self.0, Some(rustc_session::Limit(self.1))) } } impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| fmt_instance(f, self, tcx.type_length_limit())) + fmt_instance(f, self, None) } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 5cc0ce87c9b..25473f52c03 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -284,7 +284,7 @@ impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { type TargetDataLayoutRef = &'tcx TargetDataLayout; fn delayed_bug(&self, txt: String) { - self.tcx.dcx().span_delayed_bug(DUMMY_SP, txt); + self.tcx.dcx().delayed_bug(txt); } fn current_data_layout(&self) -> Self::TargetDataLayoutRef { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 757d3337afc..9e8d7c2ef3e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,6 +38,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; @@ -50,7 +51,7 @@ use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{ExpnId, ExpnKind, Span}; +use rustc_span::{hygiene, ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -655,7 +656,7 @@ pub struct CratePredicatesMap<'tcx> { /// For each struct with outlive bounds, maps to a vector of the /// predicate of its outlive bounds. If an item has no outlives /// bounds, it will have no entry. - pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>, + pub predicates: DefIdMap<&'tcx [(Clause<'tcx>, Span)]>, } impl<'tcx> Clause<'tcx> { @@ -2517,21 +2518,21 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } - /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion - /// site. Only applies when `Span` is the result of macro expansion. + /// Returns corrected span if the debuginfo for `span` should be collapsed to the outermost + /// expansion site (with collapse_debuginfo attribute if the corresponding feature enabled). + /// Only applies when `Span` is the result of macro expansion. /// /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default - /// and only when a macro definition is annotated with `#[collapse_debuginfo]`. + /// and only when a (some enclosing) macro definition is annotated with `#[collapse_debuginfo]`. /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. /// /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. - pub fn should_collapse_debuginfo(self, span: Span) -> bool { - !self.sess.opts.unstable_opts.debug_macros - && if self.features().collapse_debuginfo { - span.in_macro_expansion_with_collapse_debuginfo() - } else { - span.from_expansion() - } + pub fn collapsed_debuginfo(self, span: Span, upto: Span) -> Span { + if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() { + return span; + } + let collapse_debuginfo_enabled = self.features().collapse_debuginfo; + hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled) } #[inline] @@ -2658,7 +2659,7 @@ pub fn provide(providers: &mut Providers) { #[derive(Clone, Debug, Default, HashStable)] pub struct CrateInherentImpls { pub inherent_impls: LocalDefIdMap<Vec<DefId>>, - pub incoherent_impls: FxHashMap<SimplifiedType, Vec<LocalDefId>>, + pub incoherent_impls: UnordMap<SimplifiedType, Vec<LocalDefId>>, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)] diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index fc4d4c9a3d2..5ca88ec3102 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -132,7 +132,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { .tcx .dcx() .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( + .with_span_label( self.span, format!( "lifetime `{r}` is part of concrete type but not used in \ diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index a63a4eff5e1..47f9d9e61ad 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -1,6 +1,7 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::DefIndex; use rustc_index::{Idx, IndexVec}; +use std::hash::Hash; use crate::ty; @@ -24,8 +25,8 @@ impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVe type Value<'tcx> = IndexVec<I, T::Value<'tcx>>; } -impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for FxHashMap<I, T> { - type Value<'tcx> = FxHashMap<I, T::Value<'tcx>>; +impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> { + type Value<'tcx> = UnordMap<I, T::Value<'tcx>>; } impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ebbd02e01bf..a10bdc6012c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -12,7 +12,7 @@ use rustc_apfloat::Float; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathDataName}; use rustc_hir::LangItem; use rustc_session::config::TrimmedDefPaths; @@ -912,7 +912,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); - let mut is_sized = false; + let mut has_sized_bound = false; + let mut has_negative_sized_bound = false; let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { @@ -922,13 +923,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print + Sized, but rather + ?Sized if absent. + // Don't print `+ Sized`, but rather `+ ?Sized` if absent. if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { - is_sized = true; - continue; + match pred.polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => { + has_sized_bound = true; + continue; + } + ty::ImplPolarity::Negative => has_negative_sized_bound = true, + } } - self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); + self.insert_trait_and_projection( + trait_ref, + pred.polarity, + None, + &mut traits, + &mut fn_traits, + ); } ty::ClauseKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); @@ -939,6 +951,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.insert_trait_and_projection( trait_ref, + ty::ImplPolarity::Positive, Some(proj_ty), &mut traits, &mut fn_traits, @@ -955,7 +968,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait - let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized; + let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; for (fn_once_trait_ref, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; @@ -1002,18 +1015,21 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // trait_refs we collected in the OpaqueFnEntry as normal trait refs. _ => { if entry.has_fn_once { - traits.entry(fn_once_trait_ref).or_default().extend( - // Group the return ty with its def id, if we had one. - entry - .return_ty - .map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)), - ); + traits + .entry((fn_once_trait_ref, ty::ImplPolarity::Positive)) + .or_default() + .extend( + // Group the return ty with its def id, if we had one. + entry.return_ty.map(|ty| { + (tcx.require_lang_item(LangItem::FnOnce, None), ty) + }), + ); } if let Some(trait_ref) = entry.fn_mut_trait_ref { - traits.entry(trait_ref).or_default(); + traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default(); } if let Some(trait_ref) = entry.fn_trait_ref { - traits.entry(trait_ref).or_default(); + traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default(); } } } @@ -1023,11 +1039,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Print the rest of the trait types (that aren't Fn* family of traits) - for (trait_ref, assoc_items) in traits { + for ((trait_ref, polarity), assoc_items) in traits { write!(self, "{}", if first { "" } else { " + " })?; self.wrap_binder(&trait_ref, |trait_ref, cx| { define_scoped_cx!(cx); + + if polarity == ty::ImplPolarity::Negative { + p!("!"); + } p!(print(trait_ref.print_only_trait_name())); let generics = tcx.generics_of(trait_ref.def_id); @@ -1094,9 +1114,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { })?; } - if !is_sized { - write!(self, "{}?Sized", if first { "" } else { " + " })?; - } else if first { + let add_sized = has_sized_bound && (first || has_negative_sized_bound); + let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound; + if add_sized || add_maybe_sized { + if !first { + write!(self, " + ")?; + } + if add_maybe_sized { + write!(self, "?")?; + } write!(self, "Sized")?; } @@ -1128,9 +1154,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn insert_trait_and_projection( &mut self, trait_ref: ty::PolyTraitRef<'tcx>, + polarity: ty::ImplPolarity, proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>, traits: &mut FxIndexMap< - ty::PolyTraitRef<'tcx>, + (ty::PolyTraitRef<'tcx>, ty::ImplPolarity), FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>, >, fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>, @@ -1139,7 +1166,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce // super-trait ref and record it there. - if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() { + // We skip negative Fn* bounds since they can't use parenthetical notation anyway. + if polarity == ty::ImplPolarity::Positive + && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() + { // If we have a FnOnce, then insert it into if trait_def_id == fn_once_trait { let entry = fn_traits.entry(trait_ref).or_default(); @@ -1167,7 +1197,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Otherwise, just group our traits and projection types. - traits.entry(trait_ref).or_default().extend(proj_ty); + traits.entry((trait_ref, polarity)).or_default().extend(proj_ty); } fn pretty_print_inherent_projection( @@ -3049,8 +3079,8 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N /// /// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths!`]. // this is pub to be able to intra-doc-link it -pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> { - let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default(); +pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> { + let mut map: DefIdMap<Symbol> = Default::default(); if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths { // Trimming paths is expensive and not optimized, since we expect it to only be used for error reporting. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 38bf39bff90..8cf5fc8013f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> { /// Whether this alias type is an opaque. pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool { - matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque)) + matches!(self.opt_kind(tcx), Some(ty::Opaque)) } /// FIXME: rename `AliasTy` to `AliasTerm` and always handle @@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> { // Extern types have metadata = (). | ty::Foreign(..) // `dyn*` has no metadata - | ty::Dynamic(_, _, DynKind::DynStar) + | ty::Dynamic(_, _, ty::DynStar) // If returned by `struct_tail_without_normalization` this is a unit struct // without any fields, or not a struct, and therefore is Sized. | ty::Adt(..) @@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> { | ty::Tuple(..) => (tcx.types.unit, false), ty::Str | ty::Slice(_) => (tcx.types.usize, false), - ty::Dynamic(_, _, DynKind::Dyn) => { + ty::Dynamic(_, _, ty::Dyn) => { let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false) }, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 58699c934b6..ad41a674dd8 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -527,7 +527,7 @@ impl<'a, V> LocalTableInContext<'a, V> { } pub fn items_in_stable_order(&self) -> Vec<(ItemLocalId, &'a V)> { - self.data.to_sorted_stable_ord() + self.data.items().map(|(&k, v)| (k, v)).into_sorted_stable_ord_by_key(|(k, _)| k) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ad2442a7963..372f11a5acc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,7 +1,7 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::query::Providers; +use crate::query::{IntoQueryParam, Providers}; use crate::ty::layout::IntegerExt; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -369,7 +369,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some((old_item_id, _)) = dtor_candidate { self.dcx() .struct_span_err(self.def_span(item_id), "multiple drop impls found") - .span_note(self.def_span(old_item_id), "other impl here") + .with_span_note(self.def_span(old_item_id), "other impl here") .delay_as_bug(); } @@ -702,6 +702,7 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, args: GenericArgsRef<'tcx>, + inspect_coroutine_fields: InspectCoroutineFields, ) -> Result<Ty<'tcx>, Ty<'tcx>> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), @@ -712,6 +713,7 @@ impl<'tcx> TyCtxt<'tcx> { check_recursion: true, expand_coroutines: true, tcx: self, + inspect_coroutine_fields, }; let expanded_type = visitor.expand_opaque_ty(def_id, args).unwrap(); @@ -729,16 +731,43 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { - "async closure" - } - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { - "async gen closure" - } + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + ) => "async fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) => "async block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + ) => "async closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + ) => "async gen fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + ) => "async gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + ) => "async gen closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + ) => "gen fn", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + ) => "gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + ) => "gen closure", hir::CoroutineKind::Coroutine(_) => "coroutine", - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { - "gen closure" - } } } _ => def_kind.descr(def_id), @@ -786,6 +815,13 @@ impl<'tcx> TyCtxt<'tcx> { || self.extern_crate(key.as_def_id()).is_some_and(|e| e.is_direct()) } + /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`, + /// because the item must also be "maybe const", and the crate where the item is + /// defined must also have the effects feature enabled. + pub fn has_host_param(self, def_id: impl IntoQueryParam<DefId>) -> bool { + self.generics_of(def_id).host_effect_index.is_some() + } + pub fn expected_host_effect_param_for_body(self, def_id: impl Into<DefId>) -> ty::Const<'tcx> { let def_id = def_id.into(); // FIXME(effects): This is suspicious and should probably not be done, @@ -858,6 +894,13 @@ struct OpaqueTypeExpander<'tcx> { /// recursion, and 'false' otherwise to avoid unnecessary work. check_recursion: bool, tcx: TyCtxt<'tcx>, + inspect_coroutine_fields: InspectCoroutineFields, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum InspectCoroutineFields { + No, + Yes, } impl<'tcx> OpaqueTypeExpander<'tcx> { @@ -899,9 +942,11 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let expanded_ty = match self.expanded_cache.get(&(def_id, args)) { Some(expanded_ty) => *expanded_ty, None => { - for bty in self.tcx.coroutine_hidden_types(def_id) { - let hidden_ty = bty.instantiate(self.tcx, args); - self.fold_ty(hidden_ty); + if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) { + for bty in self.tcx.coroutine_hidden_types(def_id) { + let hidden_ty = bty.instantiate(self.tcx, args); + self.fold_ty(hidden_ty); + } } let expanded_ty = Ty::new_coroutine_witness(self.tcx, def_id, args); self.expanded_cache.insert((def_id, args), expanded_ty); @@ -1479,11 +1524,12 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( check_recursion: false, expand_coroutines: false, tcx, + inspect_coroutine_fields: InspectCoroutineFields::No, }; val.fold_with(&mut visitor) } -/// Determines whether an item is annotated with `doc(hidden)`. +/// Determines whether an item is directly annotated with `doc(hidden)`. fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.get_attrs(def_id, sym::doc) .filter_map(|attr| attr.meta_item_list()) diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index b4e45ad5685..6a03bf243eb 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,20 +1,22 @@ use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::Representability; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_query_system::query::QueryInfo; +use rustc_query_system::query::{report_cycle, CycleError}; use rustc_query_system::Value; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; +use std::collections::VecDeque; use std::fmt::Write; +use std::ops::ControlFlow; impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) } @@ -22,13 +24,13 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> { } impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } } impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -40,10 +42,14 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> { } impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { let err = Ty::new_error(tcx, guar); - let arity = if let Some(frame) = stack.get(0) + let arity = if let Some(frame) = cycle_error.cycle.get(0) && frame.query.dep_kind == dep_kinds::fn_sig && let Some(def_id) = frame.query.def_id && let Some(node) = tcx.hir().get_if_local(def_id) @@ -70,10 +76,14 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> { } impl<'tcx> Value<TyCtxt<'tcx>> for Representability { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + _guar: ErrorGuaranteed, + ) -> Self { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); - for info in cycle { + for info in &cycle_error.cycle { if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() @@ -87,9 +97,9 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability { item_and_field_ids.push((item_id.expect_local(), field_id)); } } - for info in cycle { + for info in &cycle_error.cycle { if info.query.dep_kind == dep_kinds::representability_adt_ty - && let Some(def_id) = info.query.ty_adt_id + && let Some(def_id) = info.query.ty_def_id && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) { @@ -102,19 +112,128 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability { } impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar)) } } impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { - fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { - ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar)) + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + guar: ErrorGuaranteed, + ) -> Self { + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar)) } } +// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`. +fn search_for_cycle_permutation<Q, T>( + cycle: &[Q], + try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>, + otherwise: impl FnOnce() -> T, +) -> T { + let mut cycle: VecDeque<_> = cycle.iter().collect(); + for _ in 0..cycle.len() { + match try_cycle(&mut cycle) { + ControlFlow::Continue(_) => { + cycle.rotate_left(1); + } + ControlFlow::Break(t) => return t, + } + } + + otherwise() +} + impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { + fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + _guar: ErrorGuaranteed, + ) -> Self { + let diag = search_for_cycle_permutation( + &cycle_error.cycle, + |cycle| { + if cycle[0].query.dep_kind == dep_kinds::layout_of + && let Some(def_id) = cycle[0].query.ty_def_id + && let Some(def_id) = def_id.as_local() + && let def_kind = tcx.def_kind(def_id) + && matches!(def_kind, DefKind::Closure) + && let Some(coroutine_kind) = tcx.coroutine_kind(def_id) + { + // FIXME: `def_span` for an fn-like coroutine will point to the fn's body + // due to interactions between the desugaring into a closure expr and the + // def_span code. I'm not motivated to fix it, because I tried and it was + // not working, so just hack around it by grabbing the parent fn's span. + let span = if coroutine_kind.is_fn_like() { + tcx.def_span(tcx.local_parent(def_id)) + } else { + tcx.def_span(def_id) + }; + let mut diag = struct_span_code_err!( + tcx.sess.dcx(), + span, + E0733, + "recursion in {} {} requires boxing", + tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), + tcx.def_kind_descr(def_kind, def_id.to_def_id()), + ); + for (i, frame) in cycle.iter().enumerate() { + if frame.query.dep_kind != dep_kinds::layout_of { + continue; + } + let Some(frame_def_id) = frame.query.ty_def_id else { + continue; + }; + let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else { + continue; + }; + let frame_span = + frame.query.default_span(cycle[(i + 1) % cycle.len()].span); + if frame_span.is_dummy() { + continue; + } + if i == 0 { + diag.span_label(frame_span, "recursive call here"); + } else { + let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() { + tcx.def_span(tcx.parent(frame_def_id)) + } else { + tcx.def_span(frame_def_id) + }; + let mut multispan = MultiSpan::from_span(coroutine_span); + multispan + .push_span_label(frame_span, "...leading to this recursive call"); + diag.span_note( + multispan, + format!("which leads to this {}", tcx.def_descr(frame_def_id)), + ); + } + } + // FIXME: We could report a structured suggestion if we had + // enough info here... Maybe we can use a hacky HIR walker. + if matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + ) { + diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); + } + + ControlFlow::Break(diag) + } else { + ControlFlow::Continue(()) + } + }, + || report_cycle(tcx.sess, cycle_error), + ); + + let guar = diag.emit(); + // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). @@ -190,7 +309,7 @@ pub fn recursive_type_error( } s }; - let mut err = struct_span_err!( + struct_span_code_err!( tcx.dcx(), err_span, E0072, @@ -198,13 +317,13 @@ pub fn recursive_type_error( pluralize!(cycle_len), items_list, pluralize!("has", cycle_len), - ); - err.multipart_suggestion( + ) + .with_multipart_suggestion( "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle", suggestion, Applicability::HasPlaceholders, - ); - err.emit(); + ) + .emit(); } fn find_item_ty_spans( diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 4ce7f831c87..e3dea2212df 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -61,7 +61,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { @call(mir_drop, args) => { Ok(TerminatorKind::Drop { place: self.parse_place(args[0])?, - target: self.parse_block(args[1])?, + target: self.parse_return_to(args[1])?, unwind: self.parse_unwind_action(args[2])?, replace: false, }) @@ -104,6 +104,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ) } + fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> { + parse_by_kind!(self, expr_id, _, "return block", + @call(mir_return_to, args) => { + self.parse_block(args[0]) + }, + ) + } + fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> { let Some((otherwise, rest)) = arms.split_last() else { return Err(ParseError { @@ -146,7 +154,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ExprKind::Assign { lhs, rhs } => (*lhs, *rhs), ); let destination = self.parse_place(destination)?; - let target = self.parse_block(args[1])?; + let target = self.parse_return_to(args[1])?; let unwind = self.parse_unwind_action(args[2])?; parse_by_kind!(self, call, _, "function call", diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index e77e82d9954..5721957037e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -9,7 +9,6 @@ use rustc_middle::thir::*; use rustc_middle::ty::{ self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex, }; -use rustc_span::DUMMY_SP; use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -111,15 +110,15 @@ fn lit_to_mir_constant<'tcx>( let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = tcx - .layout_of(param_ty) - .map_err(|_| { - LitToConstError::Reported(tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("couldn't compute width of literal: {:?}", lit_input.lit), - )) - })? - .size; + let width = + tcx.layout_of(param_ty) + .map_err(|_| { + LitToConstError::Reported(tcx.dcx().delayed_bug(format!( + "couldn't compute width of literal: {:?}", + lit_input.lit + ))) + })? + .size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); @@ -158,16 +157,16 @@ fn lit_to_mir_constant<'tcx>( } (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg) .ok_or_else(|| { - LitToConstError::Reported(tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("couldn't parse float literal: {:?}", lit_input.lit), - )) + LitToConstError::Reported( + tcx.dcx() + .delayed_bug(format!("couldn't parse float literal: {:?}", lit_input.lit)), + ) })?, (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), (ast::LitKind::Err, _) => { return Err(LitToConstError::Reported( - tcx.dcx().span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), + tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), )); } _ => return Err(LitToConstError::TypeError), diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index f50945a4de0..060a3b521a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -82,7 +82,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cond, Some(condition_scope), condition_scope, - source_info + source_info, + true, )); this.expr_into_dest(destination, then_blk, then) @@ -173,6 +174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(condition_scope), condition_scope, source_info, + true, ) }); let (short_circuit, continuation, constant) = match op { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7f29e3308f4..906b3205ca7 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -33,6 +33,12 @@ use std::borrow::Borrow; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Lowers a condition in a way that ensures that variables bound in any let + /// expressions are definitely initialized in the if body. + /// + /// If `declare_bindings` is false then variables created in `let` + /// expressions will not be declared. This is for if let guards on arms with + /// an or pattern, where the guard is lowered multiple times. pub(crate) fn then_else_break( &mut self, mut block: BasicBlock, @@ -40,6 +46,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override: Option<region::Scope>, break_scope: region::Scope, variable_source_info: SourceInfo, + declare_bindings: bool, ) -> BlockAnd<()> { let this = self; let expr = &this.thir[expr_id]; @@ -53,6 +60,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); let rhs_then_block = unpack!(this.then_else_break( @@ -61,6 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); rhs_then_block.unit() @@ -75,6 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, local_scope, variable_source_info, + true, ) }); let rhs_success_block = unpack!(this.then_else_break( @@ -83,6 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + true, )); this.cfg.goto(lhs_success_block, variable_source_info, rhs_success_block); rhs_success_block.unit() @@ -102,6 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, local_scope, variable_source_info, + true, ) }); this.break_for_else(success_block, break_scope, variable_source_info); @@ -116,6 +128,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, ) }) } @@ -125,6 +138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, ), ExprKind::Let { expr, ref pat } => this.lower_let_expr( block, @@ -133,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { break_scope, Some(variable_source_info.scope), variable_source_info.span, - true, + declare_bindings, ), _ => { let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope()); @@ -417,7 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, arm.span, &arm.pattern, - arm.guard.as_ref(), + arm.guard, opt_scrutinee_place, ); @@ -709,7 +723,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut visibility_scope: Option<SourceScope>, scope_span: Span, pattern: &Pat<'tcx>, - guard: Option<&Guard<'tcx>>, + guard: Option<ExprId>, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option<SourceScope> { self.visit_primary_bindings( @@ -737,13 +751,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); }, ); - if let Some(Guard::IfLet(guard_pat, _)) = guard { - // FIXME: pass a proper `opt_match_place` - self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None); + if let Some(guard_expr) = guard { + self.declare_guard_bindings(guard_expr, scope_span, visibility_scope); } visibility_scope } + /// Declare bindings in a guard. This has to be done when declaring bindings + /// for an arm to ensure that or patterns only have one version of each + /// variable. + pub(crate) fn declare_guard_bindings( + &mut self, + guard_expr: ExprId, + scope_span: Span, + visibility_scope: Option<SourceScope>, + ) { + match self.thir.exprs[guard_expr].kind { + ExprKind::Let { expr: _, pat: ref guard_pat } => { + // FIXME: pass a proper `opt_match_place` + self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None); + } + ExprKind::Scope { value, .. } => { + self.declare_guard_bindings(value, scope_span, visibility_scope); + } + ExprKind::Use { source } => { + self.declare_guard_bindings(source, scope_span, visibility_scope); + } + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + self.declare_guard_bindings(lhs, scope_span, visibility_scope); + self.declare_guard_bindings(rhs, scope_span, visibility_scope); + } + _ => {} + } + } + pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, @@ -2009,7 +2050,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // * So we eagerly create the reference for the arm and then take a // reference to that. if let Some((arm, match_scope)) = arm_match_scope - && let Some(guard) = &arm.guard + && let Some(guard) = arm.guard { let tcx = self.tcx; let bindings = parent_bindings @@ -2034,21 +2075,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut guard_span = rustc_span::DUMMY_SP; let (post_guard_block, otherwise_post_guard_block) = - self.in_if_then_scope(match_scope, guard_span, |this| match *guard { - Guard::If(e) => { - guard_span = this.thir[e].span; - this.then_else_break( - block, - e, - None, - match_scope, - this.source_info(arm.span), - ) - } - Guard::IfLet(ref pat, s) => { - guard_span = this.thir[s].span; - this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false) - } + self.in_if_then_scope(match_scope, guard_span, |this| { + guard_span = this.thir[guard].span; + this.then_else_break( + block, + guard, + None, + match_scope, + this.source_info(arm.span), + false, + ) }); let source_info = self.source_info(guard_span); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e0199fb8767..b8d08319422 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -9,7 +9,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{CoroutineKind, Node}; +use rustc_hir::Node; use rustc_index::bit_set::GrowableBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -177,7 +177,7 @@ struct Builder<'a, 'tcx> { check_overflow: bool, fn_span: Span, arg_count: usize, - coroutine_kind: Option<CoroutineKind>, + coroutine: Option<Box<CoroutineInfo<'tcx>>>, /// The current set of scopes, updated as we traverse; /// see the `scope` module for more details. @@ -458,7 +458,6 @@ fn construct_fn<'tcx>( ) -> Body<'tcx> { let span = tcx.def_span(fn_def); let fn_id = tcx.local_def_id_to_hir_id(fn_def); - let coroutine_kind = tcx.coroutine_kind(fn_def); // The representation of thir for `-Zunpretty=thir-tree` relies on // the entry expression being the last element of `thir.exprs`. @@ -488,17 +487,15 @@ fn construct_fn<'tcx>( let arguments = &thir.params; - let (yield_ty, return_ty) = if coroutine_kind.is_some() { - let coroutine_ty = arguments[thir::UPVAR_ENV_PARAM].ty; - let coroutine_sig = match coroutine_ty.kind() { - ty::Coroutine(_, gen_args, ..) => gen_args.as_coroutine().sig(), - _ => { - span_bug!(span, "coroutine w/o coroutine type: {:?}", coroutine_ty) - } - }; - (Some(coroutine_sig.yield_ty), coroutine_sig.return_ty) - } else { - (None, fn_sig.output()) + let return_ty = fn_sig.output(); + let coroutine = match tcx.type_of(fn_def).instantiate_identity().kind() { + ty::Coroutine(_, args) => Some(Box::new(CoroutineInfo::initial( + tcx.coroutine_kind(fn_def).unwrap(), + args.as_coroutine().yield_ty(), + args.as_coroutine().resume_ty(), + ))), + ty::Closure(..) | ty::FnDef(..) => None, + ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"), }; if let Some(custom_mir_attr) = @@ -529,7 +526,7 @@ fn construct_fn<'tcx>( safety, return_ty, return_ty_span, - coroutine_kind, + coroutine, ); let call_site_scope = @@ -562,9 +559,7 @@ fn construct_fn<'tcx>( } else { None }; - if yield_ty.is_some() { - body.coroutine.as_mut().unwrap().yield_ty = yield_ty; - } + body } @@ -629,9 +624,8 @@ fn construct_const<'a, 'tcx>( fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> { let span = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - let coroutine_kind = tcx.coroutine_kind(def_id); - let (inputs, output, yield_ty) = match tcx.def_kind(def_id) { + let (inputs, output, coroutine) = match tcx.def_kind(def_id) { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst @@ -644,31 +638,48 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - ); (sig.inputs().to_vec(), sig.output(), None) } - DefKind::Closure if coroutine_kind.is_some() => { - let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Coroutine(_, args) = coroutine_ty.kind() else { - bug!("expected type of coroutine-like closure to be a coroutine") - }; - let args = args.as_coroutine(); - let yield_ty = args.yield_ty(); - let return_ty = args.return_ty(); - (vec![coroutine_ty, args.resume_ty()], return_ty, Some(yield_ty)) - } DefKind::Closure => { let closure_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Closure(_, args) = closure_ty.kind() else { - bug!("expected type of closure to be a closure") - }; - let args = args.as_closure(); - let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); - let self_ty = match args.kind() { - ty::ClosureKind::Fn => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnMut => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty), - ty::ClosureKind::FnOnce => closure_ty, - }; - ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None) + match closure_ty.kind() { + ty::Closure(_, args) => { + let args = args.as_closure(); + let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); + let self_ty = match args.kind() { + ty::ClosureKind::Fn => { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnMut => { + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnOnce => closure_ty, + }; + ( + [self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), + sig.output(), + None, + ) + } + ty::Coroutine(_, args) => { + let args = args.as_coroutine(); + let resume_ty = args.resume_ty(); + let yield_ty = args.yield_ty(); + let return_ty = args.return_ty(); + ( + vec![closure_ty, args.resume_ty()], + return_ty, + Some(Box::new(CoroutineInfo::initial( + tcx.coroutine_kind(def_id).unwrap(), + yield_ty, + resume_ty, + ))), + ) + } + _ => { + span_bug!(span, "expected type of closure body to be a closure or coroutine"); + } + } } - dk => bug!("{:?} is not a body: {:?}", def_id, dk), + dk => span_bug!(span, "{:?} is not a body: {:?}", def_id, dk), }; let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; @@ -692,7 +703,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - let mut body = Body::new( + Body::new( MirSource::item(def_id.to_def_id()), cfg.basic_blocks, source_scopes, @@ -701,13 +712,9 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - inputs.len(), vec![], span, - coroutine_kind, + coroutine, Some(guar), - ); - - body.coroutine.as_mut().map(|gen| gen.yield_ty = yield_ty); - - body + ) } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -721,7 +728,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { safety: Safety, return_ty: Ty<'tcx>, return_span: Span, - coroutine_kind: Option<CoroutineKind>, + coroutine: Option<Box<CoroutineInfo<'tcx>>>, ) -> Builder<'a, 'tcx> { let tcx = infcx.tcx; let attrs = tcx.hir().attrs(hir_id); @@ -752,7 +759,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count, - coroutine_kind, + coroutine, scopes: scope::Scopes::new(), block_context: BlockContext::new(), source_scopes: IndexVec::new(), @@ -796,7 +803,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.arg_count, self.var_debug_info, self.fn_span, - self.coroutine_kind, + self.coroutine, None, ) } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 1a700ac7342..48b237f3ae6 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -706,7 +706,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If we are emitting a `drop` statement, we need to have the cached // diverge cleanup pads ready in case that drop panics. let needs_cleanup = self.scopes.scopes.last().is_some_and(|scope| scope.needs_cleanup()); - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX }; let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes"); @@ -960,7 +960,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // path, we only need to invalidate the cache for drops that happen on // the unwind or coroutine drop paths. This means that for // non-coroutines we don't need to invalidate caches for `DropKind::Storage`. - let invalidate_caches = needs_drop || self.coroutine_kind.is_some(); + let invalidate_caches = needs_drop || self.coroutine.is_some(); for scope in self.scopes.scopes.iter_mut().rev() { if invalidate_caches { scope.invalidate_cache(); @@ -1073,7 +1073,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return cached_drop; } - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); for scope in &mut self.scopes.scopes[uncached_scope..=target] { for drop in &scope.drops { if is_coroutine || drop.kind == DropKind::Value { @@ -1318,7 +1318,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { blocks[ROOT_NODE] = continue_block; drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks); - let is_coroutine = self.coroutine_kind.is_some(); + let is_coroutine = self.coroutine.is_some(); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { @@ -1355,7 +1355,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build the unwind and coroutine drop trees. pub(crate) fn build_drop_trees(&mut self) { - if self.coroutine_kind.is_some() { + if self.coroutine.is_some() { self.build_coroutine_drop_trees(); } else { Self::build_unwind_tree( diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 2e8b6c19ec7..b4a02fae454 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -14,7 +14,7 @@ use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{sym, Span}; use std::mem; use std::ops::Bound; @@ -144,11 +144,17 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { let hir_context = self.tcx.local_def_id_to_hir_id(def); let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe); let mut inner_visitor = UnsafetyVisitor { + tcx: self.tcx, thir: inner_thir, hir_context, safety_context, + body_target_features: self.body_target_features, + assignment_info: self.assignment_info, + in_union_destructure: false, + param_env: self.param_env, + inside_adt: false, warnings: self.warnings, - ..*self + suggest_unsafe_block: self.suggest_unsafe_block, }; inner_visitor.visit_expr(&inner_thir[expr]); // Unsafe blocks can be used in the inner body, make sure to take it into account @@ -886,14 +892,15 @@ impl UnsafeOpKind { } } -pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { - // THIR unsafeck is gated under `-Z thir-unsafeck` +pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { + // THIR unsafeck can be disabled with `-Z thir-unsafeck=off` if !tcx.sess.opts.unstable_opts.thir_unsafeck { return; } // Closures and inline consts are handled by their owner, if it has a body - if tcx.is_typeck_child(def.to_def_id()) { + // Also, don't safety check custom MIR + if tcx.is_typeck_child(def.to_def_id()) || tcx.has_attr(def, sym::custom_mir) { return; } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 8677cba6a7c..61ad99acf38 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -467,11 +467,11 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { level, fluent::mir_build_non_exhaustive_patterns_type_not_empty, ); - diag.set_span(self.span); + diag.span(self.span); diag.code(error_code!(E0004)); let peeled_ty = self.ty.peel_refs(); - diag.set_arg("ty", self.ty); - diag.set_arg("peeled_ty", peeled_ty); + diag.arg("ty", self.ty); + diag.arg("peeled_ty", peeled_ty); if let ty::Adt(def, _) = peeled_ty.kind() { let def_span = self @@ -855,7 +855,7 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - diag.set_arg("ty", self.ty); + diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); for Variant { span } in self.variants { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a776e917de5..430c4ee3da7 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -31,7 +31,7 @@ pub fn provide(providers: &mut Providers) { providers.mir_built = build::mir_built; providers.closure_saved_names_of_captured_variables = build::closure_saved_names_of_captured_variables; - providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; + providers.check_unsafety = check_unsafety::check_unsafety; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::print::thir_tree; providers.thir_flat = thir::print::thir_flat; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 3a56b03948e..8d5e6cd4f41 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,7 +1,6 @@ use rustc_ast as ast; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt}; -use rustc_span::DUMMY_SP; use crate::build::parse_float_into_scalar; @@ -13,15 +12,15 @@ pub(crate) fn lit_to_const<'tcx>( let trunc = |n| { let param_ty = ParamEnv::reveal_all().and(ty); - let width = tcx - .layout_of(param_ty) - .map_err(|_| { - LitToConstError::Reported(tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("couldn't compute width of literal: {:?}", lit_input.lit), - )) - })? - .size; + let width = + tcx.layout_of(param_ty) + .map_err(|_| { + LitToConstError::Reported(tcx.dcx().delayed_bug(format!( + "couldn't compute width of literal: {:?}", + lit_input.lit + ))) + })? + .size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); @@ -60,20 +59,21 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg) - .ok_or_else(|| { - LitToConstError::Reported(tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("couldn't parse float literal: {:?}", lit_input.lit), - )) - })? - .assert_int(); + let bits = + parse_float_into_scalar(*n, *fty, neg) + .ok_or_else(|| { + LitToConstError::Reported(tcx.dcx().delayed_bug(format!( + "couldn't parse float literal: {:?}", + lit_input.lit + ))) + })? + .assert_int(); ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), (ast::LitKind::Err, _) => { return Err(LitToConstError::Reported( - tcx.dcx().span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"), + tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), )); } _ => return Err(LitToConstError::TypeError), diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8ec70c58c46..78d72b30284 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -855,13 +855,8 @@ impl<'tcx> Cx<'tcx> { fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { let arm = Arm { - pattern: self.pattern_from_hir(arm.pat), - guard: arm.guard.as_ref().map(|g| match g { - hir::Guard::If(e) => Guard::If(self.mirror_expr(e)), - hir::Guard::IfLet(l) => { - Guard::IfLet(self.pattern_from_hir(l.pat), self.mirror_expr(l.init)) - } - }), + pattern: self.pattern_from_hir(&arm.pat), + guard: arm.guard.as_ref().map(|g| self.mirror_expr(g)), body: self.mirror_expr(arm.body), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, 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 0bcc2a315ff..f6c5e4a5cd6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -11,7 +11,9 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; @@ -55,7 +57,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err } fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> { - struct_span_err!(sess.dcx(), sp, E0004, "{}", &error_message) + struct_span_code_err!(sess.dcx(), sp, E0004, "{}", &error_message) } #[derive(Debug, Copy, Clone, PartialEq)] @@ -100,20 +102,10 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn visit_arm(&mut self, arm: &'p Arm<'tcx>) { self.with_lint_level(arm.lint_level, |this| { - match arm.guard { - Some(Guard::If(expr)) => { - this.with_let_source(LetSource::IfLetGuard, |this| { - this.visit_expr(&this.thir[expr]) - }); - } - Some(Guard::IfLet(ref pat, expr)) => { - this.with_let_source(LetSource::IfLetGuard, |this| { - this.check_let(pat, Some(expr), pat.span); - this.visit_pat(pat); - this.visit_expr(&this.thir[expr]); - }); - } - None => {} + if let Some(expr) = arm.guard { + this.with_let_source(LetSource::IfLetGuard, |this| { + this.visit_expr(&this.thir[expr]) + }); } this.visit_pat(&arm.pattern); this.visit_expr(&self.thir[arm.body]); @@ -440,7 +432,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { } let scrut_ty = scrut.ty; - let report = analyze_match(&cx, &tarms, scrut_ty); + let report = match analyze_match(&cx, &tarms, scrut_ty) { + Ok(report) => report, + Err(err) => { + self.error = Err(err); + return; + } + }; match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -554,7 +552,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let cx = self.new_cx(refutability, None, scrut, pat.span); let pat = self.lower_pattern(&cx, pat)?; let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }]; - let report = analyze_match(&cx, &arms, pat.ty()); + let report = analyze_match(&cx, &arms, pat.ty().inner())?; Ok((cx, report)) } @@ -972,7 +970,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( } } else if ty == cx.tcx.types.str_ { err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary"); - } else if cx.is_foreign_non_exhaustive_enum(ty) { + } else if cx.is_foreign_non_exhaustive_enum(cx.reveal_opaque_ty(ty)) { err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively")); } } @@ -1112,12 +1110,12 @@ fn collect_non_exhaustive_tys<'tcx>( non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>, ) { if matches!(pat.ctor(), Constructor::NonExhaustive) { - non_exhaustive_tys.insert(pat.ty()); + non_exhaustive_tys.insert(pat.ty().inner()); } if let Constructor::IntRange(range) = pat.ctor() { if cx.is_range_beyond_boundaries(range, pat.ty()) { // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. - non_exhaustive_tys.insert(pat.ty()); + non_exhaustive_tys.insert(pat.ty().inner()); } } pat.iter_fields() diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 28be3139905..267ea3aa3e1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -593,9 +593,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "pattern: ", depth_lvl + 1); self.print_pat(pattern, depth_lvl + 2); - if let Some(guard) = guard { + if let Some(guard) = *guard { print_indented!(self, "guard: ", depth_lvl + 1); - self.print_guard(guard, depth_lvl + 2); + self.print_expr(guard, depth_lvl + 2); } else { print_indented!(self, "guard: None", depth_lvl + 1); } @@ -764,27 +764,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "}", depth_lvl); } - fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { - print_indented!(self, "Guard {", depth_lvl); - - match guard { - Guard::If(expr_id) => { - print_indented!(self, "If (", depth_lvl + 1); - self.print_expr(*expr_id, depth_lvl + 2); - print_indented!(self, ")", depth_lvl + 1); - } - Guard::IfLet(pat, expr_id) => { - print_indented!(self, "IfLet (", depth_lvl + 1); - self.print_pat(pat, depth_lvl + 2); - print_indented!(self, ",", depth_lvl + 1); - self.print_expr(*expr_id, depth_lvl + 2); - print_indented!(self, ")", depth_lvl + 1); - } - } - - print_indented!(self, "}", depth_lvl); - } - fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { let ClosureExpr { closure_id, args, upvars, movability, fake_reads } = expr; diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d94d96c1115..582c2c0c6b6 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -131,7 +131,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _) => { let def_id = def_id.expect_local(); let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = - self.tcx.unsafety_check_result(def_id); + self.tcx.mir_unsafety_check_result(def_id); self.register_violations(violations, used_unsafe_blocks.items().copied()); } }, @@ -153,7 +153,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { if self.tcx.def_kind(def_id) == DefKind::InlineConst { let local_def_id = def_id.expect_local(); let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } = - self.tcx.unsafety_check_result(local_def_id); + self.tcx.mir_unsafety_check_result(local_def_id); self.register_violations(violations, used_unsafe_blocks.items().copied()); } } @@ -390,7 +390,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { unsafety_check_result, ..*providers }; + *providers = Providers { mir_unsafety_check_result, ..*providers }; } /// Context information for [`UnusedUnsafeVisitor`] traversal, @@ -490,7 +490,7 @@ fn check_unused_unsafe( unused_unsafes } -fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult { +fn mir_unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult { debug!("unsafety_violations({:?})", def); // N.B., this borrow is valid because all the consumers of @@ -538,7 +538,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id); + let UnsafetyCheckResult { violations, unused_unsafes, .. } = + tcx.mir_unsafety_check_result(def_id); // Only suggest wrapping the entire function body in an unsafe block once let mut suggest_unsafe_block = true; diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index 3884346076e..cb5b66b314d 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -51,7 +51,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 99eecb567f2..d0bbca08a40 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -670,6 +670,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { // This loop can get very hot for some bodies: it check each local in each bb. // To avoid this quadratic behaviour, we only clear the locals that were modified inside // the current block. + // The order in which we remove consts does not matter. + #[allow(rustc::potential_query_instability)] for local in written_only_inside_own_block_locals.drain() { debug_assert_eq!( self.ecx.machine.can_const_prop[local], diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index ce1a36cf670..379e96e263c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -942,6 +942,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body, saved_locals: saved_locals, local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + eligible_storage_live: BitSet::new_empty(body.local_decls.len()), }; requires_storage.visit_reachable_with(body, &mut visitor); @@ -978,6 +979,8 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> { // FIXME(tmandry): Consider using sparse bitsets here once we have good // benchmarks for coroutines. local_conflicts: BitMatrix<Local, Local>, + // We keep this bitset as a buffer to avoid reallocating memory. + eligible_storage_live: BitSet<Local>, } impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> @@ -1009,19 +1012,19 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> impl StorageConflictVisitor<'_, '_, '_> { fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) { // Ignore unreachable blocks. - if self.body.basic_blocks[loc.block].terminator().kind == TerminatorKind::Unreachable { + if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { return; } - let mut eligible_storage_live = flow_state.clone(); - eligible_storage_live.intersect(&**self.saved_locals); + self.eligible_storage_live.clone_from(flow_state); + self.eligible_storage_live.intersect(&**self.saved_locals); - for local in eligible_storage_live.iter() { - self.local_conflicts.union_row_with(&eligible_storage_live, local); + for local in self.eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&self.eligible_storage_live, local); } - if eligible_storage_live.count() > 1 { - trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); + if self.eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, self.eligible_storage_live); } } } @@ -1733,6 +1736,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } body.coroutine.as_mut().unwrap().yield_ty = None; + body.coroutine.as_mut().unwrap().resume_ty = None; body.coroutine.as_mut().unwrap().coroutine_layout = Some(layout); // Insert `drop(coroutine_struct)` which is used to drop upvars for coroutines in diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index aa7b6b02f74..dcd7014f4fc 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{Span, Symbol}; +use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -107,6 +107,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { ); let mappings = self.create_mappings(&coverage_spans, &coverage_counters); + if mappings.is_empty() { + // No spans could be converted into valid mappings, so skip this function. + debug!("no spans could be converted into valid mappings; skipping"); + return; + } + self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { @@ -148,9 +154,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // Flatten the spans into individual term/span pairs. .flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span))) // Convert each span to a code region, and create the final mapping. - .map(|(term, span)| { - let code_region = make_code_region(source_map, file_name, span, body_span); - Mapping { term, code_region } + .filter_map(|(term, span)| { + let code_region = make_code_region(source_map, file_name, span, body_span)?; + Some(Mapping { term, code_region }) }) .collect::<Vec<_>>() } @@ -252,13 +258,22 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb data.statements.insert(0, statement); } -/// Convert the Span into its file name, start line and column, and end line and column +/// Convert the Span into its file name, start line and column, and end line and column. +/// +/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by +/// the compiler, these column numbers are denoted in **bytes**, because that's what +/// LLVM's `llvm-cov` tool expects to see in coverage maps. +/// +/// Returns `None` if the conversion failed for some reason. This shouldn't happen, +/// but it's hard to rule out entirely (especially in the presence of complex macros +/// or other expansions), and if it does happen then skipping a span or function is +/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. fn make_code_region( source_map: &SourceMap, file_name: Symbol, span: Span, body_span: Span, -) -> CodeRegion { +) -> Option<CodeRegion> { debug!( "Called make_code_region(file_name={}, span={}, body_span={})", file_name, @@ -266,27 +281,62 @@ fn make_code_region( source_map.span_to_diagnostic_string(body_span) ); - let (file, mut start_line, mut start_col, mut end_line, mut end_col) = - source_map.span_to_location_info(span); - if span.hi() == span.lo() { - // Extend an empty span by one character so the region will be counted. - if span.hi() == body_span.hi() { - start_col = start_col.saturating_sub(1); - } else { - end_col = start_col + 1; - } + let lo = span.lo(); + let hi = span.hi(); + + let file = source_map.lookup_source_file(lo); + if !file.contains(hi) { + debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping"); + return None; + } + + // Column numbers need to be in bytes, so we can't use the more convenient + // `SourceMap` methods for looking up file coordinates. + let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> { + let rpos = file.relative_position(pos); + let line_index = file.lookup_line(rpos)?; + let line_start = file.lines()[line_index]; + // Line numbers and column numbers are 1-based, so add 1 to each. + Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1)) }; - if let Some(file) = file { - start_line = source_map.doctest_offset_line(&file.name, start_line); - end_line = source_map.doctest_offset_line(&file.name, end_line); + + let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?; + let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?; + + // If the span is empty, try to expand it horizontally by one character's + // worth of bytes, so that it is more visible in `llvm-cov` reports. + // We do this after resolving line/column numbers, so that empty spans at the + // end of a line get an extra column instead of wrapping to the next line. + if span.is_empty() + && body_span.contains(span) + && let Some(src) = &file.src + { + // Prefer to expand the end position, if it won't go outside the body span. + if hi < body_span.hi() { + let hi_rpos = hi_rpos.to_usize(); + let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos; + end_col += nudge_bytes; + } else if lo > body_span.lo() { + let lo_rpos = lo_rpos.to_usize(); + let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1); + // Subtract the nudge, but don't go below column 1. + start_col = start_col.saturating_sub(nudge_bytes).max(1); + } + // If neither nudge could be applied, stick with the empty span coordinates. } - CodeRegion { + + // Apply an offset so that code in doctests has correct line numbers. + // FIXME(#79417): Currently we have no way to offset doctest _columns_. + start_line = source_map.doctest_offset_line(&file.name, start_line); + end_line = source_map.doctest_offset_line(&file.name, end_line); + + Some(CodeRegion { file_name, start_line: start_line as u32, start_col: start_col as u32, end_line: end_line as u32, end_col: end_col as u32, - } + }) } fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ed091752187..5983189984d 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,11 +1,9 @@ -use std::cell::OnceCell; - use rustc_data_structures::graph::WithNumNodes; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; +use rustc_span::{BytePos, Span, DUMMY_SP}; -use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use super::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -70,35 +68,17 @@ impl CoverageSpans { /// `dominates()` the `BasicBlock`s in this `CoverageSpan`. #[derive(Debug, Clone)] struct CoverageSpan { - pub span: Span, - pub expn_span: Span, - pub current_macro_or_none: OnceCell<Option<Symbol>>, - pub bcb: BasicCoverageBlock, + span: Span, + bcb: BasicCoverageBlock, /// List of all the original spans from MIR that have been merged into this /// span. Mainly used to precisely skip over gaps when truncating a span. - pub merged_spans: Vec<Span>, - pub is_closure: bool, + merged_spans: Vec<Span>, + is_closure: bool, } impl CoverageSpan { - pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, fn_sig_span, START_BCB, false) - } - - pub(super) fn new( - span: Span, - expn_span: Span, - bcb: BasicCoverageBlock, - is_closure: bool, - ) -> Self { - Self { - span, - expn_span, - current_macro_or_none: Default::default(), - bcb, - merged_spans: vec![span], - is_closure, - } + fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self { + Self { span, bcb, merged_spans: vec![span], is_closure } } pub fn merge_from(&mut self, other: &Self) { @@ -123,37 +103,6 @@ impl CoverageSpan { pub fn is_in_same_bcb(&self, other: &Self) -> bool { self.bcb == other.bcb } - - /// 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 - .get_or_init(|| { - if let ExpnKind::Macro(MacroKind::Bang, current_macro) = - self.expn_span.ctxt().outer_expn_data().kind - { - return Some(current_macro); - } - None - }) - .map(|symbol| symbol) - } - - /// If the span is part of a macro, and the macro is visible (expands directly to the given - /// body_span), returns the macro name symbol. - pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> { - let current_macro = self.current_macro()?; - let parent_callsite = self.expn_span.parent_callsite()?; - - // In addition to matching the context of the body span, the parent callsite - // must also be the source callsite, i.e. the parent must have no parent. - let is_visible_macro = - parent_callsite.parent_callsite().is_none() && parent_callsite.eq_ctxt(body_span); - is_visible_macro.then_some(current_macro) - } - - pub fn is_macro_expansion(&self) -> bool { - self.current_macro().is_some() - } } /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a @@ -164,10 +113,6 @@ impl CoverageSpan { /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) struct CoverageSpansGenerator<'a> { - /// A `Span` covering the function body of the MIR (typically from left curly brace to right - /// curly brace). - body_span: Span, - /// The BasicCoverageBlock Control Flow Graph (BCB CFG). basic_coverage_blocks: &'a CoverageGraph, @@ -244,7 +189,6 @@ impl<'a> CoverageSpansGenerator<'a> { ); let coverage_spans = Self { - body_span: hir_info.body_span, basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, @@ -266,7 +210,6 @@ impl<'a> CoverageSpansGenerator<'a> { // span-processing steps don't make sense yet. if self.some_prev.is_none() { debug!(" initial span"); - self.maybe_push_macro_name_span(); continue; } @@ -278,7 +221,6 @@ impl<'a> CoverageSpansGenerator<'a> { debug!(" same bcb (and neither is a closure), merge with prev={prev:?}"); let prev = self.take_prev(); self.curr_mut().merge_from(&prev); - self.maybe_push_macro_name_span(); // Note that curr.span may now differ from curr_original_span } else if prev.span.hi() <= curr.span.lo() { debug!( @@ -286,7 +228,6 @@ impl<'a> CoverageSpansGenerator<'a> { ); let prev = self.take_prev(); self.refined_spans.push(prev); - self.maybe_push_macro_name_span(); } else if prev.is_closure { // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // next iter @@ -297,35 +238,11 @@ impl<'a> CoverageSpansGenerator<'a> { } else if curr.is_closure { self.carve_out_span_for_closure(); } else if self.prev_original_span == curr.span { - // Note that this compares the new (`curr`) span to `prev_original_span`. - // In this branch, the actual span byte range of `prev_original_span` is not - // important. What is important is knowing whether the new `curr` span was - // **originally** the same as the original span of `prev()`. The original spans - // reflect their original sort order, and for equal spans, conveys a partial - // ordering based on CFG dominator priority. - if prev.is_macro_expansion() && curr.is_macro_expansion() { - // Macros that expand to include branching (such as - // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or - // `trace!()`) typically generate callee spans with identical - // ranges (typically the full span of the macro) for all - // `BasicBlocks`. This makes it impossible to distinguish - // the condition (`if val1 != val2`) from the optional - // branched statements (such as the call to `panic!()` on - // assert failure). In this case it is better (or less - // worse) to drop the optional branch bcbs and keep the - // non-conditional statements, to count when reached. - debug!( - " curr and prev are part of a macro expansion, and curr has the same span \ - as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ - prev={prev:?}", - ); - self.take_curr(); // Discards curr. - } else { - self.update_pending_dups(); - } + // `prev` and `curr` have the same span, or would have had the + // same span before `prev` was modified by other spans. + self.update_pending_dups(); } else { self.cutoff_prev_at_overlapping_curr(); - self.maybe_push_macro_name_span(); } } @@ -360,41 +277,6 @@ impl<'a> CoverageSpansGenerator<'a> { self.refined_spans } - /// If `curr` is part of a new macro expansion, carve out and push a separate - /// span that ends just after the macro name and its subsequent `!`. - fn maybe_push_macro_name_span(&mut self) { - let curr = self.curr(); - - let Some(visible_macro) = curr.visible_macro(self.body_span) else { return }; - if let Some(prev) = &self.some_prev - && prev.expn_span.eq_ctxt(curr.expn_span) - { - return; - } - - // The split point is relative to `curr_original_span`, - // because `curr.span` may have been merged with preceding spans. - let split_point_after_macro_bang = self.curr_original_span.lo() - + BytePos(visible_macro.as_str().len() as u32) - + BytePos(1); // add 1 for the `!` - debug_assert!(split_point_after_macro_bang <= curr.span.hi()); - if split_point_after_macro_bang > curr.span.hi() { - // Something is wrong with the macro name span; - // return now to avoid emitting malformed mappings (e.g. #117788). - return; - } - - let mut macro_name_cov = curr.clone(); - macro_name_cov.span = macro_name_cov.span.with_hi(split_point_after_macro_bang); - self.curr_mut().span = curr.span.with_lo(split_point_after_macro_bang); - - debug!( - " and curr starts a new macro expansion, so add a new span just for \ - the macro `{visible_macro}!`, new span={macro_name_cov:?}", - ); - self.refined_spans.push(macro_name_cov); - } - #[track_caller] fn curr(&self) -> &CoverageSpan { self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)")) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 8f6592afe85..1b6dfccd574 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,11 +1,14 @@ use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{ self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::Span; +use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; -use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use crate::coverage::graph::{ + BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, +}; use crate::coverage::spans::CoverageSpan; use crate::coverage::ExtractedHirInfo; @@ -15,26 +18,29 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( basic_coverage_blocks: &CoverageGraph, ) -> Vec<CoverageSpan> { let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info; + + let mut initial_spans = vec![SpanFromMir::for_fn_sig(fn_sig_span)]; + if is_async_fn { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared - // outer function will be unhelpful, so just produce a single span - // associating the function signature with its entry BCB. - return vec![CoverageSpan::for_fn_sig(fn_sig_span)]; - } - - let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2); - for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); - } + // outer function will be unhelpful, so just keep the signature span + // and ignore all of the spans in the MIR body. + } else { + for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { + initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + } - if initial_spans.is_empty() { - // This can happen if, for example, the function is unreachable (contains only a - // `BasicBlock`(s) with an `Unreachable` terminator). - return initial_spans; + // If no spans were extracted from the body, discard the signature span. + // FIXME: This preserves existing behavior; consider getting rid of it. + if initial_spans.len() == 1 { + initial_spans.clear(); + } } - initial_spans.push(CoverageSpan::for_fn_sig(fn_sig_span)); + initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); + remove_unwanted_macro_spans(&mut initial_spans); + split_visible_macro_spans(&mut initial_spans); initial_spans.sort_by(|a, b| { // First sort by span start. @@ -53,7 +59,62 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) }); - initial_spans + initial_spans.into_iter().map(SpanFromMir::into_coverage_span).collect::<Vec<_>>() +} + +/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate +/// multiple condition/consequent blocks that have the span of the whole macro +/// invocation, which is unhelpful. Keeping only the first such span seems to +/// give better mappings, so remove the others. +/// +/// (The input spans should be sorted in BCB dominator order, so that the +/// retained "first" span is likely to dominate the others.) +fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { + let mut seen_macro_spans = FxHashSet::default(); + initial_spans.retain(|covspan| { + // Ignore (retain) closure spans and non-macro-expansion spans. + if covspan.is_closure || covspan.visible_macro.is_none() { + return true; + } + + // Retain only the first macro-expanded covspan with this span. + seen_macro_spans.insert(covspan.span) + }); +} + +/// When a span corresponds to a macro invocation that is visible from the +/// function body, split it into two parts. The first part covers just the +/// macro name plus `!`, and the second part covers the rest of the macro +/// invocation. This seems to give better results for code that uses macros. +fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { + let mut extra_spans = vec![]; + + initial_spans.retain(|covspan| { + if covspan.is_closure { + return true; + } + + let Some(visible_macro) = covspan.visible_macro else { return true }; + + let split_len = visible_macro.as_str().len() as u32 + 1; + let (before, after) = covspan.span.split_at(split_len); + if !covspan.span.contains(before) || !covspan.span.contains(after) { + // Something is unexpectedly wrong with the split point. + // The debug assertion in `split_at` will have already caught this, + // but in release builds it's safer to do nothing and maybe get a + // bug report for unexpected coverage, rather than risk an ICE. + return true; + } + + assert!(!covspan.is_closure); + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false)); + false // Discard the original covspan that we just split. + }); + + // The newly-split spans are added at the end, so any previous sorting + // is not preserved. + initial_spans.extend(extra_spans); } // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of @@ -66,22 +127,24 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( body_span: Span, bcb: BasicCoverageBlock, bcb_data: &'a BasicCoverageBlockData, -) -> impl Iterator<Item = CoverageSpan> + Captures<'a> + Captures<'tcx> { +) -> impl Iterator<Item = SpanFromMir> + Captures<'a> + Captures<'tcx> { bcb_data.basic_blocks.iter().flat_map(move |&bb| { let data = &mir_body[bb]; let statement_spans = data.statements.iter().filter_map(move |statement| { let expn_span = filtered_statement_span(statement)?; - let span = unexpand_into_body_span(expn_span, body_span)?; + let (span, visible_macro) = + unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, is_closure_or_coroutine(statement))) + Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_or_coroutine(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { let expn_span = filtered_terminator_span(terminator)?; - let span = unexpand_into_body_span(expn_span, body_span)?; + let (span, visible_macro) = + unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, false)) + Some(SpanFromMir::new(span, visible_macro, bcb, false)) }); statement_spans.chain(terminator_span) @@ -202,7 +265,83 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> { /// /// [^1]Expansions result from Rust syntax including macros, syntactic sugar, /// etc.). -#[inline] -fn unexpand_into_body_span(span: Span, body_span: Span) -> Option<Span> { - span.find_ancestor_inside_same_ctxt(body_span) +fn unexpand_into_body_span_with_visible_macro( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option<Symbol>)> { + let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; + + let visible_macro = prev + .map(|prev| match prev.ctxt().outer_expn_data().kind { + ExpnKind::Macro(MacroKind::Bang, name) => Some(name), + _ => None, + }) + .flatten(); + + Some((span, visible_macro)) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. +/// The ancestor that was traversed just before the matching span (if any) is +/// also returned. +/// +/// For example, a return value of `Some((ancestor, Some(prev))` means that: +/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` +/// - `ancestor == prev.parent_callsite()` +/// +/// [`SyntaxContext`]: rustc_span::SyntaxContext +fn unexpand_into_body_span_with_prev( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option<Span>)> { + let mut prev = None; + let mut curr = original_span; + + while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { + prev = Some(curr); + curr = curr.parent_callsite()?; + } + + debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); + if let Some(prev) = prev { + debug_assert_eq!(Some(curr), prev.parent_callsite()); + } + + Some((curr, prev)) +} + +#[derive(Debug)] +struct SpanFromMir { + /// A span that has been extracted from MIR and then "un-expanded" back to + /// within the current function's `body_span`. After various intermediate + /// processing steps, this span is emitted as part of the final coverage + /// mappings. + /// + /// With the exception of `fn_sig_span`, this should always be contained + /// within `body_span`. + span: Span, + visible_macro: Option<Symbol>, + bcb: BasicCoverageBlock, + is_closure: bool, +} + +impl SpanFromMir { + fn for_fn_sig(fn_sig_span: Span) -> Self { + Self::new(fn_sig_span, None, START_BCB, false) + } + + fn new( + span: Span, + visible_macro: Option<Symbol>, + bcb: BasicCoverageBlock, + is_closure: bool, + ) -> Self { + Self { span, visible_macro, bcb, is_closure } + } + + fn into_coverage_span(self) -> CoverageSpan { + let Self { span, visible_macro: _, bcb, is_closure } = self; + CoverageSpan::new(span, bcb, is_closure) + } } diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs index b40b2ec8bfd..824974970bb 100644 --- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs +++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs @@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 15502adfb5a..49b0edc0db8 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -131,11 +131,8 @@ //! [attempt 2]: https://github.com/rust-lang/rust/pull/71003 //! [attempt 3]: https://github.com/rust-lang/rust/pull/72632 -use std::collections::hash_map::{Entry, OccupiedEntry}; - -use crate::simplify::remove_dead_blocks; use crate::MirPass; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::HasLocalDecls; @@ -212,7 +209,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len()); // This is the set of merges we will apply this round. It is a subset of the candidates. - let mut merges = FxHashMap::default(); + let mut merges = FxIndexMap::default(); for (src, candidates) in candidates.c.iter() { if merged_locals.contains(*src) { @@ -241,12 +238,6 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { apply_merges(body, tcx, &merges, &merged_locals); } - if round_count != 0 { - // Merging can introduce overlap between moved arguments and/or call destination in an - // unreachable code, which validator considers to be ill-formed. - remove_dead_blocks(body); - } - trace!(round_count); } } @@ -257,8 +248,8 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { /// frequently. Everything with a `&'alloc` lifetime points into here. #[derive(Default)] struct Allocations { - candidates: FxHashMap<Local, Vec<Local>>, - candidates_reverse: FxHashMap<Local, Vec<Local>>, + candidates: FxIndexMap<Local, Vec<Local>>, + candidates_reverse: FxIndexMap<Local, Vec<Local>>, write_info: WriteInfo, // PERF: Do this for `MaybeLiveLocals` allocations too. } @@ -279,11 +270,11 @@ struct Candidates<'alloc> { /// /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to /// remove that assignment. - c: &'alloc mut FxHashMap<Local, Vec<Local>>, + c: &'alloc mut FxIndexMap<Local, Vec<Local>>, /// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`, /// then this contains `b => a`. // PERF: Possibly these should be `SmallVec`s? - reverse: &'alloc mut FxHashMap<Local, Vec<Local>>, + reverse: &'alloc mut FxIndexMap<Local, Vec<Local>>, } ////////////////////////////////////////////////////////// @@ -294,7 +285,7 @@ struct Candidates<'alloc> { fn apply_merges<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, - merges: &FxHashMap<Local, Local>, + merges: &FxIndexMap<Local, Local>, merged_locals: &BitSet<Local>, ) { let mut merger = Merger { tcx, merges, merged_locals }; @@ -303,7 +294,7 @@ fn apply_merges<'tcx>( struct Merger<'a, 'tcx> { tcx: TyCtxt<'tcx>, - merges: &'a FxHashMap<Local, Local>, + merges: &'a FxIndexMap<Local, Local>, merged_locals: &'a BitSet<Local>, } @@ -386,7 +377,7 @@ impl<'alloc> Candidates<'alloc> { /// `vec_filter_candidates` but for an `Entry` fn entry_filter_candidates( - mut entry: OccupiedEntry<'_, Local, Vec<Local>>, + mut entry: IndexOccupiedEntry<'_, Local, Vec<Local>>, p: Local, f: impl FnMut(Local) -> CandidateFilter, at: Location, @@ -406,7 +397,7 @@ impl<'alloc> Candidates<'alloc> { at: Location, ) { // Cover the cases where `p` appears as a `src` - if let Entry::Occupied(entry) = self.c.entry(p) { + if let IndexEntry::Occupied(entry) = self.c.entry(p) { Self::entry_filter_candidates(entry, p, &mut f, at); } // And the cases where `p` appears as a `dest` @@ -419,7 +410,7 @@ impl<'alloc> Candidates<'alloc> { if f(*src) == CandidateFilter::Keep { return true; } - let Entry::Occupied(entry) = self.c.entry(*src) else { + let IndexEntry::Occupied(entry) = self.c.entry(*src) else { return false; }; Self::entry_filter_candidates( @@ -728,8 +719,8 @@ fn places_to_candidate_pair<'tcx>( fn find_candidates<'alloc, 'tcx>( body: &Body<'tcx>, borrowed: &BitSet<Local>, - candidates: &'alloc mut FxHashMap<Local, Vec<Local>>, - candidates_reverse: &'alloc mut FxHashMap<Local, Vec<Local>>, + candidates: &'alloc mut FxIndexMap<Local, Vec<Local>>, + candidates_reverse: &'alloc mut FxIndexMap<Local, Vec<Local>>, ) -> Candidates<'alloc> { candidates.clear(); candidates_reverse.clear(); @@ -751,7 +742,7 @@ fn find_candidates<'alloc, 'tcx>( struct FindAssignments<'a, 'alloc, 'tcx> { body: &'a Body<'tcx>, - candidates: &'alloc mut FxHashMap<Local, Vec<Local>>, + candidates: &'alloc mut FxIndexMap<Local, Vec<Local>>, borrowed: &'a BitSet<Local>, } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 6eb6cb069fe..0d600f0f937 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -212,7 +212,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 17916e16daf..446f13feff0 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -67,11 +67,11 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for RequiresUnsafe { fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::mir_transform_requires_unsafe); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); - diag.set_span(self.span); + diag.span(self.span); diag.span_label(self.span, self.details.label()); let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); - diag.set_arg("details", desc); - diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); + diag.arg("details", desc); + diag.arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); self.details.add_subdiagnostics(&mut diag); if let Some(sp) = self.enclosing { diag.span_label(sp, fluent::mir_transform_not_inherited); @@ -122,16 +122,16 @@ impl RequiresUnsafeDetail { } CallToFunctionWith { ref missing, ref build_enabled } => { diag.help(fluent::mir_transform_target_feature_call_help); - diag.set_arg( + diag.arg( "missing_target_features", DiagnosticArgValue::StrListSepByAnd( missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), ), ); - diag.set_arg("missing_target_features_count", missing.len()); + diag.arg("missing_target_features_count", missing.len()); if !build_enabled.is_empty() { diag.note(fluent::mir_transform_target_feature_call_note); - diag.set_arg( + diag.arg( "build_target_features", DiagnosticArgValue::StrListSepByAnd( build_enabled @@ -140,7 +140,7 @@ impl RequiresUnsafeDetail { .collect(), ), ); - diag.set_arg("build_target_features_count", build_enabled.len()); + diag.arg("build_target_features_count", build_enabled.len()); } } } @@ -181,9 +181,8 @@ pub(crate) struct UnsafeOpInUnsafeFn { impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { #[track_caller] fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { - let dcx = diag.dcx().expect("lint should not yet be emitted"); - let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); - diag.set_arg("details", desc); + let desc = diag.dcx.eagerly_translate_to_string(self.details.label(), [].into_iter()); + diag.arg("details", desc); diag.span_label(self.details.span, self.details.label()); self.details.add_subdiagnostics(diag); @@ -213,7 +212,7 @@ impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> { let assert_kind = self.panic(); let message = assert_kind.diagnostic_message(); assert_kind.add_args(&mut |name, value| { - diag.set_arg(name, value); + diag.arg(name, value); }); diag.span_label(span, message); } @@ -280,9 +279,9 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { diag.subdiagnostic(reason); } diag.span_help(self.src_sp, fluent::_subdiag::help); - diag.set_arg("pre", self.pre); - diag.set_arg("def_path", self.tcx.def_path_str(self.def_id)); - diag.set_arg("post", self.post); + diag.arg("pre", self.pre); + diag.arg("def_path", self.tcx.def_path_str(self.def_id)); + diag.arg("post", self.post); } fn msg(&self) -> rustc_errors::DiagnosticMessage { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8ad804bf3e7..ebefc3b47cc 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -15,7 +15,7 @@ use rustc_target::abi::FieldIdx; use rustc_target::spec::abi::Abi; use crate::cost_checker::CostChecker; -use crate::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::simplify::simplify_cfg; use crate::util; use std::iter; use std::ops::{Range, RangeFrom}; @@ -56,8 +56,7 @@ impl<'tcx> MirPass<'tcx> for Inline { let _guard = span.enter(); if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); - CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + simplify_cfg(body); deref_finder(tcx, body); } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index a41d8e21245..dcab124505e 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -43,6 +43,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; +use rustc_target::abi::{TagEncoding, Variants}; use crate::cost_checker::CostChecker; @@ -391,8 +392,25 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { StatementKind::SetDiscriminant { box place, variant_index } => { let discr_target = self.map.find_discr(place.as_ref())?; let enum_ty = place.ty(self.body, self.tcx).ty; - let discr = discriminant_for_variant(enum_ty, *variant_index)?; - self.process_operand(bb, discr_target, &discr, state)?; + // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant + // of a niche encoding. If we cannot ensure that we write to the discriminant, do + // nothing. + let enum_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; + let writes_discriminant = match enum_layout.variants { + Variants::Single { index } => { + assert_eq!(index, *variant_index); + true + } + Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => true, + Variants::Multiple { + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, + .. + } => *variant_index != untagged_variant, + }; + if writes_discriminant { + let discr = discriminant_for_variant(enum_ty, *variant_index)?; + self.process_operand(bb, discr_target, &discr, state)?; + } } // If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`. StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5562ae7f3bd..ce9043ec287 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,6 +1,6 @@ -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(cow_is_borrowed)] #![feature(decl_macro)] @@ -10,6 +10,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(option_get_or_insert_default)] +#![feature(round_char_boundary)] #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] @@ -94,6 +95,7 @@ mod multiple_return_terminators; mod normalize_array_len; mod nrvo; mod prettify; +mod promote_consts; mod ref_prop; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -115,7 +117,6 @@ mod uninhabited_enum_branching; mod unreachable_prop; use rustc_const_eval::transform::check_consts::{self, ConstCx}; -use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; use rustc_mir_dataflow::rustc_peek; @@ -285,9 +286,9 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { /// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). /// We used to have this for pre-miri MIR based const eval. fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { - // Unsafety check uses the raw mir, so make sure it is run. + // MIR unsafety check uses the raw mir, so make sure it is run. if !tcx.sess.opts.unstable_opts.thir_unsafeck { - tcx.ensure_with_value().unsafety_check_result(def); + tcx.ensure_with_value().mir_unsafety_check_result(def); } // has_ffi_unwind_calls query uses the raw mir, so make sure it is run. @@ -565,17 +566,28 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { body, &[ &check_alignment::CheckAlignment, - &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first + // Before inlining: trim down MIR with passes to reduce inlining work. + + // Has to be done before inlining, otherwise actual call will be almost always inlined. + // Also simple, so can just do first + &lower_slice_len::LowerSliceLenCalls, + // Perform inlining, which may add a lot of code. &inline::Inline, - // Substitutions during inlining may introduce switch on enums with uninhabited branches. + // Code from other crates may have storage markers, so this needs to happen after inlining. + &remove_storage_markers::RemoveStorageMarkers, + // Inlining and substitution may introduce ZST and useless drops. + &remove_zsts::RemoveZsts, + &remove_unneeded_drops::RemoveUnneededDrops, + // Type substitution may create uninhabited enums. &uninhabited_enum_branching::UninhabitedEnumBranching, &unreachable_prop::UnreachablePropagation, &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching), - &remove_storage_markers::RemoveStorageMarkers, - &remove_zsts::RemoveZsts, - &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering + // Inlining may have introduced a lot of redundant code and a large move pattern. + // Now, we need to shrink the generated MIR. + + // Has to run after `slice::len` lowering + &normalize_array_len::NormalizeArrayLen, &const_goto::ConstGoto, - &remove_unneeded_drops::RemoveUnneededDrops, &ref_prop::ReferencePropagation, &sroa::ScalarReplacementOfAggregates, &match_branches::MatchBranchSimplification, diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 3940d0ddbf3..c0c0a3f5ee6 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -1,6 +1,7 @@ //! This pass statically detects code which has undefined behaviour or is likely to be erroneous. //! It can be used to locate problems in MIR building or optimizations. It assumes that all code //! can be executed, so it has false positives. +use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -11,7 +12,6 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor}; use std::borrow::Cow; pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { - let reachable_blocks = traversal::reachable_as_bitset(body); let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) @@ -24,17 +24,19 @@ pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { .iterate_to_fixpoint() .into_results_cursor(body); - Lint { + let mut lint = Lint { tcx, when, body, is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(), always_live_locals, - reachable_blocks, maybe_storage_live, maybe_storage_dead, + places: Default::default(), + }; + for (bb, data) in traversal::reachable(body) { + lint.visit_basic_block_data(bb, data); } - .visit_body(body); } struct Lint<'a, 'tcx> { @@ -43,9 +45,9 @@ struct Lint<'a, 'tcx> { body: &'a Body<'tcx>, is_fn_like: bool, always_live_locals: &'a BitSet<Local>, - reachable_blocks: BitSet<BasicBlock>, maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>, + places: FxHashSet<PlaceRef<'tcx>>, } impl<'a, 'tcx> Lint<'a, 'tcx> { @@ -67,7 +69,7 @@ impl<'a, 'tcx> Lint<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - if self.reachable_blocks.contains(location.block) && context.is_use() { + if context.is_use() { self.maybe_storage_dead.seek_after_primary_effect(location); if self.maybe_storage_dead.get().contains(local) { self.fail(location, format!("use of local {local:?}, which has no storage here")); @@ -76,18 +78,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - match statement.kind { - StatementKind::StorageLive(local) => { - if self.reachable_blocks.contains(location.block) { - self.maybe_storage_live.seek_before_primary_effect(location); - if self.maybe_storage_live.get().contains(local) { + match &statement.kind { + StatementKind::Assign(box (dest, rvalue)) => { + if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { + // The sides of an assignment must not alias. Currently this just checks whether + // the places are identical. + if dest == src { self.fail( location, - format!("StorageLive({local:?}) which already has storage here"), + "encountered `Assign` statement with overlapping memory", ); } } } + StatementKind::StorageLive(local) => { + self.maybe_storage_live.seek_before_primary_effect(location); + if self.maybe_storage_live.get().contains(*local) { + self.fail( + location, + format!("StorageLive({local:?}) which already has storage here"), + ); + } + } _ => {} } @@ -95,9 +107,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - match terminator.kind { + match &terminator.kind { TerminatorKind::Return => { - if self.is_fn_like && self.reachable_blocks.contains(location.block) { + if self.is_fn_like { self.maybe_storage_live.seek_after_primary_effect(location); for local in self.maybe_storage_live.get().iter() { if !self.always_live_locals.contains(local) { @@ -111,6 +123,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { } } } + TerminatorKind::Call { args, destination, .. } => { + // The call destination place and Operand::Move place used as an argument might be + // passed by a reference to the callee. Consequently they must be non-overlapping. + // Currently this simply checks for duplicate places. + self.places.clear(); + self.places.insert(destination.as_ref()); + let mut has_duplicates = false; + for arg in args { + if let Operand::Move(place) = arg { + has_duplicates |= !self.places.insert(place.as_ref()); + } + } + if has_duplicates { + self.fail( + location, + format!( + "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}", + terminator.kind, + ), + ); + } + } _ => {} } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 1c4aa37d57f..6d4332793af 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -174,7 +174,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 82074f1960d..f4c572aec12 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -109,14 +109,15 @@ fn run_passes_inner<'tcx>( phase_change: Option<MirPhase>, validate_each: bool, ) { - let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip(); - let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip(); let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); if !body.should_skip() { + let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; + let lint = tcx.sess.opts.unstable_opts.lint_mir; + for pass in passes { let name = pass.name(); @@ -162,7 +163,12 @@ fn run_passes_inner<'tcx>( body.pass_count = 0; dump_mir_for_phase_change(tcx, body); - if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { + + let validate = + (validate_each & tcx.sess.opts.unstable_opts.validate_mir & !body.should_skip()) + || new_phase == MirPhase::Runtime(RuntimePhase::Optimized); + let lint = tcx.sess.opts.unstable_opts.lint_mir & !body.should_skip(); + if validate { validate_body(tcx, body, format!("after phase change to {}", new_phase.name())); } if lint { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 8b2ea2dc21d..841b86fed45 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -12,6 +12,7 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use either::{Left, Right}; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -22,10 +23,11 @@ use rustc_span::Span; use rustc_index::{Idx, IndexSlice, IndexVec}; +use std::assert_matches::assert_matches; use std::cell::Cell; use std::{cmp, iter, mem}; -use crate::transform::check_consts::{qualifs, ConstCx}; +use rustc_const_eval::transform::check_consts::{qualifs, ConstCx}; /// A `MirPass` for promotion. /// @@ -64,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TempState { +enum TempState { /// No references to this temp. Undefined, /// One direct assignment and any number of direct uses. @@ -78,18 +80,11 @@ pub enum TempState { PromotedOut, } -impl TempState { - pub fn is_promotable(&self) -> bool { - debug!("is_promotable: self={:?}", self); - matches!(self, TempState::Defined { .. }) - } -} - /// A "root candidate" for promotion, which will become the /// returned value in a promoted MIR, unless it's a subset /// of a larger candidate. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Candidate { +struct Candidate { location: Location, } @@ -123,46 +118,43 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { let temp = &mut self.temps[index]; debug!("visit_local: temp={:?}", temp); - if *temp == TempState::Undefined { - match context { + *temp = match *temp { + TempState::Undefined => match context { PlaceContext::MutatingUse(MutatingUseContext::Store) | PlaceContext::MutatingUse(MutatingUseContext::Call) => { - *temp = TempState::Defined { location, uses: 0, valid: Err(()) }; + TempState::Defined { location, uses: 0, valid: Err(()) } + } + _ => TempState::Unpromotable, + }, + TempState::Defined { ref mut uses, .. } => { + // We always allow borrows, even mutable ones, as we need + // to promote mutable borrows of some ZSTs e.g., `&mut []`. + let allowed_use = match context { + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + | PlaceContext::NonMutatingUse(_) => true, + PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, + }; + debug!("visit_local: allowed_use={:?}", allowed_use); + if allowed_use { + *uses += 1; return; } - _ => { /* mark as unpromotable below */ } + TempState::Unpromotable } - } else if let TempState::Defined { uses, .. } = temp { - // We always allow borrows, even mutable ones, as we need - // to promote mutable borrows of some ZSTs e.g., `&mut []`. - let allowed_use = match context { - PlaceContext::MutatingUse(MutatingUseContext::Borrow) - | PlaceContext::NonMutatingUse(_) => true, - PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, - }; - debug!("visit_local: allowed_use={:?}", allowed_use); - if allowed_use { - *uses += 1; - return; - } - /* mark as unpromotable below */ - } - *temp = TempState::Unpromotable; + TempState::Unpromotable | TempState::PromotedOut => TempState::Unpromotable, + }; } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - match *rvalue { - Rvalue::Ref(..) => { - self.candidates.push(Candidate { location }); - } - _ => {} + if let Rvalue::Ref(..) = *rvalue { + self.candidates.push(Candidate { location }); } } } -pub fn collect_temps_and_candidates<'tcx>( +fn collect_temps_and_candidates<'tcx>( ccx: &ConstCx<'_, 'tcx>, ) -> (IndexVec<Local, TempState>, Vec<Candidate>) { let mut collector = Collector { @@ -196,230 +188,165 @@ struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> { - let loc = candidate.location; - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => { - // We can only promote interior borrows of promotable temps (non-temps - // don't get promoted anyway). - self.validate_local(place.local)?; - - // The reference operation itself must be promotable. - // (Needs to come after `validate_local` to avoid ICEs.) - self.validate_ref(*kind, place)?; + let Left(statement) = self.body.stmt_at(candidate.location) else { bug!() }; + let Some((_, Rvalue::Ref(_, kind, place))) = statement.kind.as_assign() else { bug!() }; - // We do not check all the projections (they do not get promoted anyway), - // but we do stay away from promoting anything involving a dereference. - if place.projection.contains(&ProjectionElem::Deref) { - return Err(Unpromotable); - } + // We can only promote interior borrows of promotable temps (non-temps + // don't get promoted anyway). + self.validate_local(place.local)?; - Ok(()) - } - _ => bug!(), + // The reference operation itself must be promotable. + // (Needs to come after `validate_local` to avoid ICEs.) + self.validate_ref(*kind, place)?; + + // We do not check all the projections (they do not get promoted anyway), + // but we do stay away from promoting anything involving a dereference. + if place.projection.contains(&ProjectionElem::Deref) { + return Err(Unpromotable); } + + Ok(()) } // FIXME(eddyb) maybe cache this? fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool { - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let num_stmts = self.body[loc.block].statements.len(); - - if loc.statement_index < num_stmts { - let statement = &self.body[loc.block].statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::<Q, _>( - self.ccx, - &mut |l| self.qualif_local::<Q>(l), - rhs, - ), - _ => { + let TempState::Defined { location: loc, .. } = self.temps[local] else { + return false; + }; + + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { + span_bug!(statement.source_info.span, "{:?} is not an assignment", statement) + }; + qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.qualif_local::<Q>(l), rhs) + } + Right(terminator) => { + assert_matches!(terminator.kind, TerminatorKind::Call { .. }); + let return_ty = self.body.local_decls[local].ty; + Q::in_any_value_of_ty(self.ccx, return_ty) + } + } + } + + fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> { + let TempState::Defined { location: loc, uses, valid } = self.temps[local] else { + return Err(Unpromotable); + }; + + // We cannot promote things that need dropping, since the promoted value would not get + // dropped. + if self.qualif_local::<qualifs::NeedsDrop>(local) { + return Err(Unpromotable); + } + + if valid.is_ok() { + return Ok(()); + } + + let ok = { + let stmt_or_term = self.body.stmt_at(loc); + match stmt_or_term { + Left(statement) => { + let Some((_, rhs)) = statement.kind.as_assign() else { span_bug!( statement.source_info.span, "{:?} is not an assignment", statement - ); - } + ) + }; + self.validate_rvalue(rhs) } - } else { - let terminator = self.body[loc.block].terminator(); - match &terminator.kind { - TerminatorKind::Call { .. } => { - let return_ty = self.body.local_decls[local].ty; - Q::in_any_value_of_ty(self.ccx, return_ty) - } + Right(terminator) => match &terminator.kind { + TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), + TerminatorKind::Yield { .. } => Err(Unpromotable), kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } - } + }, } - } else { - false - } - } + }; - fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> { - if let TempState::Defined { location: loc, uses, valid } = self.temps[local] { - // We cannot promote things that need dropping, since the promoted value - // would not get dropped. - if self.qualif_local::<qualifs::NeedsDrop>(local) { - return Err(Unpromotable); - } - valid.or_else(|_| { - let ok = { - let block = &self.body[loc.block]; - let num_stmts = block.statements.len(); - - if loc.statement_index < num_stmts { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), - _ => { - span_bug!( - statement.source_info.span, - "{:?} is not an assignment", - statement - ); - } - } - } else { - let terminator = block.terminator(); - match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { - self.validate_call(func, args) - } - TerminatorKind::Yield { .. } => Err(Unpromotable), - kind => { - span_bug!(terminator.source_info.span, "{:?} not promotable", kind); - } - } - } - }; - self.temps[local] = match ok { - Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, - Err(_) => TempState::Unpromotable, - }; - ok - }) - } else { - Err(Unpromotable) - } + self.temps[local] = match ok { + Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) }, + Err(_) => TempState::Unpromotable, + }; + + ok } fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { - match place.last_projection() { - None => self.validate_local(place.local), - Some((place_base, elem)) => { - // Validate topmost projection, then recurse. - match elem { - ProjectionElem::Deref => { - let mut promotable = false; - // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, - // and we need to be able to promote this. So check if this deref matches - // that specific pattern. - - // We need to make sure this is a `Deref` of a local with no further projections. - // Discussion can be found at - // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - if let Some(local) = place_base.as_local() { - if let TempState::Defined { location, .. } = self.temps[local] { - let def_stmt = self.body[location.block] - .statements - .get(location.statement_index); - if let Some(Statement { - kind: - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )), - .. - }) = def_stmt - { - if let Some(did) = c.check_static_ptr(self.tcx) { - // Evaluating a promoted may not read statics except if it got - // promoted from a static (this is a CTFE check). So we - // can only promote static accesses inside statics. - if let Some(hir::ConstContext::Static(..)) = self.const_kind - { - if !self.tcx.is_thread_local_static(did) { - promotable = true; - } - } - } - } - } - } - if !promotable { - return Err(Unpromotable); - } - } - ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { - return Err(Unpromotable); - } + let Some((place_base, elem)) = place.last_projection() else { + return self.validate_local(place.local); + }; - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) - | ProjectionElem::Subslice { .. } => {} - - ProjectionElem::Index(local) => { - let mut promotable = false; - // Only accept if we can predict the index and are indexing an array. - let val = if let TempState::Defined { location: loc, .. } = - self.temps[local] - { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.const_.try_eval_target_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None - } - } else { - None - }; - if let Some(idx) = val { - // Determine the type of the thing we are indexing. - let ty = place_base.ty(self.body, self.tcx).ty; - match ty.kind() { - ty::Array(_, len) => { - // It's an array; determine its length. - if let Some(len) = - len.try_eval_target_usize(self.tcx, self.param_env) - { - // If the index is in-bounds, go ahead. - if idx < len { - promotable = true; - } - } - } - _ => {} - } - } - if !promotable { - return Err(Unpromotable); - } + // Validate topmost projection, then recurse. + match elem { + // Recurse directly. + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) + | ProjectionElem::Subslice { .. } => {} - self.validate_local(local)?; - } + // Never recurse. + ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { + return Err(Unpromotable); + } - ProjectionElem::Field(..) => { - let base_ty = place_base.ty(self.body, self.tcx).ty; - if base_ty.is_union() { - // No promotion of union field accesses. - return Err(Unpromotable); - } - } + ProjectionElem::Deref => { + // When a static is used by-value, that gets desugared to `*STATIC_ADDR`, + // and we need to be able to promote this. So check if this deref matches + // that specific pattern. + + // We need to make sure this is a `Deref` of a local with no further projections. + // Discussion can be found at + // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 + if let Some(local) = place_base.as_local() + && let TempState::Defined { location, .. } = self.temps[local] + && let Left(def_stmt) = self.body.stmt_at(location) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = def_stmt.kind.as_assign() + && let Some(did) = c.check_static_ptr(self.tcx) + // Evaluating a promoted may not read statics except if it got + // promoted from a static (this is a CTFE check). So we + // can only promote static accesses inside statics. + && let Some(hir::ConstContext::Static(..)) = self.const_kind + && !self.tcx.is_thread_local_static(did) + { + // Recurse. + } else { + return Err(Unpromotable); } + } + ProjectionElem::Index(local) => { + // Only accept if we can predict the index and are indexing an array. + if let TempState::Defined { location: loc, .. } = self.temps[local] + && let Left(statement) = self.body.stmt_at(loc) + && let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign() + && let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.param_env) + // Determine the type of the thing we are indexing. + && let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind() + // It's an array; determine its length. + && let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) + // If the index is in-bounds, go ahead. + && idx < len + { + self.validate_local(local)?; + // Recurse. + } else { + return Err(Unpromotable); + } + } - self.validate_place(place_base) + ProjectionElem::Field(..) => { + let base_ty = place_base.ty(self.body, self.tcx).ty; + if base_ty.is_union() { + // No promotion of union field accesses. + return Err(Unpromotable); + } } } + + self.validate_place(place_base) } fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> { @@ -676,7 +603,7 @@ impl<'tcx> Validator<'_, 'tcx> { } // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. -pub fn validate_candidates( +fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice<Local, TempState>, candidates: &[Candidate], @@ -930,7 +857,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } -pub fn promote_candidates<'tcx>( +fn promote_candidates<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec<Local, TempState>, @@ -969,7 +896,7 @@ pub fn promote_candidates<'tcx>( 0, vec![], body.span, - body.coroutine_kind(), + None, body.tainted_by_errors, ); promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial); diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 5d528bed356..2778d91e17b 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -38,7 +38,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(tcx, body); + simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 6e22690d8da..7120ef72142 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -50,11 +50,11 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // If execution did something, applying a simplification layer // helps later passes optimize the copy away. if separate_const_switch(body) > 0 { - super::simplify::simplify_cfg(tcx, body); + super::simplify::simplify_cfg(body); } } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 856a0f22771..8c8818bd68e 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -27,7 +27,6 @@ //! naively generate still contains the `_a = ()` write in the unreachable block "after" the //! return. -use rustc_data_structures::fx::FxIndexSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -62,9 +61,8 @@ impl SimplifyCfg { } } -pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub(crate) fn simplify_cfg(body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_duplicate_unreachable_blocks(tcx, body); remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager @@ -76,9 +74,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { self.name() } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source); - simplify_cfg(tcx, body); + simplify_cfg(body); } } @@ -289,55 +287,25 @@ pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) { } } -pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - struct OptApplier<'tcx> { - tcx: TyCtxt<'tcx>, - duplicates: FxIndexSet<BasicBlock>, - } - - impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { - for target in terminator.successors_mut() { - // We don't have to check whether `target` is a cleanup block, because have - // entirely excluded cleanup blocks in building the set of duplicates. - if self.duplicates.contains(target) { - *target = self.duplicates[0]; - } - } - - simplify_duplicate_switch_targets(terminator); - - self.super_terminator(terminator, location); - } - } +pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) { + let should_deduplicate_unreachable = |bbdata: &BasicBlockData<'_>| { + // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a + // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just + // before then so we need to handle missing terminators. + // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we + // don't emit empty unreachable cleanup blocks, so this simple check suffices. + bbdata.terminator.is_some() && bbdata.is_empty_unreachable() && !bbdata.is_cleanup + }; - let unreachable_blocks = body + let reachable = traversal::reachable_as_bitset(body); + let empty_unreachable_blocks = body .basic_blocks .iter_enumerated() - .filter(|(_, bb)| { - // CfgSimplifier::simplify leaves behind some unreachable basic blocks without a - // terminator. Those blocks will be deleted by remove_dead_blocks, but we run just - // before then so we need to handle missing terminators. - // We also need to prevent confusing cleanup and non-cleanup blocks. In practice we - // don't emit empty unreachable cleanup blocks, so this simple check suffices. - bb.terminator.is_some() && bb.is_empty_unreachable() && !bb.is_cleanup - }) - .map(|(block, _)| block) - .collect::<FxIndexSet<_>>(); - - if unreachable_blocks.len() > 1 { - OptApplier { tcx, duplicates: unreachable_blocks }.visit_body(body); - } -} + .filter(|(bb, bbdata)| should_deduplicate_unreachable(bbdata) && reachable.contains(*bb)) + .count(); -pub fn remove_dead_blocks(body: &mut Body<'_>) { - let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); - if num_blocks == reachable.count() { + if num_blocks == reachable.count() && empty_unreachable_blocks <= 1 { return; } @@ -346,14 +314,28 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut orig_index = 0; let mut used_index = 0; - basic_blocks.raw.retain(|_| { - let keep = reachable.contains(BasicBlock::new(orig_index)); - if keep { - replacements[orig_index] = BasicBlock::new(used_index); - used_index += 1; + let mut kept_unreachable = None; + basic_blocks.raw.retain(|bbdata| { + let orig_bb = BasicBlock::new(orig_index); + if !reachable.contains(orig_bb) { + orig_index += 1; + return false; + } + + let used_bb = BasicBlock::new(used_index); + if should_deduplicate_unreachable(bbdata) { + let kept_unreachable = *kept_unreachable.get_or_insert(used_bb); + if kept_unreachable != used_bb { + replacements[orig_index] = kept_unreachable; + orig_index += 1; + return false; + } } + + replacements[orig_index] = used_bb; + used_index += 1; orig_index += 1; - keep + true }); for block in basic_blocks { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 3a6e1ef3488..1ed3b14e755 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -94,6 +94,7 @@ impl SsaLocals { self.direct_uses[local] } + #[inline] pub fn assignment_dominates( &self, dominators: &Dominators<BasicBlock>, diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index f12a6aa2429..bff59aa6023 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -54,6 +54,8 @@ impl MirPass<'_> for UnreachablePropagation { patch.apply(body); // We do want do keep some unreachable blocks, but make them empty. + // The order in which we clear bb statements does not matter. + #[allow(rustc::potential_query_instability)] for bb in unreachable_blocks { body.basic_blocks_mut()[bb].statements.clear(); } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index e27875853df..94b553a07a7 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -20,6 +20,9 @@ monomorphize_recursion_limit = reached the recursion limit while instantiating `{$shrunk}` .note = `{$def_path_str}` defined here +monomorphize_start_not_found = using `fn main` requires the standard library + .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` + monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 44beafa0873..92f001cc321 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -194,7 +194,7 @@ use rustc_target::abi::Size; use std::path::PathBuf; use crate::errors::{ - EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit, + self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit, TypeLengthLimit, }; @@ -1272,7 +1272,9 @@ impl<'v> RootCollector<'_, 'v> { return; }; - let start_def_id = self.tcx.require_lang_item(LangItem::Start, None); + let Some(start_def_id) = self.tcx.lang_items().start_fn() else { + self.tcx.dcx().emit_fatal(errors::StartNotFound); + }; let main_ret_ty = self.tcx.fn_sig(main_def_id).no_bound_vars().unwrap().output(); // Given that `main()` has no arguments, diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 592e71251b8..bd89874b5cc 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -51,7 +51,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for UnusedGenericParamsHint { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::monomorphize_unused_generic_params); - diag.set_span(self.span); + diag.span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { // FIXME: I can figure out how to do a label with a fluent string with a fixed message, // or a label with a dynamic value in a hard-coded string, but I haven't figured out @@ -95,6 +95,11 @@ pub struct EncounteredErrorWhileInstantiating { } #[derive(Diagnostic)] +#[diag(monomorphize_start_not_found)] +#[help] +pub struct StartNotFound; + +#[derive(Diagnostic)] #[diag(monomorphize_unknown_cgu_collection_mode)] pub struct UnknownCguCollectionMode<'a> { pub mode: &'a str, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 08e62840839..2c40cd4d8f2 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -1093,7 +1093,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co MonoItemCollectionMode::Eager } else { if mode != "lazy" { - tcx.dcx().emit_warning(UnknownCguCollectionMode { mode }); + tcx.dcx().emit_warn(UnknownCguCollectionMode { mode }); } MonoItemCollectionMode::Lazy diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c6bddbfacd6..c11a6fab7e5 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -10,6 +10,8 @@ parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretat parse_array_brackets_instead_of_braces = this is a block expression, not an array .suggestion = to make an array, use square brackets instead of curly braces +parse_array_index_offset_of = array indexing not supported in offset_of + parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed parse_assoc_lifetime = associated lifetimes are not supported @@ -405,6 +407,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` +parse_invalid_offset_of = offset_of expects dot-separated field and variant names + parse_invalid_unicode_escape = invalid unicode character escape .label = invalid escape .help = unicode escape must {$surrogate -> @@ -767,6 +771,9 @@ parse_unexpected_if_with_if = unexpected `if` in the condition expression parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern .suggestion = remove the lifetime +parse_unexpected_paren_in_range_pat = range pattern bounds cannot have parentheses +parse_unexpected_paren_in_range_pat_sugg = remove these parentheses + parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head .suggestion = remove parentheses in `for` loop diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e276b34ca37..0de252707bd 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1065,8 +1065,8 @@ impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier { None => fluent::parse_expected_identifier_found_str, }, ); - diag.set_span(self.span); - diag.set_arg("token", self.token); + diag.span(self.span); + diag.arg("token", self.token); if let Some(sugg) = self.suggest_raw { sugg.add_to_diagnostic(&mut diag); @@ -1123,8 +1123,8 @@ impl<'a> IntoDiagnostic<'a> for ExpectedSemi { None => fluent::parse_expected_semi_found_str, }, ); - diag.set_span(self.span); - diag.set_arg("token", self.token); + diag.span(self.span); + diag.arg("token", self.token); if let Some(unexpected_token_label) = self.unexpected_token_label { diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token); @@ -2379,6 +2379,27 @@ pub(crate) struct ExpectedCommaAfterPatternField { } #[derive(Diagnostic)] +#[diag(parse_unexpected_paren_in_range_pat)] +pub(crate) struct UnexpectedParenInRangePat { + #[primary_span] + pub span: Vec<Span>, + #[subdiagnostic] + pub sugg: UnexpectedParenInRangePatSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unexpected_paren_in_range_pat_sugg, + applicability = "machine-applicable" +)] +pub(crate) struct UnexpectedParenInRangePatSugg { + #[suggestion_part(code = "")] + pub start_span: Span, + #[suggestion_part(code = "")] + pub end_span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_return_types_use_thin_arrow)] pub(crate) struct ReturnTypesUseThinArrow { #[primary_span] @@ -2887,3 +2908,11 @@ pub(crate) struct TransposeDynOrImplSugg<'a> { pub insertion_span: Span, pub kw: &'a str, } + +#[derive(Diagnostic)] +#[diag(parse_array_index_offset_of)] +pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span); + +#[derive(Diagnostic)] +#[diag(parse_invalid_offset_of)] +pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 083d1984e00..7db9291921f 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,9 +7,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{ - error_code, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalAbort, StashKey, -}; +use rustc_errors::{error_code, Applicability, DiagCtxt, Diagnostic, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -69,7 +67,7 @@ pub(crate) fn parse_token_trees<'a>( let (stream, res, unmatched_delims) = tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); match res { - Ok(_open_spacing) if unmatched_delims.is_empty() => Ok(stream), + Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { // Return error if there are unmatched delimiters or unclosed delimiters. // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch @@ -251,9 +249,9 @@ impl<'a> StringReader<'a> { let lifetime_name = self.str_from(start); if starts_with_number { let span = self.mk_sp(start, self.pos); - let mut diag = self.dcx().struct_err("lifetimes cannot start with a number"); - diag.set_span(span); - diag.stash(span, StashKey::LifetimeIsChar); + self.dcx().struct_err("lifetimes cannot start with a number") + .with_span(span) + .stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); token::Lifetime(ident) @@ -344,18 +342,6 @@ impl<'a> StringReader<'a> { token::Ident(sym, false) } - fn struct_fatal_span_char( - &self, - from_pos: BytePos, - to_pos: BytePos, - m: &str, - c: char, - ) -> DiagnosticBuilder<'a, FatalAbort> { - self.sess - .dcx - .struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c))) - } - /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly /// complain about it. fn lint_unicode_text_flow(&self, start: BytePos) { @@ -409,51 +395,58 @@ impl<'a> StringReader<'a> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start, end), - "unterminated character literal", - error_code!(E0762), - ) + self.dcx() + .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") + .with_code(error_code!(E0762)) + .emit() } self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated byte constant", - error_code!(E0763), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated byte constant", + ) + .with_code(error_code!(E0763)) + .emit() } self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start, end), - "unterminated double quote string", - error_code!(E0765), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start, end), + "unterminated double quote string", + ) + .with_code(error_code!(E0765)) + .emit() } self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated double quote byte string", - error_code!(E0766), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated double quote byte string", + ) + .with_code(error_code!(E0766)) + .emit() } self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { - self.dcx().span_fatal_with_code( - self.mk_sp(start + BytePos(1), end), - "unterminated C string", - error_code!(E0767), - ) + self.dcx() + .struct_span_fatal( + self.mk_sp(start + BytePos(1), end), + "unterminated C string", + ) + .with_code(error_code!(E0767)) + .emit() } self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } @@ -568,13 +561,16 @@ impl<'a> StringReader<'a> { } fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! { - self.struct_fatal_span_char( - start, - self.pos, - "found invalid character; only `#` is allowed in raw string delimitation", - bad_char, - ) - .emit() + self.sess + .dcx + .struct_span_fatal( + self.mk_sp(start, self.pos), + format!( + "found invalid character; only `#` is allowed in raw string delimitation: {}", + escaped_char(bad_char) + ), + ) + .emit() } fn report_unterminated_raw_string( @@ -584,12 +580,9 @@ impl<'a> StringReader<'a> { possible_offset: Option<u32>, found_terminators: u32, ) -> ! { - let mut err = self.dcx().struct_span_fatal_with_code( - self.mk_sp(start, start), - "unterminated raw string", - error_code!(E0748), - ); - + let mut err = + self.dcx().struct_span_fatal(self.mk_sp(start, start), "unterminated raw string"); + err.code(error_code!(E0748)); err.span_label(self.mk_sp(start, start), "unterminated raw string"); if n_hashes > 0 { @@ -620,11 +613,8 @@ impl<'a> StringReader<'a> { None => "unterminated block comment", }; let last_bpos = self.pos; - let mut err = self.dcx().struct_span_fatal_with_code( - self.mk_sp(start, last_bpos), - msg, - error_code!(E0758), - ); + let mut err = self.dcx().struct_span_fatal(self.mk_sp(start, last_bpos), msg); + err.code(error_code!(E0758)); let mut nested_block_comment_open_idxs = vec![]; let mut last_nested_block_comment_idxs = None; let mut content_chars = self.str_from(start).char_indices().peekable(); diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index b6cccd275ee..64b3928689a 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -277,9 +277,9 @@ impl<'a> TokenTreesReader<'a> { parser.bump(); } if !diff_errs.is_empty() { - errs.iter_mut().for_each(|err| { - err.delay_as_bug(); - }); + for err in errs { + err.cancel(); + } return diff_errs; } return errs; diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 775082adbe8..fbc77f28780 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -264,14 +264,14 @@ pub(crate) fn emit_unescape_error( } EscapeError::UnskippedWhitespaceWarning => { let (c, char_span) = last_char(); - dcx.emit_warning(UnescapeError::UnskippedWhitespace { + dcx.emit_warn(UnescapeError::UnskippedWhitespace { span: err_span, ch: escaped_char(c), char_span, }); } EscapeError::MultipleSkippedLinesWarning => { - dcx.emit_warning(UnescapeError::MultipleSkippedLinesWarning(err_span)); + dcx.emit_warn(UnescapeError::MultipleSkippedLinesWarning(err_span)); } } } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f06aeed8628..b93f08a21e3 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -154,7 +154,7 @@ fn try_file_to_source_file( let msg = format!("couldn't read {}: {}", path.display(), e); let mut diag = Diagnostic::new(Level::Fatal, msg); if let Some(sp) = spanopt { - diag.set_span(sp); + diag.span(sp); } diag }) @@ -245,9 +245,9 @@ pub fn parse_cfg_attr( crate::validate_attr::check_cfg_attr_bad_delim(parse_sess, dspan, delim); match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), - Err(mut e) => { - e.help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) - .note(CFG_ATTR_NOTE_REF) + Err(e) => { + e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) + .with_note(CFG_ATTR_NOTE_REF) .emit(); } } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index fb8ad05f25d..02dab95233a 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -55,11 +55,10 @@ impl<'a> Parser<'a> { } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style != ast::AttrStyle::Outer { let span = self.token.span; - let mut err = self.dcx().struct_span_err_with_code( - span, - fluent::parse_inner_doc_comment_not_permitted, - error_code!(E0753), - ); + let mut err = self + .dcx() + .struct_span_err(span, fluent::parse_inner_doc_comment_not_permitted); + err.code(error_code!(E0753)); if let Some(replacement_span) = self.annotate_following_item_if_applicable( &mut err, span, @@ -174,7 +173,7 @@ impl<'a> Parser<'a> { ) { Ok(Some(item)) => { // FIXME(#100717) - err.set_arg("item", item.kind.descr()); + err.arg("item", item.kind.descr()); err.span_label(item.span, fluent::parse_label_does_not_annotate_this); err.span_suggestion_verbose( replacement_span, @@ -200,23 +199,25 @@ impl<'a> Parser<'a> { if let InnerAttrPolicy::Forbidden(reason) = policy { let mut diag = match reason.as_ref().copied() { Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => { - let mut diag = self.dcx().struct_span_err( - attr_sp, - fluent::parse_inner_attr_not_permitted_after_outer_doc_comment, - ); - diag.span_label(attr_sp, fluent::parse_label_attr) - .span_label(prev_doc_comment_span, fluent::parse_label_prev_doc_comment); - diag + self.dcx() + .struct_span_err( + attr_sp, + fluent::parse_inner_attr_not_permitted_after_outer_doc_comment, + ) + .with_span_label(attr_sp, fluent::parse_label_attr) + .with_span_label( + prev_doc_comment_span, + fluent::parse_label_prev_doc_comment, + ) } - Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => { - let mut diag = self.dcx().struct_span_err( + Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => self + .dcx() + .struct_span_err( attr_sp, fluent::parse_inner_attr_not_permitted_after_outer_attr, - ); - diag.span_label(attr_sp, fluent::parse_label_attr) - .span_label(prev_outer_attr_sp, fluent::parse_label_prev_attr); - diag - } + ) + .with_span_label(attr_sp, fluent::parse_label_attr) + .with_span_label(prev_outer_attr_sp, fluent::parse_label_prev_attr), Some(InnerAttrForbiddenReason::InCodeBlock) | None => { self.dcx().struct_span_err(attr_sp, fluent::parse_inner_attr_not_permitted) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 77bca2f138a..720a610fdf5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -34,8 +34,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalError, - PResult, + pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, FatalError, PErr, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -846,7 +846,7 @@ impl<'a> Parser<'a> { ) => { let n_hashes: u8 = *n_hashes; - err.set_primary_message("too many `#` when terminating raw string"); + err.primary_message("too many `#` when terminating raw string"); let str_span = self.prev_token.span; let mut span = self.token.span; let mut count = 0; @@ -857,7 +857,7 @@ impl<'a> Parser<'a> { self.bump(); count += 1; } - err.set_span(span); + err.span(span); err.span_suggestion( span, format!("remove the extra `#`{}", pluralize!(count)), @@ -896,7 +896,7 @@ impl<'a> Parser<'a> { let struct_expr = snapshot.parse_expr_struct(None, path, false); let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No); return Some(match (struct_expr, block_tail) { - (Ok(expr), Err(mut err)) => { + (Ok(expr), Err(err)) => { // We have encountered the following: // fn foo() -> Foo { // field: value, @@ -1049,9 +1049,9 @@ impl<'a> Parser<'a> { &mut self, segment: &PathSegment, end: &[&TokenKind], - ) -> bool { + ) -> Option<ErrorGuaranteed> { if !self.may_recover() { - return false; + return None; } // This function is intended to be invoked after parsing a path segment where there are two @@ -1086,7 +1086,7 @@ impl<'a> Parser<'a> { parsed_angle_bracket_args, ); if !parsed_angle_bracket_args { - return false; + return None; } // Keep the span at the start so we can highlight the sequence of `>` characters to be @@ -1124,7 +1124,7 @@ impl<'a> Parser<'a> { number_of_gt, number_of_shr, ); if number_of_gt < 1 && number_of_shr < 1 { - return false; + return None; } // Finally, double check that we have our end token as otherwise this is the @@ -1139,10 +1139,9 @@ impl<'a> Parser<'a> { let span = lo.until(self.token.span); let num_extra_brackets = number_of_gt + number_of_shr * 2; - self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }); - return true; + return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets })); } - false + None } /// Check if a method call with an intended turbofish has been written without surrounding @@ -1212,29 +1211,32 @@ impl<'a> Parser<'a> { match x { Ok((_, _, false)) => { if self.eat(&token::Gt) { + // We made sense of it. Improve the error message. e.span_suggestion_verbose( binop.span.shrink_to_lo(), fluent::parse_sugg_turbofish_syntax, "::", Applicability::MaybeIncorrect, - ) - .emit(); + ); match self.parse_expr() { Ok(_) => { + // The subsequent expression is valid. Mark + // `expr` as erroneous and emit `e` now, but + // return `Ok` so parsing can continue. + e.emit(); *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } Err(err) => { - *expr = self.mk_expr_err(expr.span); err.cancel(); } } } } + Ok((_, _, true)) => {} Err(err) => { err.cancel(); } - _ => {} } } Err(e) @@ -2041,17 +2043,12 @@ impl<'a> Parser<'a> { &mut self, delim: Delimiter, lo: Span, - result: PResult<'a, P<Expr>>, + err: PErr<'a>, ) -> P<Expr> { - match result { - Ok(x) => x, - Err(mut err) => { - err.emit(); - // Recover from parse error, callers expect the closing delim to be consumed. - self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) - } - } + err.emit(); + // Recover from parse error, callers expect the closing delim to be consumed. + self.consume_block(delim, ConsumeClosingDelim::Yes); + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) } /// Eats tokens until we can be relatively sure we reached the end of the @@ -2470,7 +2467,7 @@ impl<'a> Parser<'a> { return Ok(true); // Continue } } - Err(mut err) => { + Err(err) => { args.push(arg); // We will emit a more generic error later. err.delay_as_bug(); @@ -2848,15 +2845,16 @@ impl<'a> Parser<'a> { let label = self.eat_label().expect("just checked if a label exists"); self.bump(); // eat `:` let span = label.ident.span.to(self.prev_token.span); - let mut err = self.dcx().struct_span_err(span, "block label not supported here"); - err.span_label(span, "not supported here"); - err.tool_only_span_suggestion( - label.ident.span.until(self.token.span), - "remove this block label", - "", - Applicability::MachineApplicable, - ); - err.emit(); + self.dcx() + .struct_span_err(span, "block label not supported here") + .with_span_label(span, "not supported here") + .with_tool_only_span_suggestion( + label.ident.span.until(self.token.span), + "remove this block label", + "", + Applicability::MachineApplicable, + ) + .emit(); true } @@ -2946,7 +2944,7 @@ impl<'a> Parser<'a> { } pub fn recover_diff_marker(&mut self) { - if let Err(mut err) = self.err_diff_marker() { + if let Err(err) = self.err_diff_marker() { err.emit(); FatalError.raise(); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bf6151b64d3..8ca02452342 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> { match self.parse_expr_res(restrictions, None) { Ok(expr) => Ok(expr), - Err(mut err) => match self.token.ident() { + Err(err) => match self.token.ident() { Some((Ident { name: kw::Underscore, .. }, false)) if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { @@ -1023,7 +1023,7 @@ impl<'a> Parser<'a> { // we should break everything including floats into more basic proc-macro style // tokens in the lexer (probably preferable). // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`. - fn break_up_float(&mut self, float: Symbol) -> DestructuredFloat { + fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat { #[derive(Debug)] enum FloatComponent { IdentLike(String), @@ -1053,7 +1053,6 @@ impl<'a> Parser<'a> { // With proc macros the span can refer to anything, the source may be too short, // or too long, or non-ASCII. It only makes sense to break our span into components // if its underlying text is identical to our float literal. - let span = self.token.span; let can_take_span_apart = || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref(); @@ -1115,7 +1114,7 @@ impl<'a> Parser<'a> { float: Symbol, suffix: Option<Symbol>, ) -> P<Expr> { - match self.break_up_float(float) { + match self.break_up_float(float, self.token.span) { // 1e2 DestructuredFloat::Single(sym, _sp) => { self.parse_expr_tuple_field_access(lo, base, sym, suffix, None) @@ -1143,40 +1142,105 @@ impl<'a> Parser<'a> { } } - fn parse_field_name_maybe_tuple(&mut self) -> PResult<'a, ThinVec<Ident>> { - let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = self.token.kind - else { - return Ok(thin_vec![self.parse_field_name()?]); - }; - Ok(match self.break_up_float(symbol) { - // 1e2 - DestructuredFloat::Single(sym, sp) => { - self.bump(); - thin_vec![Ident::new(sym, sp)] - } - // 1. - DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => { - assert!(suffix.is_none()); - // Analogous to `Self::break_and_eat` - self.break_last_token = true; - // This might work, in cases like `1. 2`, and might not, - // in cases like `offset_of!(Ty, 1.)`. It depends on what comes - // after the float-like token, and therefore we have to make - // the other parts of the parser think that there is a dot literal. - self.token = Token::new(token::Ident(sym, false), sym_span); - self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing)); - thin_vec![Ident::new(sym, sym_span)] - } - // 1.2 | 1.2e3 - DestructuredFloat::MiddleDot(symbol1, ident1_span, _dot_span, symbol2, ident2_span) => { - self.bump(); - thin_vec![Ident::new(symbol1, ident1_span), Ident::new(symbol2, ident2_span)] + /// Parse the field access used in offset_of, matched by `$(e:expr)+`. + /// Currently returns a list of idents. However, it should be possible in + /// future to also do array indices, which might be arbitrary expressions. + fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> { + let mut fields = Vec::new(); + let mut trailing_dot = None; + + loop { + // This is expected to use a metavariable $(args:expr)+, but the builtin syntax + // could be called directly. Calling `parse_expr` allows this function to only + // consider `Expr`s. + let expr = self.parse_expr()?; + let mut current = &expr; + let start_idx = fields.len(); + loop { + match current.kind { + ExprKind::Field(ref left, right) => { + // Field access is read right-to-left. + fields.insert(start_idx, right); + trailing_dot = None; + current = left; + } + // Parse this both to give helpful error messages and to + // verify it can be done with this parser setup. + ExprKind::Index(ref left, ref _right, span) => { + self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span)); + current = left; + } + ExprKind::Lit(token::Lit { + kind: token::Float | token::Integer, + symbol, + suffix, + }) => { + if let Some(suffix) = suffix { + self.expect_no_tuple_index_suffix(current.span, suffix); + } + match self.break_up_float(symbol, current.span) { + // 1e2 + DestructuredFloat::Single(sym, sp) => { + trailing_dot = None; + fields.insert(start_idx, Ident::new(sym, sp)); + } + // 1. + DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => { + assert!(suffix.is_none()); + trailing_dot = Some(dot_span); + fields.insert(start_idx, Ident::new(sym, sym_span)); + } + // 1.2 | 1.2e3 + DestructuredFloat::MiddleDot( + symbol1, + span1, + _dot_span, + symbol2, + span2, + ) => { + trailing_dot = None; + fields.insert(start_idx, Ident::new(symbol2, span2)); + fields.insert(start_idx, Ident::new(symbol1, span1)); + } + DestructuredFloat::Error => { + trailing_dot = None; + fields.insert(start_idx, Ident::new(symbol, self.prev_token.span)); + } + } + break; + } + ExprKind::Path(None, Path { ref segments, .. }) => { + match &segments[..] { + [PathSegment { ident, args: None, .. }] => { + trailing_dot = None; + fields.insert(start_idx, *ident) + } + _ => { + self.dcx().emit_err(errors::InvalidOffsetOf(current.span)); + break; + } + } + break; + } + _ => { + self.dcx().emit_err(errors::InvalidOffsetOf(current.span)); + break; + } + } } - DestructuredFloat::Error => { - self.bump(); - thin_vec![Ident::new(symbol, self.prev_token.span)] + + if matches!(self.token.kind, token::CloseDelim(..) | token::Comma) { + break; + } else if trailing_dot.is_none() { + // This loop should only repeat if there is a trailing dot. + self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span)); + break; } - }) + } + if let Some(dot) = trailing_dot { + self.dcx().emit_err(errors::InvalidOffsetOf(dot)); + } + Ok(fields.into_iter().collect()) } fn parse_expr_tuple_field_access( @@ -1208,15 +1272,13 @@ impl<'a> Parser<'a> { }; let open_paren = self.token.span; - let mut seq = self + let seq = self .parse_expr_paren_seq() .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))); - if let Some(expr) = - self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot) - { - return expr; + match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) { + Ok(expr) => expr, + Err(err) => self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err), } - self.recover_seq_parse_error(Delimiter::Parenthesis, lo, seq) } /// If we encounter a parser state that looks like the user has written a `struct` literal with @@ -1226,14 +1288,11 @@ impl<'a> Parser<'a> { &mut self, lo: Span, open_paren: Span, - seq: &mut PResult<'a, P<Expr>>, + seq: PResult<'a, P<Expr>>, snapshot: Option<(SnapshotParser<'a>, ExprKind)>, - ) -> Option<P<Expr>> { - if !self.may_recover() { - return None; - } - match (seq.as_mut(), snapshot) { - (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { + ) -> PResult<'a, P<Expr>> { + match (self.may_recover(), seq, snapshot) { + (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { snapshot.bump(); // `(` match snapshot.parse_struct_fields(path.clone(), false, Delimiter::Parenthesis) { Ok((fields, ..)) @@ -1251,11 +1310,13 @@ impl<'a> Parser<'a> { if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as - // that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different. + // that of the open delim in `TokenTreesReader::parse_token_tree`, even + // if they are different. self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")") { - let mut replacement_err = - self.dcx().create_err(errors::ParenthesesWithStructFields { + err.cancel(); + self.dcx() + .create_err(errors::ParenthesesWithStructFields { span, r#type: path, braces_for_struct: errors::BracesForStructLiteral { @@ -1268,23 +1329,22 @@ impl<'a> Parser<'a> { .map(|field| field.span.until(field.expr.span)) .collect(), }, - }); - replacement_err.emit(); - - let old_err = mem::replace(err, replacement_err); - old_err.cancel(); + }) + .emit(); } else { err.emit(); } - return Some(self.mk_expr_err(span)); + Ok(self.mk_expr_err(span)) + } + Ok(_) => Err(err), + Err(err2) => { + err2.cancel(); + Err(err) } - Ok(_) => {} - Err(err) => err.cancel(), } } - _ => {} + (_, seq, _) => seq, } - None } /// Parse an indexing expression `expr[...]`. @@ -1488,7 +1548,7 @@ impl<'a> Parser<'a> { ) { Ok(x) => x, Err(err) => { - return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, Err(err))); + return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err)); } }; let kind = if es.len() == 1 && !trailing_comma { @@ -1692,9 +1752,8 @@ impl<'a> Parser<'a> { mk_lit_char: impl FnOnce(Symbol, Span) -> L, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a>, ) -> L { - if let Some(mut diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) - { - diag.span_suggestion_verbose( + if let Some(diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { + diag.with_span_suggestion_verbose( lifetime.span.shrink_to_hi(), "add `'` to close the char literal", "'", @@ -1703,7 +1762,7 @@ impl<'a> Parser<'a> { .emit(); } else { err(self) - .span_suggestion_verbose( + .with_span_suggestion_verbose( lifetime.span.shrink_to_hi(), "add `'` to close the char literal", "'", @@ -1907,15 +1966,29 @@ impl<'a> Parser<'a> { let container = self.parse_ty()?; self.expect(&TokenKind::Comma)?; - let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false }; - let (fields, _trailing, _recovered) = self.parse_seq_to_before_end( - &TokenKind::CloseDelim(Delimiter::Parenthesis), - seq_sep, - Parser::parse_field_name_maybe_tuple, - )?; - let fields = fields.into_iter().flatten().collect::<Vec<_>>(); + let fields = self.parse_floating_field_access()?; + let trailing_comma = self.eat_noexpect(&TokenKind::Comma); + + if let Err(mut e) = + self.expect_one_of(&[], &[TokenKind::CloseDelim(Delimiter::Parenthesis)]) + { + if trailing_comma { + e.note("unexpected third argument to offset_of"); + } else { + e.note("offset_of expects dot-separated field and variant names"); + } + e.emit(); + } + + // Eat tokens until the macro call ends. + if self.may_recover() { + while !matches!(self.token.kind, token::CloseDelim(..) | token::Eof) { + self.bump(); + } + } + let span = lo.to(self.token.span); - Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into()))) + Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields))) } /// Returns a string literal if the next token is a string literal. @@ -2077,7 +2150,7 @@ impl<'a> Parser<'a> { if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { // #59553: warn instead of reject out of hand to allow the fix to percolate // through the ecosystem when people fix their macros - self.dcx().emit_warning(errors::InvalidLiteralSuffixOnTupleIndex { + self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: Some(()), @@ -2411,7 +2484,7 @@ impl<'a> Parser<'a> { } ExprKind::Block(_, None) => { this.dcx().emit_err(errors::IfExpressionMissingCondition { - if_span: lo.shrink_to_hi(), + if_span: lo.with_neighbor(cond.span).shrink_to_hi(), block_span: self.sess.source_map().start_point(cond_span), }); std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) @@ -2825,7 +2898,7 @@ impl<'a> Parser<'a> { while self.token != token::CloseDelim(Delimiter::Brace) { match self.parse_arm() { Ok(arm) => arms.push(arm), - Err(mut e) => { + Err(e) => { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); @@ -3359,7 +3432,7 @@ impl<'a> Parser<'a> { } match self.parse_expr() { Ok(e) => base = ast::StructRest::Base(e), - Err(mut e) if recover => { + Err(e) if recover => { e.emit(); self.recover_stmt(); } @@ -3657,7 +3730,7 @@ impl<'a> Parser<'a> { } pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P<Expr> { - P(Expr { kind, span, attrs: AttrVec::new(), id: DUMMY_NODE_ID, tokens: None }) + self.mk_expr_with_attrs(span, kind, AttrVec::new()) } pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 7e243c1c32a..48cf04f7790 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -77,7 +77,6 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); } - err.emit(); return Err(err); } } @@ -141,17 +140,18 @@ impl<'a> Parser<'a> { // Parse optional const generics default value. let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None }; - let mut err = self.dcx().struct_span_err( - mistyped_const_ident.span, - format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()), - ); - err.span_suggestion_verbose( - mistyped_const_ident.span, - "use the `const` keyword", - kw::Const.as_str(), - Applicability::MachineApplicable, - ); - err.emit(); + self.dcx() + .struct_span_err( + mistyped_const_ident.span, + format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()), + ) + .with_span_suggestion_verbose( + mistyped_const_ident.span, + "use the `const` keyword", + kw::Const.as_str(), + Applicability::MachineApplicable, + ) + .emit(); Ok(GenericParam { ident, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0ac0b678aba..bcff820da79 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -10,7 +10,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; +use rustc_errors::{struct_span_code_err, Applicability, PResult, StashKey}; use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; use rustc_span::source_map; @@ -739,11 +739,14 @@ impl<'a> Parser<'a> { break; } Ok(Some(item)) => items.extend(item), - Err(mut err) => { + Err(err) => { self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); - err.span_label(open_brace_span, "while parsing this item list starting here") - .span_label(self.prev_token.span, "the item list ends here") - .emit(); + err.with_span_label( + open_brace_span, + "while parsing this item list starting here", + ) + .with_span_label(self.prev_token.span, "the item list ends here") + .emit(); break; } } @@ -756,14 +759,14 @@ impl<'a> Parser<'a> { if let token::DocComment(..) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) { // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585) - struct_span_err!( + struct_span_code_err!( self.dcx(), self.token.span, E0584, "found a documentation comment that doesn't document anything", ) - .span_label(self.token.span, "this doc comment doesn't document anything") - .help( + .with_span_label(self.token.span, "this doc comment doesn't document anything") + .with_help( "doc comments must come before what they document, if a comment was \ intended use `//`", ) @@ -1106,8 +1109,7 @@ impl<'a> Parser<'a> { && self.token.is_keyword(kw::Unsafe) && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace)) { - let mut err = self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err(); - err.emit(); + self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit(); unsafety = Unsafe::Yes(self.token.span); self.eat_keyword(kw::Unsafe); } @@ -1198,7 +1200,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found_err(); + let err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1216,7 +1218,7 @@ impl<'a> Parser<'a> { let before_trait = trai.path.span.shrink_to_lo(); let const_up_to_impl = const_span.with_hi(impl_span.lo()); - err.multipart_suggestion( + err.with_multipart_suggestion( "you might have meant to write a const trait impl", vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())], Applicability::MaybeIncorrect, @@ -1454,8 +1456,8 @@ impl<'a> Parser<'a> { let ident = this.parse_field_ident("enum", vlo)?; if this.token == token::Not { - if let Err(mut err) = this.unexpected::<()>() { - err.note(fluent::parse_macro_expands_to_enum_variant).emit(); + if let Err(err) = this.unexpected::<()>() { + err.with_note(fluent::parse_macro_expands_to_enum_variant).emit(); } this.bump(); @@ -1791,37 +1793,36 @@ impl<'a> Parser<'a> { } _ => { let sp = self.prev_token.span.shrink_to_hi(); - let mut err = self.dcx().struct_span_err( - sp, - format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)), - ); + let msg = + format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)); // Try to recover extra trailing angle brackets - let mut recovered = false; if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind { if let Some(last_segment) = segments.last() { - recovered = self.check_trailing_angle_brackets( + let guar = self.check_trailing_angle_brackets( last_segment, &[&token::Comma, &token::CloseDelim(Delimiter::Brace)], ); - if recovered { + if let Some(_guar) = guar { // Handle a case like `Vec<u8>>,` where we can continue parsing fields // after the comma self.eat(&token::Comma); - // `check_trailing_angle_brackets` already emitted a nicer error - // NOTE(eddyb) this was `.cancel()`, but `err` - // gets returned, so we can't fully defuse it. - err.delay_as_bug(); + + // `check_trailing_angle_brackets` already emitted a nicer error, as + // proven by the presence of `_guar`. We can continue parsing. + return Ok(a_var); } } } + let mut err = self.dcx().struct_span_err(sp, msg); + if self.token.is_ident() || (self.token.kind == TokenKind::Pound && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket)))) { - // This is likely another field, TokenKind::Pound is used for `#[..]` attribute for next field, - // emit the diagnostic and keep going + // This is likely another field, TokenKind::Pound is used for `#[..]` + // attribute for next field. Emit the diagnostic and continue parsing. err.span_suggestion( sp, "try adding a comma", @@ -1829,14 +1830,6 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.emit(); - recovered = true; - } - - if recovered { - // Make sure an error was emitted (either by recovering an angle bracket, - // or by finding an identifier as the next token), since we're - // going to continue parsing - assert!(self.dcx().has_errors().is_some()); } else { return Err(err); } @@ -1846,7 +1839,7 @@ impl<'a> Parser<'a> { } fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> { - if let Err(mut err) = self.expect(&token::Colon) { + if let Err(err) = self.expect(&token::Colon) { let sm = self.sess.source_map(); let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start()); let semi_typo = self.token.kind == token::Semi @@ -1862,7 +1855,7 @@ impl<'a> Parser<'a> { if eq_typo || semi_typo { self.bump(); // Gracefully handle small typos. - err.span_suggestion_short( + err.with_span_suggestion_short( self.prev_token.span, "field names and their types are separated with `:`", ":", @@ -1938,15 +1931,14 @@ impl<'a> Parser<'a> { Case::Insensitive, ) { Ok(_) => { - let mut err = self.dcx().struct_span_err( + self.dcx().struct_span_err( lo.to(self.prev_token.span), format!("functions are not allowed in {adt_ty} definitions"), - ); - err.help( + ) + .with_help( "unlike in C++, Java, and C#, functions are declared in `impl` blocks", - ); - err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); - err + ) + .with_help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information") } Err(err) => { err.cancel(); @@ -1956,14 +1948,15 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(kw::Struct) { match self.parse_item_struct() { - Ok((ident, _)) => { - let mut err = self.dcx().struct_span_err( + Ok((ident, _)) => self + .dcx() + .struct_span_err( lo.with_hi(ident.span.hi()), format!("structs are not allowed in {adt_ty} definitions"), - ); - err.help("consider creating a new `struct` definition instead of nesting"); - err - } + ) + .with_help( + "consider creating a new `struct` definition instead of nesting", + ), Err(err) => { err.cancel(); self.restore_snapshot(snapshot); @@ -2118,7 +2111,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); err.span_suggestion( - span.shrink_to_hi(), + span.with_neighbor(self.token.span).shrink_to_hi(), "add a semicolon", ';', Applicability::MaybeIncorrect, @@ -2598,7 +2591,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_diff_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(req_name, first_param).or_else(|mut e| { + let param = p.parse_param_general(req_name, first_param).or_else(|e| { e.emit(); let lo = p.prev_token.span; p.restore_snapshot(snapshot); @@ -2632,7 +2625,7 @@ impl<'a> Parser<'a> { let is_name_required = match this.token.kind { token::DotDotDot => false, - _ => req_name(this.token.span.edition()), + _ => req_name(this.token.span.with_neighbor(this.prev_token.span).edition()), }; let (pat, ty) = if is_name_required || this.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3932d32a6e1..ff2fb6271a8 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -499,7 +499,7 @@ impl<'a> Parser<'a> { let (ident, is_raw) = self.ident_or_err(recover)?; if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found_err(); + let err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { pprust::token_to_string(&self.prev_token) ); expect_err - .span_suggestion_verbose( + .with_span_suggestion_verbose( self.prev_token.span.shrink_to_hi().until(self.token.span), msg, " @ ", @@ -863,7 +863,7 @@ impl<'a> Parser<'a> { // Parsed successfully, therefore most probably the code only // misses a separator. expect_err - .span_suggestion_short( + .with_span_suggestion_short( sp, format!("missing `{token_str}`"), token_str, @@ -925,9 +925,8 @@ impl<'a> Parser<'a> { }); } - expect_err.set_primary_message( - "closure bodies that contain statements must be surrounded by braces", - ); + expect_err + .primary_message("closure bodies that contain statements must be surrounded by braces"); let preceding_pipe_span = closure_spans.closing_pipe; let following_token_span = self.token.span; @@ -951,7 +950,7 @@ impl<'a> Parser<'a> { ); expect_err.span_note(second_note, "the closure body may be incorrectly delimited"); - expect_err.set_span(vec![preceding_pipe_span, following_token_span]); + expect_err.span(vec![preceding_pipe_span, following_token_span]); let opening_suggestion_str = " {".to_string(); let closing_suggestion_str = "}".to_string(); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index afbc2537578..7918e03750c 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -6,7 +6,8 @@ use crate::errors::{ InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, + TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, + UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -143,7 +144,7 @@ impl<'a> Parser<'a> { // Parse the first pattern (`p_0`). let mut first_pat = match self.parse_pat_no_top_alt(expected, syntax_loc) { Ok(pat) => pat, - Err(mut err) + Err(err) if self.token.is_reserved_ident() && !self.token.is_keyword(kw::In) && !self.token.is_keyword(kw::If) => @@ -241,7 +242,7 @@ impl<'a> Parser<'a> { Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) }; - let mut err = self.dcx().create_err(match syntax_loc { + let err = self.dcx().create_err(match syntax_loc { PatternLocation::LetBinding => { TopLevelOrPatternNotAllowed::LetBinding { span, sub } } @@ -251,8 +252,9 @@ impl<'a> Parser<'a> { }); if trailing_vert { err.delay_as_bug(); + } else { + err.emit(); } - err.emit(); } Ok((pat, colon)) @@ -459,9 +461,10 @@ impl<'a> Parser<'a> { super::token_descr(&self_.token) ); - let mut err = self_.dcx().struct_span_err(self_.token.span, msg); - err.span_label(self_.token.span, format!("expected {expected}")); - err + self_ + .dcx() + .struct_span_err(self_.token.span, msg) + .with_span_label(self_.token.span, format!("expected {expected}")) }); PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { @@ -579,6 +582,8 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { + let open_paren = self.token.span; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { p.parse_pat_allow_top_alt( None, @@ -591,7 +596,29 @@ impl<'a> Parser<'a> { // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { - PatKind::Paren(fields.into_iter().next().unwrap()) + let pat = fields.into_iter().next().unwrap(); + let close_paren = self.prev_token.span; + + match &pat.kind { + // recover ranges with parentheses around the `(start)..` + PatKind::Lit(begin) + if self.may_recover() + && let Some(form) = self.parse_range_end() => + { + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, close_paren], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: close_paren, + }, + }); + + self.parse_pat_range_begin_with(begin.clone(), form)? + } + + // (pat) with optional parentheses + _ => PatKind::Paren(pat), + } } else { PatKind::Tuple(fields) }) @@ -794,11 +821,21 @@ impl<'a> Parser<'a> { || t.can_begin_literal_maybe_minus() // e.g. `42`. || t.is_whole_expr() || t.is_lifetime() // recover `'a` instead of `'a'` + || (self.may_recover() // recover leading `(` + && t.kind == token::OpenDelim(Delimiter::Parenthesis) + && self.look_ahead(dist + 1, |t| t.kind != token::OpenDelim(Delimiter::Parenthesis)) + && self.is_pat_range_end_start(dist + 1)) }) } + /// Parse a range pattern end bound fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { - if self.check_inline_const(0) { + // recover leading `(` + let open_paren = (self.may_recover() + && self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis))) + .then_some(self.prev_token.span); + + let bound = if self.check_inline_const(0) { self.parse_const_block(self.token.span, true) } else if self.check_path() { let lo = self.token.span; @@ -814,7 +851,22 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path))) } else { self.parse_literal_maybe_minus() + }?; + + // recover trailing `)` + if let Some(open_paren) = open_paren { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + + self.dcx().emit_err(UnexpectedParenInRangePat { + span: vec![open_paren, self.prev_token.span], + sugg: UnexpectedParenInRangePatSugg { + start_span: open_paren, + end_span: self.prev_token.span, + }, + }); } + + Ok(bound) } /// Is this the start of a pattern beginning with a path? @@ -978,7 +1030,7 @@ impl<'a> Parser<'a> { let attrs = match self.parse_outer_attributes() { Ok(attrs) => attrs, Err(err) => { - if let Some(mut delayed) = delayed_err { + if let Some(delayed) = delayed_err { delayed.emit(); } return Err(err); @@ -990,7 +1042,7 @@ impl<'a> Parser<'a> { if !ate_comma { let mut err = self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span }); - if let Some(mut delayed) = delayed_err { + if let Some(delayed) = delayed_err { delayed.emit(); } self.recover_misplaced_pattern_modifiers(&fields, &mut err); @@ -1063,14 +1115,14 @@ impl<'a> Parser<'a> { // This way we avoid "pattern missing fields" errors afterwards. // We delay this error until the end in order to have a span for a // suggested fix. - if let Some(mut delayed_err) = delayed_err { + if let Some(delayed_err) = delayed_err { delayed_err.emit(); return Err(err); } else { delayed_err = Some(err); } } else { - if let Some(mut err) = delayed_err { + if let Some(err) = delayed_err { err.emit(); } return Err(err); @@ -1082,7 +1134,7 @@ impl<'a> Parser<'a> { let field = match this.parse_pat_field(lo, attrs) { Ok(field) => Ok(field), Err(err) => { - if let Some(mut delayed_err) = delayed_err.take() { + if let Some(delayed_err) = delayed_err.take() { delayed_err.emit(); } return Err(err); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 4253c0ae421..e7cad74b4dd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -128,7 +128,7 @@ impl<'a> Parser<'a> { self.prev_token.span, "found single colon before projection in qualified path", ) - .span_suggestion( + .with_span_suggestion( self.prev_token.span, "use double colon", "::", @@ -493,7 +493,7 @@ impl<'a> Parser<'a> { self.angle_bracket_nesting -= 1; Ok(args) } - Err(mut e) if self.angle_bracket_nesting > 10 => { + Err(e) if self.angle_bracket_nesting > 10 => { self.angle_bracket_nesting -= 1; // When encountering severely malformed code where there are several levels of // nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 831edcd88c1..1a8bbf0a157 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -32,7 +32,7 @@ impl<'a> Parser<'a> { /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| { + Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None @@ -663,7 +663,7 @@ impl<'a> Parser<'a> { match expect_result { // Recover from parser, skip type error to avoid extra errors. Ok(true) => true, - Err(mut e) => { + Err(e) => { if self.recover_colon_as_semi() { // recover_colon_as_semi has already emitted a nicer error. e.delay_as_bug(); @@ -716,7 +716,7 @@ impl<'a> Parser<'a> { _ => {} } - if let Err(mut e) = + if let Err(e) = self.check_mistyped_turbofish_with_multiple_type_params(e, expr) { if recover.no() { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 4be2c662d03..a4fb92c67ac 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -300,7 +300,7 @@ impl<'a> Parser<'a> { let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); let kind = self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; - let mut err = self.dcx().create_err(errors::TransposeDynOrImpl { + let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), sugg: errors::TransposeDynOrImplSugg { @@ -487,7 +487,7 @@ impl<'a> Parser<'a> { fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { let elt_ty = match self.parse_ty() { Ok(ty) => ty, - Err(mut err) + Err(err) if self.look_ahead(1, |t| t.kind == token::CloseDelim(Delimiter::Bracket)) | self.look_ahead(1, |t| t.kind == token::Semi) => { @@ -1109,20 +1109,19 @@ impl<'a> Parser<'a> { lifetime_defs.append(&mut generic_params); let generic_args_span = generic_args.span(); - let mut err = self - .dcx() - .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters"); let snippet = format!( "for<{}> ", lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(), ); let before_fn_path = fn_path.span.shrink_to_lo(); - err.multipart_suggestion( - "consider using a higher-ranked trait bound instead", - vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], - Applicability::MaybeIncorrect, - ) - .emit(); + self.dcx() + .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters") + .with_multipart_suggestion( + "consider using a higher-ranked trait bound instead", + vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)], + Applicability::MaybeIncorrect, + ) + .emit(); Ok(()) } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 4efb1be03be..2fafbd6d97b 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -29,7 +29,7 @@ pub fn check_attr(sess: &ParseSess, attr: &Attribute) { _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. parse_meta(sess, attr) - .map_err(|mut err| { + .map_err(|err| { err.emit(); }) .ok(); @@ -139,7 +139,7 @@ pub fn check_builtin_attribute( ) { match parse_meta(sess, attr) { Ok(meta) => check_builtin_meta_item(sess, &meta, attr.style, name, template), - Err(mut err) => { + Err(err) => { err.emit(); } } @@ -208,7 +208,7 @@ fn emit_malformed_attribute( } else { sess.dcx .struct_span_err(span, error_msg) - .span_suggestions( + .with_span_suggestions( span, if suggestions.len() == 1 { "must be of the form" diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e886db3da29..1e1d45d6f70 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -289,10 +289,10 @@ impl<'a> Iterator for Parser<'a> { } } else { if let Some(&(_, maybe)) = self.cur.peek() { - if maybe == '?' { - self.suggest_format(); - } else { - self.suggest_positional_arg_instead_of_captured_arg(arg); + match maybe { + '?' => self.suggest_format_debug(), + '<' | '^' | '>' => self.suggest_format_align(maybe), + _ => self.suggest_positional_arg_instead_of_captured_arg(arg), } } } @@ -868,10 +868,9 @@ impl<'a> Parser<'a> { found.then_some(cur) } - fn suggest_format(&mut self) { + fn suggest_format_debug(&mut self) { if let (Some(pos), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { let word = self.word(); - let _end = self.current_pos(); let pos = self.to_span_index(pos); self.errors.insert( 0, @@ -887,6 +886,23 @@ impl<'a> Parser<'a> { } } + fn suggest_format_align(&mut self, alignment: char) { + if let Some(pos) = self.consume_pos(alignment) { + let pos = self.to_span_index(pos); + self.errors.insert( + 0, + ParseError { + description: "expected format parameter to occur after `:`".to_owned(), + note: None, + label: format!("expected `{}` to occur after `:`", alignment).to_owned(), + span: pos.to(pos), + secondary_label: None, + suggestion: Suggestion::None, + }, + ); + } + } + fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { if let Some(end) = self.consume_pos('.') { let byte_pos = self.to_span_index(end); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index be50aad1303..d41cc724408 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -575,6 +575,11 @@ passes_outside_loop = passes_outside_loop_suggestion = consider labeling this block to be able to break within it +passes_panic_unwind_without_std = + unwinding panics are not supported without std + .note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem + .help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding + passes_params_not_allowed = referencing function parameters is not allowed in naked functions .help = follow the calling convention in asm block to use parameters diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index edce99db705..e4bbc9eeaf7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2341,17 +2341,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match terr { TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => { if let Some(ty) = hir_sig.decl.inputs.get(idx) { - diag.set_span(ty.span); + diag.span(ty.span); cause.span = ty.span; } else if idx == hir_sig.decl.inputs.len() { let span = hir_sig.decl.output.span(); - diag.set_span(span); + diag.span(span); cause.span = span; } } TypeError::ArgCount => { if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) { - diag.set_span(ty.span); + diag.span(ty.span); cause.span = ty.span; } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 3e5fb1a6b47..3e3f2771f5f 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -122,7 +122,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // corresponding feature gate. This encourages nightly users to use feature gates when // possible. None if tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you => { - tcx.dcx().emit_warning(SkippingConstChecks { span }); + tcx.dcx().emit_warn(SkippingConstChecks { span }); return; } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 22aac1e775e..ac2ca23ad41 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -15,8 +15,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{DEAD_CODE, UNUSED_TUPLE_STRUCT_FIELDS}; -use rustc_session::lint::{self, Lint, LintId}; +use rustc_session::lint; +use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::FieldIdx; use std::mem; @@ -766,6 +766,12 @@ enum ShouldWarnAboutField { No, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum ReportOn { + TupleField, + NamedField, +} + impl<'tcx> DeadVisitor<'tcx> { fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutField { if self.live_symbols.contains(&field.did.expect_local()) { @@ -787,9 +793,9 @@ impl<'tcx> DeadVisitor<'tcx> { ShouldWarnAboutField::Yes } - fn def_lint_level(&self, lint: &'static Lint, id: LocalDefId) -> lint::Level { + fn def_lint_level(&self, id: LocalDefId) -> lint::Level { let hir_id = self.tcx.local_def_id_to_hir_id(id); - self.tcx.lint_level_at_node(lint, hir_id).0 + self.tcx.lint_level_at_node(DEAD_CODE, hir_id).0 } // # Panics @@ -803,7 +809,7 @@ impl<'tcx> DeadVisitor<'tcx> { dead_codes: &[&DeadItem], participle: &str, parent_item: Option<LocalDefId>, - lint: &'static Lint, + report_on: ReportOn, ) { let Some(&first_item) = dead_codes.first() else { return; @@ -864,8 +870,8 @@ impl<'tcx> DeadVisitor<'tcx> { None }; - let diag = if LintId::of(lint) == LintId::of(UNUSED_TUPLE_STRUCT_FIELDS) { - MultipleDeadCodes::UnusedTupleStructFields { + let diag = match report_on { + ReportOn::TupleField => MultipleDeadCodes::UnusedTupleStructFields { multiple, num, descr, @@ -874,9 +880,9 @@ impl<'tcx> DeadVisitor<'tcx> { change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() }, parent_info, ignored_derived_impls, - } - } else { - MultipleDeadCodes::DeadCodes { + }, + + ReportOn::NamedField => MultipleDeadCodes::DeadCodes { multiple, num, descr, @@ -884,11 +890,11 @@ impl<'tcx> DeadVisitor<'tcx> { name_list, parent_info, ignored_derived_impls, - } + }, }; let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id); - self.tcx.emit_spanned_lint(lint, hir_id, MultiSpan::from_spans(spans), diag); + self.tcx.emit_spanned_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); } fn warn_multiple( @@ -896,7 +902,7 @@ impl<'tcx> DeadVisitor<'tcx> { def_id: LocalDefId, participle: &str, dead_codes: Vec<DeadItem>, - lint: &'static Lint, + report_on: ReportOn, ) { let mut dead_codes = dead_codes .iter() @@ -907,7 +913,7 @@ impl<'tcx> DeadVisitor<'tcx> { } dead_codes.sort_by_key(|v| v.level); for group in dead_codes[..].group_by(|a, b| a.level == b.level) { - self.lint_at_single_level(&group, participle, Some(def_id), lint); + self.lint_at_single_level(&group, participle, Some(def_id), report_on); } } @@ -915,9 +921,9 @@ impl<'tcx> DeadVisitor<'tcx> { let item = DeadItem { def_id: id, name: self.tcx.item_name(id.to_def_id()), - level: self.def_lint_level(DEAD_CODE, id), + level: self.def_lint_level(id), }; - self.lint_at_single_level(&[&item], participle, None, DEAD_CODE); + self.lint_at_single_level(&[&item], participle, None, ReportOn::NamedField); } fn check_definition(&mut self, def_id: LocalDefId) { @@ -964,12 +970,12 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_id = item.id.owner_id.def_id; if !visitor.is_live_code(def_id) { let name = tcx.item_name(def_id.to_def_id()); - let level = visitor.def_lint_level(DEAD_CODE, def_id); + let level = visitor.def_lint_level(def_id); dead_items.push(DeadItem { def_id, name, level }) } } - visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, DEAD_CODE); + visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, ReportOn::NamedField); } if !live_symbols.contains(&item.owner_id.def_id) { @@ -991,7 +997,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_id = variant.def_id.expect_local(); if !live_symbols.contains(&def_id) { // Record to group diagnostics. - let level = visitor.def_lint_level(DEAD_CODE, def_id); + let level = visitor.def_lint_level(def_id); dead_variants.push(DeadItem { def_id, name: variant.name, level }); continue; } @@ -999,24 +1005,30 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let is_positional = variant.fields.raw.first().map_or(false, |field| { field.name.as_str().starts_with(|c: char| c.is_ascii_digit()) }); - let lint = if is_positional { UNUSED_TUPLE_STRUCT_FIELDS } else { DEAD_CODE }; + let report_on = + if is_positional { ReportOn::TupleField } else { ReportOn::NamedField }; let dead_fields = variant .fields .iter() .filter_map(|field| { let def_id = field.did.expect_local(); if let ShouldWarnAboutField::Yes = visitor.should_warn_about_field(field) { - let level = visitor.def_lint_level(lint, def_id); + let level = visitor.def_lint_level(def_id); Some(DeadItem { def_id, name: field.name, level }) } else { None } }) .collect(); - visitor.warn_multiple(def_id, "read", dead_fields, lint); + visitor.warn_multiple(def_id, "read", dead_fields, report_on); } - visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, DEAD_CODE); + visitor.warn_multiple( + item.owner_id.def_id, + "constructed", + dead_variants, + ReportOn::NamedField, + ); } } diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index f4cd2fbc91f..42e929bde2c 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -48,7 +48,7 @@ impl DebuggerVisualizerCollector<'_> { let file = match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) { Ok(file) => file, - Err(mut err) => { + Err(err) => { err.emit(); return; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 856256a0641..cf3c7cc4ace 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -813,6 +813,12 @@ pub struct UnknownExternLangItem { pub struct MissingPanicHandler; #[derive(Diagnostic)] +#[diag(passes_panic_unwind_without_std)] +#[help] +#[note] +pub struct PanicUnwindWithoutStd; + +#[derive(Diagnostic)] #[diag(passes_missing_lang_item)] #[note] #[help] @@ -868,8 +874,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_invalid_attr_at_crate_level); - diag.set_span(self.span); - diag.set_arg("name", self.name); + diag.span(self.span); + diag.arg("name", self.name); // Only emit an error with a suggestion if we can create a string out // of the attribute span if let Some(span) = self.sugg_span { @@ -881,7 +887,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel { ); } if let Some(item) = self.item { - diag.set_arg("kind", item.kind); + diag.arg("kind", item.kind); diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item); } diag @@ -1018,9 +1024,9 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_break_non_loop); - diag.set_span(self.span); + diag.span(self.span); diag.code(error_code!(E0571)); - diag.set_arg("kind", self.kind); + diag.arg("kind", self.kind); diag.span_label(self.span, fluent::passes_label); if let Some(head) = self.head { diag.span_label(head, fluent::passes_label2); @@ -1040,7 +1046,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'_, G> for BreakNonLoop<'a> { // This error is redundant, we will have already emitted a // suggestion to use the label when `segment` wasn't found // (hence the `Res::Err` check). - diag.delay_as_bug(); + diag.downgrade_to_delayed_bug(); } _ => { diag.span_suggestion( @@ -1162,7 +1168,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] fn into_diagnostic(self, dcx: &DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_naked_functions_asm_block); - diag.set_span(self.span); + diag.span(self.span); diag.code(error_code!(E0787)); for span in self.multiple_asms.iter() { diag.span_label(*span, fluent::passes_label_multiple_asm); @@ -1273,11 +1279,11 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::passes_no_main_function); - diag.set_span(DUMMY_SP); + diag.span(DUMMY_SP); diag.code(error_code!(E0601)); - diag.set_arg("crate_name", self.crate_name); - diag.set_arg("filename", self.filename); - diag.set_arg("has_filename", self.has_filename); + diag.arg("crate_name", self.crate_name); + diag.arg("filename", self.filename); + diag.arg("has_filename", self.has_filename); let note = if !self.non_main_fns.is_empty() { for &span in &self.non_main_fns { diag.span_note(span, fluent::passes_here_is_main); @@ -1294,7 +1300,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for NoMainErr { if self.file_empty { diag.note(note); } else { - diag.set_span(self.sp.shrink_to_hi()); + diag.span(self.sp.shrink_to_hi()); diag.span_label(self.sp.shrink_to_hi(), note); } @@ -1340,15 +1346,15 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for DuplicateLangItem { }, ); diag.code(error_code!(E0152)); - diag.set_arg("lang_item_name", self.lang_item_name); - diag.set_arg("crate_name", self.crate_name); - diag.set_arg("dependency_of", self.dependency_of); - diag.set_arg("path", self.path); - diag.set_arg("orig_crate_name", self.orig_crate_name); - diag.set_arg("orig_dependency_of", self.orig_dependency_of); - diag.set_arg("orig_path", self.orig_path); + diag.arg("lang_item_name", self.lang_item_name); + diag.arg("crate_name", self.crate_name); + diag.arg("dependency_of", self.dependency_of); + diag.arg("path", self.path); + diag.arg("orig_crate_name", self.orig_crate_name); + diag.arg("orig_dependency_of", self.orig_dependency_of); + diag.arg("orig_path", self.orig_path); if let Some(span) = self.local_span { - diag.set_span(span); + diag.span(span); } if let Some(span) = self.first_defined_span { diag.span_note(span, fluent::passes_first_defined_span); diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 0727bad7c5a..02f56ecb10b 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -31,7 +31,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if !errors.is_empty() { let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - tcx.dcx().span_delayed_bug(rustc_span::DUMMY_SP, message); + tcx.dcx().delayed_bug(message); } } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index cfe829f170f..92687c705ae 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -98,7 +98,6 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::DUMMY_SP; use rustc_span::{BytePos, Span}; use std::io; @@ -351,10 +350,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { - self.add_from_pat(arm.pat); - if let Some(hir::Guard::IfLet(let_expr)) = arm.guard { - self.add_from_pat(let_expr.pat); - } + self.add_from_pat(&arm.pat); intravisit::walk_arm(self, arm); } @@ -563,7 +559,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match self.successors[ln] { Some(successor) => self.assigned_on_entry(successor, var), None => { - self.ir.tcx.dcx().span_delayed_bug(DUMMY_SP, "no successor"); + self.ir.tcx.dcx().delayed_bug("no successor"); true } } @@ -921,14 +917,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for arm in arms { let body_succ = self.propagate_through_expr(arm.body, succ); - let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g { - hir::Guard::If(e) => self.propagate_through_expr(e, body_succ), - hir::Guard::IfLet(let_expr) => { - let let_bind = self.define_bindings_in_pat(let_expr.pat, body_succ); - self.propagate_through_expr(let_expr.init, let_bind) - } - }); - let arm_succ = self.define_bindings_in_pat(arm.pat, guard_succ); + let guard_succ = arm + .guard + .as_ref() + .map_or(body_succ, |g| self.propagate_through_expr(g, body_succ)); + let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); self.merge_from_succ(ln, arm_succ); } self.propagate_through_expr(e, ln) @@ -1328,9 +1321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.check_unused_vars_in_pat(arm.pat, None, None, |_, _, _, _| {}); - if let Some(hir::Guard::IfLet(let_expr)) = arm.guard { - self.check_unused_vars_in_pat(let_expr.pat, None, None, |_, _, _, _| {}); - } intravisit::walk_arm(self, arm); } } @@ -1630,7 +1620,7 @@ impl<'tcx> Liveness<'_, 'tcx> { let from_macro = non_shorthands .iter() .find(|(_, pat_span, ident_span)| { - pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion() + !pat_span.eq_ctxt(*ident_span) && pat_span.from_expansion() }) .map(|(_, pat_span, _)| *pat_span); let non_shorthands = non_shorthands diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 87fdedc15ba..18b9ba0f042 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,7 +6,8 @@ use rustc_attr::{ self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, Unstable, UnstableReason, VERSION_PLACEHOLDER, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, LocalModDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -923,7 +924,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } let declared_lang_features = &tcx.features().declared_lang_features; - let mut lang_features = FxHashSet::default(); + let mut lang_features = UnordSet::default(); for &(feature, span, since) in declared_lang_features { if let Some(since) = since { // Warn if the user has enabled an already-stable lang feature. @@ -980,11 +981,11 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { fn check_features<'tcx>( tcx: TyCtxt<'tcx>, remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, - remaining_implications: &mut FxHashMap<Symbol, Symbol>, + remaining_implications: &mut UnordMap<Symbol, Symbol>, defined_features: &LibFeatures, - all_implications: &FxHashMap<Symbol, Symbol>, + all_implications: &UnordMap<Symbol, Symbol>, ) { - for (feature, since) in defined_features.to_vec() { + for (feature, since) in defined_features.to_sorted_vec() { if let FeatureStability::AcceptedSince(since) = since && let Some(span) = remaining_lib_features.get(&feature) { @@ -1021,7 +1022,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // `remaining_lib_features`. let mut all_implications = remaining_implications.clone(); for &cnum in tcx.crates(()) { - all_implications.extend(tcx.stability_implications(cnum)); + all_implications + .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v))); } check_features( @@ -1050,10 +1052,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature }); } - // We only use the hash map contents to emit errors, and the order of - // emitted errors do not affect query stability. - #[allow(rustc::potential_query_instability)] - for (implied_by, feature) in remaining_implications { + for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() { let local_defined_features = tcx.lib_features(LOCAL_CRATE); let span = local_defined_features .stability diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index db3d442676e..4eb0c6c275e 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -9,7 +9,9 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem}; +use crate::errors::{ + MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem, +}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. @@ -76,6 +78,8 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() { if item == LangItem::PanicImpl { tcx.dcx().emit_err(MissingPanicHandler); + } else if item == LangItem::EhPersonality { + tcx.dcx().emit_err(PanicUnwindWithoutStd); } else { tcx.dcx().emit_err(MissingLangItem { name: item.name() }); } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index e01b571ede1..b52643adcc9 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -24,6 +24,8 @@ use std::fmt; use rustc_index::Idx; #[cfg(feature = "rustc")] use rustc_middle::ty::Ty; +#[cfg(feature = "rustc")] +use rustc_span::ErrorGuaranteed; use crate::constructor::{Constructor, ConstructorSet}; #[cfg(feature = "rustc")] @@ -52,6 +54,8 @@ impl<'a, T: ?Sized> Captures<'a> for T {} pub trait TypeCx: Sized + fmt::Debug { /// The type of a pattern. type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy + /// Errors that can abort analysis. + type Error: fmt::Debug; /// The index of an enum variant. type VariantIdx: Clone + Idx; /// A string literal @@ -61,8 +65,6 @@ pub trait TypeCx: Sized + fmt::Debug { /// Extra data to store in a pattern. type PatData: Clone; - /// FIXME(Nadrieril): `Cx` should only give us revealed types. - fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty; fn is_exhaustive_patterns_feature_on(&self) -> bool; /// The number of fields for this constructor. @@ -75,7 +77,7 @@ pub trait TypeCx: Sized + fmt::Debug { /// The set of all the constructors for `ty`. /// /// This must follow the invariants of `ConstructorSet` - fn ctors_for_ty(&self, ty: Self::Ty) -> ConstructorSet<Self>; + fn ctors_for_ty(&self, ty: Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>; /// Best-effort `Debug` implementation. fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result; @@ -111,24 +113,25 @@ pub fn analyze_match<'p, 'tcx>( tycx: &RustcMatchCheckCtxt<'p, 'tcx>, arms: &[rustc::MatchArm<'p, 'tcx>], scrut_ty: Ty<'tcx>, -) -> rustc::UsefulnessReport<'p, 'tcx> { +) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> { // Arena to store the extra wildcards we construct during analysis. let wildcard_arena = tycx.pattern_arena; + let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee); let cx = MatchCtxt { tycx, wildcard_arena }; - let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity); + let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?; let pat_column = PatternColumn::new(arms); // Lint on ranges that overlap on their endpoints, which is likely a mistake. - lint_overlapping_range_endpoints(cx, &pat_column); + lint_overlapping_range_endpoints(cx, &pat_column)?; // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() { - lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty) + lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?; } - report + Ok(report) } diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index cb712fe640c..52c9af85006 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -1,21 +1,21 @@ use smallvec::SmallVec; use rustc_data_structures::captures::Captures; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use rustc_session::lint; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use crate::constructor::{IntRange, MaybeInfiniteInt}; use crate::errors::{ NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap, OverlappingRangeEndpoints, Uncovered, }; +use crate::pat::PatOrWild; use crate::rustc::{ - Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RustcMatchCheckCtxt, + Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt, SplitConstructorSet, WitnessPat, }; -use crate::TypeCx; /// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that /// inspect the same subvalue/place". @@ -24,9 +24,9 @@ use crate::TypeCx; /// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential /// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately. /// -/// This must not contain an or-pattern. `specialize` takes care to expand them. +/// This must not contain an or-pattern. `expand_and_push` takes care to expand them. /// -/// This is not used in the main algorithm; only in lints. +/// This is not used in the usefulness algorithm; only in lints. #[derive(Debug)] pub(crate) struct PatternColumn<'p, 'tcx> { patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>, @@ -34,34 +34,38 @@ pub(crate) struct PatternColumn<'p, 'tcx> { impl<'p, 'tcx> PatternColumn<'p, 'tcx> { pub(crate) fn new(arms: &[MatchArm<'p, 'tcx>]) -> Self { - let mut patterns = Vec::with_capacity(arms.len()); + let patterns = Vec::with_capacity(arms.len()); + let mut column = PatternColumn { patterns }; for arm in arms { - if arm.pat.is_or_pat() { - patterns.extend(arm.pat.flatten_or_pat()) - } else { - patterns.push(arm.pat) - } + column.expand_and_push(PatOrWild::Pat(arm.pat)); } - Self { patterns } - } - - fn is_empty(&self) -> bool { - self.patterns.is_empty() + column } - fn head_ty(&self, cx: MatchCtxt<'_, 'p, 'tcx>) -> Option<Ty<'tcx>> { - if self.patterns.len() == 0 { - return None; + /// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns. + /// Internal method, prefer [`PatternColumn::new`]. + fn expand_and_push(&mut self, pat: PatOrWild<'p, RustcMatchCheckCtxt<'p, 'tcx>>) { + // We flatten or-patterns and skip algorithm-generated wildcards. + if pat.is_or_pat() { + self.patterns.extend( + pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()), + ) + } else if let Some(pat) = pat.as_pat() { + self.patterns.push(pat) } + } - let ty = self.patterns[0].ty(); - // FIXME(Nadrieril): `Cx` should only give us revealed types. - Some(cx.tycx.reveal_opaque_ty(ty)) + fn head_ty(&self) -> Option<RevealedTy<'tcx>> { + self.patterns.first().map(|pat| pat.ty()) } /// Do constructor splitting on the constructors of the column. - fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> { + fn analyze_ctors( + &self, + pcx: &PlaceCtxt<'_, 'p, 'tcx>, + ) -> Result<SplitConstructorSet<'p, 'tcx>, ErrorGuaranteed> { let column_ctors = self.patterns.iter().map(|p| p.ctor()); - pcx.ctors_for_ty().split(pcx, column_ctors) + let ctors_for_ty = &pcx.ctors_for_ty()?; + Ok(ctors_for_ty.split(pcx, column_ctors)) } fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'_> { @@ -91,21 +95,11 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { let relevant_patterns = self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); for pat in relevant_patterns { - let specialized = pat.specialize(pcx, ctor); - for (subpat, column) in specialized.iter().zip(&mut specialized_columns) { - if subpat.is_or_pat() { - column.patterns.extend(subpat.flatten_or_pat()) - } else { - column.patterns.push(subpat) - } + let specialized = pat.specialize(ctor, arity); + for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) { + column.expand_and_push(subpat); } } - - assert!( - !specialized_columns[0].is_empty(), - "ctor {ctor:?} was listed as present but isn't; - there is an inconsistency between `Constructor::is_covered_by` and `ConstructorSet::split`" - ); specialized_columns } } @@ -116,18 +110,18 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( cx: MatchCtxt<'a, 'p, 'tcx>, column: &PatternColumn<'p, 'tcx>, -) -> Vec<WitnessPat<'p, 'tcx>> { - let Some(ty) = column.head_ty(cx) else { - return Vec::new(); +) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> { + let Some(ty) = column.head_ty() else { + return Ok(Vec::new()); }; let pcx = &PlaceCtxt::new_dummy(cx, ty); - let set = column.analyze_ctors(pcx); + let set = column.analyze_ctors(pcx)?; if set.present.is_empty() { // We can't consistently handle the case where no constructors are present (since this would // require digging deep through any type in case there's a non_exhaustive enum somewhere), // so for consistency we refuse to handle the top-level case, where we could handle it. - return vec![]; + return Ok(Vec::new()); } let mut witnesses = Vec::new(); @@ -147,7 +141,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor); for (i, col_i) in specialized_columns.iter().enumerate() { // Compute witnesses for each column. - let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i); + let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i)?; // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`, // adding enough wildcards to match `arity`. for wit in wits_for_col_i { @@ -157,21 +151,21 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( } } } - witnesses + Ok(witnesses) } pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( cx: MatchCtxt<'a, 'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], pat_column: &PatternColumn<'p, 'tcx>, - scrut_ty: Ty<'tcx>, -) { + scrut_ty: RevealedTy<'tcx>, +) -> Result<(), ErrorGuaranteed> { let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx; if !matches!( rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0, rustc_session::lint::Level::Allow ) { - let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column); + let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column)?; if !witnesses.is_empty() { // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. @@ -182,7 +176,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( rcx.match_lint_level, rcx.scrut_span, NonExhaustiveOmittedPattern { - scrut_ty, + scrut_ty: scrut_ty.inner(), uncovered: Uncovered::new(rcx.scrut_span, rcx, witnesses), }, ); @@ -204,12 +198,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( use rustc_errors::DecorateLint; let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().unwrap().span, ""); - err.set_primary_message(decorator.msg()); + err.primary_message(decorator.msg()); decorator.decorate_lint(&mut err); err.emit(); } } } + Ok(()) } /// Traverse the patterns to warn the user about ranges that overlap on their endpoints. @@ -217,14 +212,14 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>( pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>( cx: MatchCtxt<'a, 'p, 'tcx>, column: &PatternColumn<'p, 'tcx>, -) { - let Some(ty) = column.head_ty(cx) else { - return; +) -> Result<(), ErrorGuaranteed> { + let Some(ty) = column.head_ty() else { + return Ok(()); }; let pcx = &PlaceCtxt::new_dummy(cx, ty); let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx; - let set = column.analyze_ctors(pcx); + let set = column.analyze_ctors(pcx)?; if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) { let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| { @@ -281,8 +276,9 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>( // Recurse into the fields. for ctor in set.present { for col in column.specialize(pcx, &ctor) { - lint_overlapping_range_endpoints(cx, &col); + lint_overlapping_range_endpoints(cx, &col)?; } } } + Ok(()) } diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index db41d2824a1..2f5dc241cb7 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -50,14 +50,6 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { pub(crate) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } - /// Expand this (possibly-nested) or-pattern into its alternatives. - pub(crate) fn flatten_or_pat(&self) -> SmallVec<[&Self; 1]> { - if self.is_or_pat() { - self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect() - } else { - smallvec![self] - } - } pub fn ctor(&self) -> &Constructor<Cx> { &self.ctor @@ -79,16 +71,10 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { /// `other_ctor` can be different from `self.ctor`, but must be covered by it. pub(crate) fn specialize( &self, - pcx: &PlaceCtxt<'_, 'p, Cx>, other_ctor: &Constructor<Cx>, - ) -> SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]> { - let wildcard_sub_tys = || { - let tys = pcx.ctor_sub_tys(other_ctor); - tys.iter() - .map(|ty| DeconstructedPat::wildcard(*ty)) - .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_) - .collect() - }; + ctor_arity: usize, + ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect(); match (&self.ctor, other_ctor) { // Return a wildcard for each field of `other_ctor`. (Wildcard, _) => wildcard_sub_tys(), @@ -104,14 +90,15 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { // Fill in the fields from both ends. let new_arity = fields.len(); for i in 0..prefix { - fields[i] = &self.fields[i]; + fields[i] = PatOrWild::Pat(&self.fields[i]); } for i in 0..suffix { - fields[new_arity - 1 - i] = &self.fields[self.fields.len() - 1 - i]; + fields[new_arity - 1 - i] = + PatOrWild::Pat(&self.fields[self.fields.len() - 1 - i]); } fields } - _ => self.fields.iter().collect(), + _ => self.fields.iter().map(PatOrWild::Pat).collect(), } } @@ -152,14 +139,86 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> { } } -/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a -/// `Display` impl. +/// This is best effort and not good enough for a `Display` impl. impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Cx::debug_pat(f, self) } } +/// Represents either a pattern obtained from user input or a wildcard constructed during the +/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input. +/// +/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard. +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""))] +pub(crate) enum PatOrWild<'p, Cx: TypeCx> { + /// A non-user-provided wildcard, created during specialization. + Wild, + /// A user-provided pattern. + Pat(&'p DeconstructedPat<'p, Cx>), +} + +impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { + pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { + match self { + PatOrWild::Wild => None, + PatOrWild::Pat(pat) => Some(pat), + } + } + pub(crate) fn ctor(self) -> &'p Constructor<Cx> { + match self { + PatOrWild::Wild => &Wildcard, + PatOrWild::Pat(pat) => pat.ctor(), + } + } + + pub(crate) fn is_or_pat(&self) -> bool { + match self { + PatOrWild::Wild => false, + PatOrWild::Pat(pat) => pat.is_or_pat(), + } + } + + /// Expand this (possibly-nested) or-pattern into its alternatives. + pub(crate) fn flatten_or_pat(self) -> SmallVec<[Self; 1]> { + match self { + PatOrWild::Pat(pat) if pat.is_or_pat() => { + pat.iter_fields().flat_map(|p| PatOrWild::Pat(p).flatten_or_pat()).collect() + } + _ => smallvec![self], + } + } + + /// Specialize this pattern with a constructor. + /// `other_ctor` can be different from `self.ctor`, but must be covered by it. + pub(crate) fn specialize( + &self, + other_ctor: &Constructor<Cx>, + ctor_arity: usize, + ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> { + match self { + PatOrWild::Wild => (0..ctor_arity).map(|_| PatOrWild::Wild).collect(), + PatOrWild::Pat(pat) => pat.specialize(other_ctor, ctor_arity), + } + } + + pub(crate) fn set_useful(&self) { + if let PatOrWild::Pat(pat) = self { + pat.set_useful() + } + } +} + +impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PatOrWild::Wild => write!(f, "_"), + PatOrWild::Pat(pat) => pat.fmt(f), + } + } +} + /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics /// purposes. As such they don't use interning and can be cloned. #[derive(derivative::Derivative)] diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index b09d565f076..a8d1bece613 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -12,7 +12,9 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef}; +use rustc_span::ErrorGuaranteed; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT}; use smallvec::SmallVec; @@ -41,6 +43,30 @@ pub type UsefulnessReport<'p, 'tcx> = crate::usefulness::UsefulnessReport<'p, RustcMatchCheckCtxt<'p, 'tcx>>; pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, 'tcx>>; +/// A type which has gone through `cx.reveal_opaque_ty`, i.e. if it was opaque it was replaced by +/// the hidden type if allowed in the current body. This ensures we consistently inspect the hidden +/// types when we should. +/// +/// Use `.inner()` or deref to get to the `Ty<'tcx>`. +#[repr(transparent)] +#[derive(derivative::Derivative)] +#[derive(Clone, Copy)] +#[derivative(Debug = "transparent")] +pub struct RevealedTy<'tcx>(Ty<'tcx>); + +impl<'tcx> std::ops::Deref for RevealedTy<'tcx> { + type Target = Ty<'tcx>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'tcx> RevealedTy<'tcx> { + pub fn inner(self) -> Ty<'tcx> { + self.0 + } +} + #[derive(Clone)] pub struct RustcMatchCheckCtxt<'p, 'tcx> { pub tcx: TyCtxt<'tcx>, @@ -74,20 +100,48 @@ impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> { } impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { - fn reveal_opaque(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> { + /// Type inference occasionally gives us opaque types in places where corresponding patterns + /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited + /// types, we use the corresponding concrete type if possible. + #[inline] + pub fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> RevealedTy<'tcx> { + fn reveal_inner<'tcx>( + cx: &RustcMatchCheckCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + ) -> RevealedTy<'tcx> { + let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!() }; + if let Some(local_def_id) = alias_ty.def_id.as_local() { + let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args }; + if let Some(ty) = cx.reveal_opaque_key(key) { + return RevealedTy(ty); + } + } + RevealedTy(ty) + } + if let ty::Alias(ty::Opaque, _) = ty.kind() { + reveal_inner(self, ty) + } else { + RevealedTy(ty) + } + } + + /// Returns the hidden type corresponding to this key if the body under analysis is allowed to + /// know it. + fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> { self.typeck_results.concrete_opaque_types.get(&key).map(|x| x.ty) } + // This can take a non-revealed `Ty` because it reveals opaques itself. pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { !ty.inhabited_predicate(self.tcx).apply_revealing_opaque( self.tcx, self.param_env, self.module, - &|key| self.reveal_opaque(key), + &|key| self.reveal_opaque_key(key), ) } /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. - pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { + pub fn is_foreign_non_exhaustive_enum(&self, ty: RevealedTy<'tcx>) -> bool { match ty.kind() { ty::Adt(def, ..) => { def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local() @@ -98,7 +152,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// Whether the range denotes the fictitious values before `isize::MIN` or after /// `usize::MAX`/`isize::MAX` (see doc of [`IntRange::split`] for why these exist). - pub fn is_range_beyond_boundaries(&self, range: &IntRange, ty: Ty<'tcx>) -> bool { + pub fn is_range_beyond_boundaries(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> bool { ty.is_ptr_sized_integral() && { // The two invalid ranges are `NegInfinity..isize::MIN` (represented as // `NegInfinity..0`), and `{u,i}size::MAX+1..PosInfinity`. `hoist_pat_range_bdy` @@ -110,29 +164,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } } - /// Type inference occasionally gives us opaque types in places where corresponding patterns - /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited - /// types, we use the corresponding concrete type if possible. - fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() { - if let Some(local_def_id) = alias_ty.def_id.as_local() { - let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args }; - if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) { - return real_ty.ty; - } - } - } - ty - } - // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. // This lists the fields we keep along with their types. pub(crate) fn list_variant_nonhidden_fields( &self, - ty: Ty<'tcx>, + ty: RevealedTy<'tcx>, variant: &'tcx VariantDef, - ) -> impl Iterator<Item = (FieldIdx, Ty<'tcx>)> + Captures<'p> + Captures<'_> { + ) -> impl Iterator<Item = (FieldIdx, RevealedTy<'tcx>)> + Captures<'p> + Captures<'_> { let cx = self; let ty::Adt(adt, args) = ty.kind() else { bug!() }; // Whether we must not match the fields of this variant exhaustively. @@ -148,6 +187,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { if is_uninhabited && (!is_visible || is_non_exhaustive) { None } else { + let ty = cx.reveal_opaque_ty(ty); Some((FieldIdx::new(i), ty)) } }) @@ -170,16 +210,26 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// Returns the types of the fields for a given constructor. The result must have a length of /// `ctor.arity()`. #[instrument(level = "trace", skip(self))] - pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<'p, 'tcx>, ty: Ty<'tcx>) -> &[Ty<'tcx>] { + pub(crate) fn ctor_sub_tys( + &self, + ctor: &Constructor<'p, 'tcx>, + ty: RevealedTy<'tcx>, + ) -> &[RevealedTy<'tcx>] { + fn reveal_and_alloc<'a, 'tcx>( + cx: &'a RustcMatchCheckCtxt<'_, 'tcx>, + iter: impl Iterator<Item = Ty<'tcx>>, + ) -> &'a [RevealedTy<'tcx>] { + cx.dropless_arena.alloc_from_iter(iter.map(|ty| cx.reveal_opaque_ty(ty))) + } let cx = self; match ctor { Struct | Variant(_) | UnionField => match ty.kind() { - ty::Tuple(fs) => cx.dropless_arena.alloc_from_iter(fs.iter()), + ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()), ty::Adt(adt, args) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - cx.dropless_arena.alloc_from_iter(once(args.type_at(0))) + reveal_and_alloc(cx, once(args.type_at(0))) } else { let variant = &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt)); @@ -190,13 +240,13 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, Ref => match ty.kind() { - ty::Ref(_, rty, _) => cx.dropless_arena.alloc_from_iter(once(*rty)), + ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)), _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"), }, Slice(slice) => match *ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - cx.dropless_arena.alloc_from_iter((0..arity).map(|_| ty)) + reveal_and_alloc(cx, (0..arity).map(|_| ty)) } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, @@ -217,7 +267,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } /// The number of fields for this constructor. - pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: Ty<'tcx>) -> usize { + pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>) -> usize { match ctor { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => fs.len(), @@ -254,7 +304,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { /// /// See [`crate::constructor`] for considerations of emptiness. #[instrument(level = "debug", skip(self), ret)] - pub fn ctors_for_ty(&self, ty: Ty<'tcx>) -> ConstructorSet<'p, 'tcx> { + pub fn ctors_for_ty( + &self, + ty: RevealedTy<'tcx>, + ) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> { let cx = self; let make_uint_range = |start, end| { IntRange::from_range( @@ -263,9 +316,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { RangeEnd::Included, ) }; + // Abort on type error. + ty.error_reported()?; // This determines the set of all possible constructors for the type `ty`. For numbers, // arrays and slices we use ranges and variable-length slices when appropriate. - match ty.kind() { + Ok(match ty.kind() { ty::Bool => ConstructorSet::Bool, ty::Char => { // The valid Unicode Scalar Value ranges. @@ -328,7 +383,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { .inhabited_predicate(cx.tcx, *def) .instantiate(cx.tcx, args) .apply_revealing_opaque(cx.tcx, cx.param_env, cx.module, &|key| { - cx.reveal_opaque(key) + cx.reveal_opaque_key(key) }); // Variants that depend on a disabled unstable feature. let is_unstable = matches!( @@ -353,7 +408,9 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } } ty::Adt(def, _) if def.is_union() => ConstructorSet::Union, - ty::Adt(..) | ty::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(ty) }, + ty::Adt(..) | ty::Tuple(..) => { + ConstructorSet::Struct { empty: cx.is_uninhabited(ty.inner()) } + } ty::Ref(..) => ConstructorSet::Ref, ty::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. @@ -373,13 +430,13 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => { bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}") } - } + }) } pub(crate) fn lower_pat_range_bdy( &self, bdy: PatRangeBoundary<'tcx>, - ty: Ty<'tcx>, + ty: RevealedTy<'tcx>, ) -> MaybeInfiniteInt { match bdy { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, @@ -402,6 +459,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat)); let cx = self; + let ty = cx.reveal_opaque_ty(pat.ty); let ctor; let fields: &[_]; match &pat.kind { @@ -414,19 +472,22 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } PatKind::Deref { subpattern } => { fields = singleton(self.lower_pat(subpattern)); - ctor = match pat.ty.kind() { + ctor = match ty.kind() { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, ty::Ref(..) => Ref, - _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty), + _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), }; } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { - match pat.ty.kind() { + match ty.kind() { ty::Tuple(fs) => { ctor = Struct; - let mut wilds: SmallVec<[_; 2]> = - fs.iter().map(|ty| DeconstructedPat::wildcard(ty)).collect(); + let mut wilds: SmallVec<[_; 2]> = fs + .iter() + .map(|ty| cx.reveal_opaque_ty(ty)) + .map(|ty| DeconstructedPat::wildcard(ty)) + .collect(); for pat in subpatterns { wilds[pat.field.index()] = self.lower_pat(&pat.pattern); } @@ -449,7 +510,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { let pat = if let Some(pat) = pattern { self.lower_pat(&pat.pattern) } else { - DeconstructedPat::wildcard(args.type_at(0)) + DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0))) }; ctor = Struct; fields = singleton(pat); @@ -466,13 +527,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // For each field in the variant, we store the relevant index into `self.fields` if any. let mut field_id_to_id: Vec<Option<usize>> = (0..variant.fields.len()).map(|_| None).collect(); - let tys = cx - .list_variant_nonhidden_fields(pat.ty, variant) - .enumerate() - .map(|(i, (field, ty))| { + let tys = cx.list_variant_nonhidden_fields(ty, variant).enumerate().map( + |(i, (field, ty))| { field_id_to_id[field.index()] = Some(i); ty - }); + }, + ); let mut wilds: SmallVec<[_; 2]> = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); for pat in subpatterns { @@ -482,11 +542,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } fields = cx.pattern_arena.alloc_from_iter(wilds); } - _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty), + _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), } } PatKind::Constant { value } => { - match pat.ty.kind() { + match ty.kind() { ty::Bool => { ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { Some(b) => Bool(b), @@ -497,7 +557,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { Some(bits) => { - let x = match *pat.ty.kind() { + let x = match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); MaybeInfiniteInt::new_finite_int(bits, size) @@ -540,7 +600,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { // `Ref`), and has one field. That field has constructor `Str(value)` and no // subfields. // Note: `t` is `str`, not `&str`. - let subpattern = DeconstructedPat::new(Str(*value), &[], *t, pat); + let ty = self.reveal_opaque_ty(*t); + let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat); ctor = Ref; fields = singleton(subpattern) } @@ -559,7 +620,6 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { rustc_hir::RangeEnd::Included => RangeEnd::Included, rustc_hir::RangeEnd::Excluded => RangeEnd::Excluded, }; - let ty = pat.ty; ctor = match ty.kind() { ty::Char | ty::Int(_) | ty::Uint(_) => { let lo = cx.lower_pat_range_bdy(*lo, ty); @@ -585,17 +645,17 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } } } - _ => bug!("invalid type for range pattern: {}", ty), + _ => bug!("invalid type for range pattern: {}", ty.inner()), }; fields = &[]; } PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { - let array_len = match pat.ty.kind() { + let array_len = match ty.kind() { ty::Array(_, length) => { Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize) } ty::Slice(_) => None, - _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), + _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", ty), }; let kind = if slice.is_some() { SliceKind::VarLen(prefix.len(), suffix.len()) @@ -624,7 +684,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { fields = &[]; } } - DeconstructedPat::new(ctor, fields, pat.ty, pat) + DeconstructedPat::new(ctor, fields, ty, pat) } /// Convert back to a `thir::PatRangeBoundary` for diagnostic purposes. @@ -634,7 +694,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { pub(crate) fn hoist_pat_range_bdy( &self, miint: MaybeInfiniteInt, - ty: Ty<'tcx>, + ty: RevealedTy<'tcx>, ) -> PatRangeBoundary<'tcx> { use MaybeInfiniteInt::*; let tcx = self.tcx; @@ -648,7 +708,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { }; match Scalar::try_from_uint(bits, size) { Some(scalar) => { - let value = mir::Const::from_scalar(tcx, scalar, ty); + let value = mir::Const::from_scalar(tcx, scalar, ty.inner()); PatRangeBoundary::Finite(value) } // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value @@ -662,7 +722,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } /// Convert back to a `thir::Pat` for diagnostic purposes. - pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: Ty<'tcx>) -> Pat<'tcx> { + pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> { use MaybeInfiniteInt::*; let cx = self; let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) { @@ -693,10 +753,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { range.hi.minus_one() }; let hi = cx.hoist_pat_range_bdy(hi, ty); - PatKind::Range(Box::new(PatRange { lo, hi, end, ty })) + PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() })) }; - Pat { ty, span: DUMMY_SP, kind } + Pat { ty: ty.inner(), span: DUMMY_SP, kind } } /// Convert back to a `thir::Pat` for diagnostic purposes. This panics for patterns that don't /// appear in diagnostics, like float ranges. @@ -768,7 +828,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } } let suffix: Box<[_]> = subpatterns.collect(); - let wild = Pat::wildcard_from_ty(pat.ty()); + let wild = Pat::wildcard_from_ty(pat.ty().inner()); PatKind::Slice { prefix: prefix.into_boxed_slice(), slice: Some(Box::new(wild)), @@ -788,7 +848,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } }; - Pat { ty: pat.ty(), span: DUMMY_SP, kind } + Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind } } /// Best-effort `Debug` implementation. @@ -890,7 +950,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { - type Ty = Ty<'tcx>; + type Ty = RevealedTy<'tcx>; + type Error = ErrorGuaranteed; type VariantIdx = VariantIdx; type StrLit = Const<'tcx>; type ArmData = HirId; @@ -900,10 +961,6 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { self.tcx.features().exhaustive_patterns } - fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.reveal_opaque_ty(ty) - } - fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: Self::Ty) -> usize { self.ctor_arity(ctor, ty) } @@ -914,7 +971,10 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { ) -> &[Self::Ty] { self.ctor_sub_tys(ctor, ty) } - fn ctors_for_ty(&self, ty: Self::Ty) -> crate::constructor::ConstructorSet<Self> { + fn ctors_for_ty( + &self, + ty: Self::Ty, + ) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> { self.ctors_for_ty(ty) } diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index d2e621a6b98..b4935d280e6 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -716,8 +716,8 @@ use smallvec::{smallvec, SmallVec}; use std::fmt; use crate::constructor::{Constructor, ConstructorSet}; -use crate::pat::{DeconstructedPat, WitnessPat}; -use crate::{Captures, MatchArm, MatchCtxt, TypeCx, TypedArena}; +use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; +use crate::{Captures, MatchArm, MatchCtxt, TypeCx}; use self::ValidityConstraint::*; @@ -753,7 +753,7 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> { pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] { self.mcx.tycx.ctor_sub_tys(ctor, self.ty) } - pub(crate) fn ctors_for_ty(&self) -> ConstructorSet<Cx> { + pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> { self.mcx.tycx.ctors_for_ty(self.ty) } } @@ -827,7 +827,7 @@ impl fmt::Display for ValidityConstraint { #[derivative(Clone(bound = ""))] struct PatStack<'p, Cx: TypeCx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. - pats: SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]>, + pats: SmallVec<[PatOrWild<'p, Cx>; 2]>, /// Sometimes we know that as far as this row is concerned, the current case is already handled /// by a different, more general, case. When the case is irrelevant for all rows this allows us /// to skip a case entirely. This is purely an optimization. See at the top for details. @@ -836,7 +836,7 @@ struct PatStack<'p, Cx: TypeCx> { impl<'p, Cx: TypeCx> PatStack<'p, Cx> { fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self { - PatStack { pats: smallvec![pat], relevant: true } + PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true } } fn is_empty(&self) -> bool { @@ -847,11 +847,11 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { self.pats.len() } - fn head(&self) -> &'p DeconstructedPat<'p, Cx> { + fn head(&self) -> PatOrWild<'p, Cx> { self.pats[0] } - fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> { + fn iter(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Captures<'_> { self.pats.iter().copied() } @@ -869,13 +869,13 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. fn pop_head_constructor( &self, - pcx: &PlaceCtxt<'_, 'p, Cx>, ctor: &Constructor<Cx>, + ctor_arity: usize, ctor_is_relevant: bool, ) -> PatStack<'p, Cx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_pats = self.head().specialize(pcx, ctor); + let mut new_pats = self.head().specialize(ctor, ctor_arity); new_pats.extend_from_slice(&self.pats[1..]); // `ctor` is relevant for this row if it is the actual constructor of this row, or if the // row has a wildcard and `ctor` is relevant for wildcards. @@ -922,11 +922,11 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> { self.pats.len() } - fn head(&self) -> &'p DeconstructedPat<'p, Cx> { + fn head(&self) -> PatOrWild<'p, Cx> { self.pats.head() } - fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> { + fn iter(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Captures<'_> { self.pats.iter() } @@ -945,13 +945,13 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> { /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. fn pop_head_constructor( &self, - pcx: &PlaceCtxt<'_, 'p, Cx>, ctor: &Constructor<Cx>, + ctor_arity: usize, ctor_is_relevant: bool, parent_row: usize, ) -> MatrixRow<'p, Cx> { MatrixRow { - pats: self.pats.pop_head_constructor(pcx, ctor, ctor_is_relevant), + pats: self.pats.pop_head_constructor(ctor, ctor_arity, ctor_is_relevant), parent_row, is_under_guard: self.is_under_guard, useful: false, @@ -981,11 +981,13 @@ struct Matrix<'p, Cx: TypeCx> { /// each column must have the same type. Each column corresponds to a place within the /// scrutinee. rows: Vec<MatrixRow<'p, Cx>>, - /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of - /// each column. This must obey the same invariants as the real rows. - wildcard_row: PatStack<'p, Cx>, + /// Track the type of each column/place. + place_ty: SmallVec<[Cx::Ty; 2]>, /// Track for each column/place whether it contains a known valid value. place_validity: SmallVec<[ValidityConstraint; 2]>, + /// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top + /// of the file for details on relevancy. + wildcard_row_is_relevant: bool, } impl<'p, Cx: TypeCx> Matrix<'p, Cx> { @@ -1004,17 +1006,15 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { /// Build a new matrix from an iterator of `MatchArm`s. fn new( - wildcard_arena: &'p TypedArena<DeconstructedPat<'p, Cx>>, arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Self { - let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); - let wildcard_row = PatStack::from_pattern(wild_pattern); let mut matrix = Matrix { rows: Vec::with_capacity(arms.len()), - wildcard_row, + place_ty: smallvec![scrut_ty], place_validity: smallvec![scrut_validity], + wildcard_row_is_relevant: true, }; for (row_id, arm) in arms.iter().enumerate() { let v = MatrixRow { @@ -1028,17 +1028,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { matrix } - fn head_ty(&self, mcx: MatchCtxt<'_, 'p, Cx>) -> Option<Cx::Ty> { - if self.column_count() == 0 { - return None; - } - - let ty = self.wildcard_row.head().ty(); - // FIXME(Nadrieril): `Cx` should only give us revealed types. - Some(mcx.tycx.reveal_opaque_ty(ty)) + fn head_ty(&self) -> Option<Cx::Ty> { + self.place_ty.first().copied() } fn column_count(&self) -> usize { - self.wildcard_row.len() + self.place_ty.len() } fn rows( @@ -1055,7 +1049,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { } /// Iterate over the first pattern of each row. - fn heads(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Clone + Captures<'_> { + fn heads(&self) -> impl Iterator<Item = PatOrWild<'p, Cx>> + Clone + Captures<'_> { self.rows().map(|r| r.head()) } @@ -1066,17 +1060,24 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { ctor: &Constructor<Cx>, ctor_is_relevant: bool, ) -> Matrix<'p, Cx> { - let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, ctor_is_relevant); - let new_validity = self.place_validity[0].specialize(ctor); - let new_place_validity = std::iter::repeat(new_validity) - .take(ctor.arity(pcx)) + let ctor_sub_tys = pcx.ctor_sub_tys(ctor); + let arity = ctor_sub_tys.len(); + let specialized_place_ty = + ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).copied().collect(); + let ctor_sub_validity = self.place_validity[0].specialize(ctor); + let specialized_place_validity = std::iter::repeat(ctor_sub_validity) + .take(arity) .chain(self.place_validity[1..].iter().copied()) .collect(); - let mut matrix = - Matrix { rows: Vec::new(), wildcard_row, place_validity: new_place_validity }; + let mut matrix = Matrix { + rows: Vec::new(), + place_ty: specialized_place_ty, + place_validity: specialized_place_validity, + wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant, + }; for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx, ctor, ctor_is_relevant, i); + let new_row = row.pop_head_constructor(ctor, arity, ctor_is_relevant, i); matrix.expand_and_push(new_row); } } @@ -1335,17 +1336,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( mcx: MatchCtxt<'a, 'p, Cx>, matrix: &mut Matrix<'p, Cx>, is_top_level: bool, -) -> WitnessMatrix<Cx> { +) -> Result<WitnessMatrix<Cx>, Cx::Error> { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); - if !matrix.wildcard_row.relevant && matrix.rows().all(|r| !r.pats.relevant) { + if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) { // Here we know that nothing will contribute further to exhaustiveness or usefulness. This // is purely an optimization: skipping this check doesn't affect correctness. See the top of // the file for details. - return WitnessMatrix::empty(); + return Ok(WitnessMatrix::empty()); } - let Some(ty) = matrix.head_ty(mcx) else { + let Some(ty) = matrix.head_ty() else { // The base case: there are no columns in the matrix. We are morally pattern-matching on (). // A row is useful iff it has no (unguarded) rows above it. for row in matrix.rows_mut() { @@ -1354,16 +1355,16 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // When there's an unguarded row, the match is exhaustive and any subsequent row is not // useful. if !row.is_under_guard { - return WitnessMatrix::empty(); + return Ok(WitnessMatrix::empty()); } } // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless // irrelevant. - return if matrix.wildcard_row.relevant { - WitnessMatrix::unit_witness() + return if matrix.wildcard_row_is_relevant { + Ok(WitnessMatrix::unit_witness()) } else { // We choose to not report anything here; see at the top for details. - WitnessMatrix::empty() + Ok(WitnessMatrix::empty()) }; }; @@ -1377,7 +1378,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // Analyze the constructors present in this column. let ctors = matrix.heads().map(|p| p.ctor()); - let ctors_for_ty = pcx.ctors_for_ty(); + let ctors_for_ty = pcx.ctors_for_ty()?; let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics. let split_set = ctors_for_ty.split(pcx, ctors); let all_missing = split_set.present.is_empty(); @@ -1416,7 +1417,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant); let mut witnesses = ensure_sufficient_stack(|| { compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false) - }); + })?; // Transform witnesses for `spec_matrix` into witnesses for `matrix`. witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors); @@ -1437,7 +1438,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( } } - ret + Ok(ret) } /// Indicates whether or not a given arm is useful. @@ -1468,9 +1469,10 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, -) -> UsefulnessReport<'p, Cx> { - let mut matrix = Matrix::new(cx.wildcard_arena, arms, scrut_ty, scrut_validity); - let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true); +) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> { + let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); + let non_exhaustiveness_witnesses = + compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?; let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); let arm_usefulness: Vec<_> = arms @@ -1487,5 +1489,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( (arm, usefulness) }) .collect(); - UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } + Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }) } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d5883f52819..b5e8ac4018d 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -35,7 +35,7 @@ use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap, + get_query_incr, get_query_non_incr, CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState, }; use rustc_query_system::HandleCycleError; @@ -144,10 +144,10 @@ where fn value_from_cycle_error( self, tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo], + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value { - (self.dynamic.value_from_cycle_error)(tcx, cycle, guar) + (self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar) } #[inline(always)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f131a0f7593..a827717d9bb 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -69,7 +69,7 @@ impl QueryContext for QueryCtxt<'_> { fn next_job_id(self) -> QueryJobId { QueryJobId( NonZeroU64::new( - self.query_system.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed), + self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed), ) .unwrap(), ) @@ -342,9 +342,9 @@ pub(crate) fn create_query_frame< hasher.finish::<Hash64>() }) }; - let ty_adt_id = key.ty_adt_id(); + let ty_def_id = key.ty_def_id(); - QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash) + QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_def_id, hash) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 9b06823dfba..1f09de0ed70 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -4,7 +4,7 @@ use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerR use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc}; use rustc_data_structures::unord::UnordMap; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; @@ -13,7 +13,7 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; -use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::Ordering; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; @@ -476,7 +476,7 @@ impl<D: Deps> DepGraph<D> { let task_deps = &mut *task_deps; if cfg!(debug_assertions) { - data.current.total_read_count.fetch_add(1, Relaxed); + data.current.total_read_count.fetch_add(1, Ordering::Relaxed); } // As long as we only have a low number of reads we can avoid doing a hash @@ -506,7 +506,7 @@ impl<D: Deps> DepGraph<D> { } } } else if cfg!(debug_assertions) { - data.current.total_duplicate_read_count.fetch_add(1, Relaxed); + data.current.total_duplicate_read_count.fetch_add(1, Ordering::Relaxed); } }) } @@ -976,8 +976,8 @@ impl<D: Deps> DepGraph<D> { pub fn print_incremental_info(&self) { if let Some(data) = &self.data { data.current.encoder.borrow().print_incremental_info( - data.current.total_read_count.load(Relaxed), - data.current.total_duplicate_read_count.load(Relaxed), + data.current.total_read_count.load(Ordering::Relaxed), + data.current.total_duplicate_read_count.load(Ordering::Relaxed), ) } } @@ -992,7 +992,7 @@ impl<D: Deps> DepGraph<D> { pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { debug_assert!(self.data.is_none()); - let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); + let index = self.virtual_dep_node_index.fetch_add(1, Ordering::Relaxed); DepNodeIndex::from_u32(index) } } diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index c025fac2631..958d9fdb52a 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -5,7 +5,7 @@ use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::DepNodeIndex; -use crate::query::{QueryContext, QueryInfo, QueryState}; +use crate::query::{CycleError, QueryContext, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; @@ -57,7 +57,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle: &[QueryInfo], + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 982b9ee94da..3ef9de7da74 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -556,7 +556,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { #[inline(never)] #[cold] -pub(crate) fn report_cycle<'a>( +pub fn report_cycle<'a>( sess: &'a Session, CycleError { usage, cycle: stack }: &CycleError, ) -> DiagnosticBuilder<'a> { diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 96a0c7a033a..9ff04c4e910 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -4,7 +4,9 @@ pub use self::plumbing::*; mod job; #[cfg(parallel_compiler)] pub use self::job::deadlock; -pub use self::job::{print_query_stack, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap}; +pub use self::job::{ + print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, +}; mod caches; pub use self::caches::{ @@ -33,7 +35,8 @@ pub struct QueryStackFrame { span: Option<Span>, pub def_id: Option<DefId>, pub def_kind: Option<DefKind>, - pub ty_adt_id: Option<DefId>, + /// A def-id that is extracted from a `Ty` in a query key + pub ty_def_id: Option<DefId>, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. @@ -49,7 +52,7 @@ impl QueryStackFrame { def_id: Option<DefId>, def_kind: Option<DefKind>, dep_kind: DepKind, - ty_adt_id: Option<DefId>, + ty_def_id: Option<DefId>, _hash: impl FnOnce() -> Hash64, ) -> Self { Self { @@ -57,7 +60,7 @@ impl QueryStackFrame { span, def_id, def_kind, - ty_adt_id, + ty_def_id, dep_kind, #[cfg(parallel_compiler)] hash: _hash(), diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 51842664eeb..3bb2cc5634f 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -124,7 +124,7 @@ fn handle_cycle_error<Q, Qcx>( query: Q, qcx: Qcx, cycle_error: &CycleError, - mut error: DiagnosticBuilder<'_>, + error: DiagnosticBuilder<'_>, ) -> Q::Value where Q: QueryConfig<Qcx>, @@ -134,7 +134,7 @@ where match query.handle_cycle_error() { Error => { let guar = error.emit(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } Fatal => { error.emit(); @@ -143,7 +143,7 @@ where } DelayBug => { let guar = error.delay_as_bug(); - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } Stash => { let guar = if let Some(root) = cycle_error.cycle.first() @@ -154,7 +154,7 @@ where } else { error.emit() }; - query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + query.value_from_cycle_error(*qcx.dep_context(), cycle_error, guar) } } } @@ -211,7 +211,7 @@ where } #[derive(Clone, Debug)] -pub(crate) struct CycleError { +pub struct CycleError { /// The query and related span that uses the cycle. pub usage: Option<(Span, QueryStackFrame)>, pub cycle: Vec<QueryInfo>, @@ -431,17 +431,14 @@ where // We have an inconsistency. This can happen if one of the two // results is tainted by errors. In this case, delay a bug to // ensure compilation is doomed. - qcx.dep_context().sess().dcx().span_delayed_bug( - DUMMY_SP, - format!( - "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ + qcx.dep_context().sess().dcx().delayed_bug(format!( + "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ computed={:#?}\nfed={:#?}", - query.dep_kind(), - key, - formatter(&result), - formatter(&cached_result), - ), - ); + query.dep_kind(), + key, + formatter(&result), + formatter(&cached_result), + )); } } } diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs index 4f1c182cdb8..133904f59af 100644 --- a/compiler/rustc_query_system/src/values.rs +++ b/compiler/rustc_query_system/src/values.rs @@ -1,20 +1,21 @@ use rustc_span::ErrorGuaranteed; use crate::dep_graph::DepContext; -use crate::query::QueryInfo; +use crate::query::CycleError; pub trait Value<Tcx: DepContext>: Sized { - fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self; + fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, guar: ErrorGuaranteed) -> Self; } impl<Tcx: DepContext, T> Value<Tcx> for T { - default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T { + default fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed) -> T { tcx.sess().dcx().abort_if_errors(); // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // non-trivial to define it earlier. panic!( - "<{} as Value>::from_cycle_error called without errors: {cycle:#?}", - std::any::type_name::<T>() + "<{} as Value>::from_cycle_error called without errors: {:#?}", + std::any::type_name::<T>(), + cycle_error.cycle, ); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4e1fda5479c..9ccfde5e3c6 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,7 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_code_err, Applicability}; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; @@ -818,7 +818,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r .dcx() .struct_span_err(item.span, "`extern crate self;` requires renaming") - .span_suggestion( + .with_span_suggestion( item.span, "rename the `self` crate to be able to import it", "extern crate self as name;", @@ -999,7 +999,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = format!("`{name}` is already in scope"); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.r.dcx().struct_span_err(span, msg).note(note).emit(); + self.r.dcx().struct_span_err(span, msg).with_note(note).emit(); } } @@ -1010,7 +1010,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { for attr in &item.attrs { if attr.has_name(sym::macro_use) { if self.parent_scope.module.parent.is_some() { - struct_span_err!( + struct_span_code_err!( self.r.dcx(), item.span, E0468, @@ -1024,7 +1024,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } let ill_formed = |span| { - struct_span_err!(self.r.dcx(), span, E0466, "bad macro import").emit(); + struct_span_code_err!(self.r.dcx(), span, E0466, "bad macro import").emit(); }; match attr.meta() { Some(meta) => match meta.kind { @@ -1095,8 +1095,13 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { allow_shadowing, ); } else { - struct_span_err!(self.r.dcx(), ident.span, E0469, "imported macro not found") - .emit(); + struct_span_code_err!( + self.r.dcx(), + ident.span, + E0469, + "imported macro not found" + ) + .emit(); } } } @@ -1110,10 +1115,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`"; let mut err = self.r.dcx().struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { - err.help("try an outer attribute: `#[macro_use]`").emit(); - } else { - err.emit(); + err.help("try an outer attribute: `#[macro_use]`"); } + err.emit(); } else if !attr.has_name(sym::macro_use) { continue; } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 3b1f957c890..0e43a35ce73 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -20,7 +20,7 @@ // separate step to be able to collapse the adjacent spans that rustfix // will remove // -// - `check_crate` finally emits the diagnostics based on the data generated +// - `check_unused` finally emits the diagnostics based on the data generated // in the last step use crate::imports::ImportKind; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8743b734926..0d744238eeb 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,7 +6,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, report_ambiguity_error, struct_span_err, Applicability, DiagCtxt, Diagnostic, + pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -100,6 +100,8 @@ pub(crate) struct ImportSuggestion { pub descr: &'static str, pub path: Path, pub accessible: bool, + // false if the path traverses a foreign `#[doc(hidden)]` item. + pub doc_visible: bool, pub via_import: bool, /// An extra note that should be issued if this item is suggested pub note: Option<String>, @@ -151,7 +153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { BuiltinLintDiagnostics::AmbiguousGlobImports { diag }, ); } else { - let mut err = struct_span_err!(self.dcx(), diag.span, E0659, "{}", &diag.msg); + let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", &diag.msg); report_ambiguity_error(&mut err, diag); err.emit(); } @@ -252,15 +254,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("the name `{name}` is defined multiple times"); let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { - (true, true) => struct_span_err!(self.dcx(), span, E0259, "{}", msg), + (true, true) => struct_span_code_err!(self.dcx(), span, E0259, "{}", msg), (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() { - true => struct_span_err!(self.dcx(), span, E0254, "{}", msg), - false => struct_span_err!(self.dcx(), span, E0260, "{}", msg), + true => struct_span_code_err!(self.dcx(), span, E0254, "{}", msg), + false => struct_span_code_err!(self.dcx(), span, E0260, "{}", msg), }, _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { - (false, false) => struct_span_err!(self.dcx(), span, E0428, "{}", msg), - (true, true) => struct_span_err!(self.dcx(), span, E0252, "{}", msg), - _ => struct_span_err!(self.dcx(), span, E0255, "{}", msg), + (false, false) => struct_span_code_err!(self.dcx(), span, E0428, "{}", msg), + (true, true) => struct_span_code_err!(self.dcx(), span, E0252, "{}", msg), + _ => struct_span_code_err!(self.dcx(), span, E0255, "{}", msg), }, }; @@ -657,7 +659,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let origin_sp = origin.iter().copied().collect::<Vec<_>>(); let msp = MultiSpan::from_spans(target_sp.clone()); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), msp, E0408, @@ -786,7 +788,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } ResolutionError::FailedToResolve { last_segment, label, suggestion, module } => { let mut err = - struct_span_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label); + struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label); err.span_label(span, label); if let Some((suggestions, msg, applicability)) = suggestion { @@ -942,16 +944,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_item_span, trait_path, } => { - let mut err = self.dcx().struct_span_err_with_code( + self.dcx().struct_span_err( span, format!( "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`", ), - code, - ); - err.span_label(span, "does not match trait"); - err.span_label(trait_item_span, "item in trait"); - err + ) + .with_code(code) + .with_span_label(span, "does not match trait") + .with_span_label(trait_item_span, "item in trait") } ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self .dcx() @@ -1146,10 +1147,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { let mut candidates = Vec::new(); let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(start_module, ThinVec::<ast::PathSegment>::new(), true)]; + let start_did = start_module.def_id(); + let mut worklist = vec![( + start_module, + ThinVec::<ast::PathSegment>::new(), + true, + start_did.is_local() || !self.tcx.is_doc_hidden(start_did), + )]; let mut worklist_via_import = vec![]; - while let Some((in_module, path_segments, accessible)) = match worklist.pop() { + while let Some((in_module, path_segments, accessible, doc_visible)) = match worklist.pop() { None => worklist_via_import.pop(), Some(x) => Some(x), } { @@ -1192,6 +1199,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + let res = name_binding.res(); + let did = match res { + Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did), + _ => res.opt_def_id(), + }; + let child_doc_visible = doc_visible + && (did.map_or(true, |did| did.is_local() || !this.tcx.is_doc_hidden(did))); + // collect results based on the filter function // avoid suggesting anything from the same module in which we are resolving // avoid suggesting anything with a hygienic name @@ -1200,7 +1215,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && in_module != parent_scope.module && !ident.span.normalize_to_macros_2_0().from_expansion() { - let res = name_binding.res(); if filter_fn(res) { // create the path let mut segms = if lookup_ident.span.at_least_rust_2018() { @@ -1214,10 +1228,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; - let did = match res { - Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did), - _ => res.opt_def_id(), - }; if child_accessible { // Remove invisible match if exists @@ -1257,6 +1267,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { descr: res.descr(), path, accessible: child_accessible, + doc_visible: child_doc_visible, note, via_import, }); @@ -1277,7 +1288,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // add the module to the lookup if seen_modules.insert(module.def_id()) { if via_import { &mut worklist_via_import } else { &mut worklist } - .push((module, path_segments, child_accessible)); + .push((module, path_segments, child_accessible, child_doc_visible)); } } } @@ -1691,8 +1702,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Print the primary message. let descr = get_descr(binding); - let mut err = - struct_span_err!(self.dcx(), ident.span, E0603, "{} `{}` is private", descr, ident); + let mut err = struct_span_code_err!( + self.dcx(), + ident.span, + E0603, + "{} `{}` is private", + descr, + ident + ); err.span_label(ident.span, format!("private {descr}")); let mut not_publicly_reexported = false; @@ -2687,8 +2704,26 @@ fn show_candidates( Vec::new(); candidates.iter().for_each(|c| { - (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) - .push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) + if c.accessible { + // Don't suggest `#[doc(hidden)]` items from other crates + if c.doc_visible { + accessible_path_strings.push(( + pprust::path_to_string(&c.path), + c.descr, + c.did, + &c.note, + c.via_import, + )) + } + } else { + inaccessible_path_strings.push(( + pprust::path_to_string(&c.path), + c.descr, + c.did, + &c.note, + c.via_import, + )) + } }); // we want consistent results across executions, but candidates are produced @@ -2787,9 +2822,7 @@ fn show_candidates( err.help(msg); } true - } else if !matches!(mode, DiagnosticMode::Import) { - assert!(!inaccessible_path_strings.is_empty()); - + } else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagnosticMode::Import)) { let prefix = if let DiagnosticMode::Pattern = mode { "you might have meant to match on " } else { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 97297662200..2ebf4c20562 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -17,7 +17,7 @@ use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult}; use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; use rustc_middle::metadata::Reexport; @@ -686,7 +686,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .collect::<Vec<_>>(); let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),); - let mut diag = struct_span_err!(self.dcx(), span, E0432, "{}", &msg); + let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{}", &msg); if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() { diag.note(note.clone()); @@ -1233,7 +1233,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); } else { if ns == TypeNS { - let mut err = if crate_private_reexport { + let err = if crate_private_reexport { self.dcx().create_err(CannotBeReexportedCratePublicNS { span: import.span, ident, @@ -1371,12 +1371,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { - self.dcx().create_err(CannotGlobImportAllCrates { span: import.span }).emit(); + self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span }); return; }; if module.is_trait() { - self.dcx().create_err(ItemsInTraitsAreNotImportable { span: import.span }).emit(); + self.dcx().emit_err(ItemsInTraitsAreNotImportable { span: import.span }); return; } else if module == import.parent_scope.module { return; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c3026e52430..4a3c8dfe3d7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1664,7 +1664,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } else { ("`'_` cannot be used here", "`'_` is a reserved lifetime name") }; - let mut diag = rustc_errors::struct_span_err!( + let mut diag = rustc_errors::struct_span_code_err!( self.r.dcx(), lifetime.ident.span, E0637, @@ -1853,7 +1853,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } | LifetimeRibKind::AnonymousWarn(_) => { let sess = self.r.tcx.sess; - let mut err = rustc_errors::struct_span_err!( + let mut err = rustc_errors::struct_span_code_err!( sess.dcx(), path_span, E0726, @@ -2301,7 +2301,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_error = |this: &Self, ns| { if this.should_report_errs() { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.dcx().create_err(ImportsCannotReferTo { span: ident.span, what }).emit(); + this.r.dcx().emit_err(ImportsCannotReferTo { span: ident.span, what }); } }; @@ -2594,13 +2594,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::UnderscoreLifetime { - rustc_errors::struct_span_err!( + rustc_errors::struct_span_code_err!( self.r.dcx(), param.ident.span, E0637, "`'_` cannot be used here" ) - .span_label(param.ident.span, "`'_` is a reserved lifetime name") + .with_span_label(param.ident.span, "`'_` is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); @@ -2608,14 +2608,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } if param.ident.name == kw::StaticLifetime { - rustc_errors::struct_span_err!( + rustc_errors::struct_span_code_err!( self.r.dcx(), param.ident.span, E0262, "invalid lifetime parameter name: `{}`", param.ident, ) - .span_label(param.ident.span, "'static is a reserved lifetime name") + .with_span_label(param.ident.span, "'static is a reserved lifetime name") .emit(); // Record lifetime res, so lowering knows there is something fishy. self.record_lifetime_param(param.id, LifetimeRes::Error); @@ -3076,7 +3076,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } let feed_visibility = |this: &mut Self, def_id| { - let vis = this.r.tcx.visibility(def_id).expect_local(); + let vis = this.r.tcx.visibility(def_id); + let vis = if vis.is_visible_locally() { + vis.expect_local() + } else { + this.r.dcx().span_delayed_bug( + span, + "error should be emitted when an unexpected trait item is used", + ); + rustc_middle::ty::Visibility::Public + }; this.r.feed_visibility(this.r.local_def_id(id), vis); }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9bd58dfe82b..2f476ae6cbc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,7 +16,7 @@ use rustc_ast::{ use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_hir as hir; @@ -429,8 +429,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let base_error = self.make_base_error(path, span, source, res); let code = source.error_code(res.is_some()); - let mut err = - self.r.dcx().struct_span_err_with_code(base_error.span, base_error.msg.clone(), code); + let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone()); + err.code(code); self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); @@ -1383,7 +1383,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { | PathSource::TupleStruct(span, _) => { // We want the main underline to cover the suggested code as well for // cleaner output. - err.set_span(*span); + err.span(*span); *span } _ => span, @@ -1615,7 +1615,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let field_spans = match source { // e.g. `if let Enum::TupleVariant(field1, field2) = _` PathSource::TupleStruct(_, pattern_spans) => { - err.set_primary_message( + err.primary_message( "cannot match against a tuple struct which contains private fields", ); @@ -1628,7 +1628,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { span: call_span, .. })) => { - err.set_primary_message( + err.primary_message( "cannot initialize a tuple struct which contains private fields", ); self.suggest_alternative_construction_methods( @@ -1755,11 +1755,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter_map(|item| { // Only assoc fns that return `Self` let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder(); - let ret_ty = fn_sig.output(); - let ret_ty = self - .r - .tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), ret_ty); + // Don't normalize the return type, because that can cause cycle errors. + let ret_ty = fn_sig.output().skip_binder(); let ty::Adt(def, _args) = ret_ty.kind() else { return None; }; @@ -2191,15 +2188,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(self.r.graph_root, ThinVec::new())]; - - while let Some((in_module, path_segments)) = worklist.pop() { + let root_did = self.r.graph_root.def_id(); + let mut worklist = vec![( + self.r.graph_root, + ThinVec::new(), + root_did.is_local() || !self.r.tcx.is_doc_hidden(root_did), + )]; + + while let Some((in_module, path_segments, doc_visible)) = worklist.pop() { // abort if the module is already found if result.is_some() { break; } - in_module.for_each_child(self.r, |_, ident, _, name_binding| { + in_module.for_each_child(self.r, |r, ident, _, name_binding| { // abort if the module is already found or if name_binding is private external if result.is_some() || !name_binding.vis.is_visible_locally() { return; @@ -2209,6 +2211,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); let module_def_id = module.def_id(); + let doc_visible = doc_visible + && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; @@ -2219,6 +2223,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { descr: "module", path, accessible: true, + doc_visible, note: None, via_import: false, }, @@ -2226,7 +2231,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { - worklist.push((module, path_segments)); + worklist.push((module, path_segments, doc_visible)); } } } @@ -2598,25 +2603,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ) { debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime); let mut err = if let Some(outer) = outer_lifetime_ref { - let mut err = struct_span_err!( + struct_span_code_err!( self.r.dcx(), lifetime_ref.ident.span, E0401, "can't use generic parameters from outer item", - ); - err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item"); - err.span_label(outer.span, "lifetime parameter from outer item"); - err + ) + .with_span_label(lifetime_ref.ident.span, "use of generic parameter from outer item") + .with_span_label(outer.span, "lifetime parameter from outer item") } else { - let mut err = struct_span_err!( + struct_span_code_err!( self.r.dcx(), lifetime_ref.ident.span, E0261, "use of undeclared lifetime name `{}`", lifetime_ref.ident - ); - err.span_label(lifetime_ref.ident.span, "undeclared lifetime"); - err + ) + .with_span_label(lifetime_ref.ident.span, "undeclared lifetime") }; self.suggest_introducing_lifetime( &mut err, @@ -2774,7 +2777,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum(); let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.r.dcx(), spans, E0106, @@ -3279,16 +3282,16 @@ fn mk_where_bound_predicate( /// Report lifetime/lifetime shadowing as an error. pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { - let mut err = struct_span_err!( + struct_span_code_err!( sess.dcx(), shadower.span, E0496, "lifetime name `{}` shadows a lifetime name that is already in scope", orig.name, - ); - err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)); - err.emit(); + ) + .with_span_label(orig.span, "first declared here") + .with_span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name)) + .emit(); } struct LifetimeFinder<'ast> { @@ -3314,11 +3317,12 @@ impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> { pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { let name = shadower.name; let shadower = shadower.span; - let mut err = sess.dcx().struct_span_warn( - shadower, - format!("label name `{name}` shadows a label name that is already in scope"), - ); - err.span_label(orig, "first declared here"); - err.span_label(shadower, format!("label `{name}` already in scope")); - err.emit(); + sess.dcx() + .struct_span_warn( + shadower, + format!("label name `{name}` shadows a label name that is already in scope"), + ) + .with_span_label(orig, "first declared here") + .with_span_label(shadower, format!("label `{name}` already in scope")) + .emit(); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0f7294cdad0..66ecaeb4449 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_code_err, Applicability}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; @@ -128,7 +128,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let msg = format!("{} `{}` was already registered", "tool", ident); tcx.dcx() .struct_span_err(ident.span, msg) - .span_label(old_ident.span, "already registered here") + .with_span_label(old_ident.span, "already registered here") .emit(); } } @@ -137,7 +137,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let span = nested_meta.span(); tcx.dcx() .struct_span_err(span, msg) - .span_label(span, "not an identifier") + .with_span_label(span, "not an identifier") .emit(); } } @@ -576,10 +576,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); } - let mut err = self.dcx().create_err(err); - err.span_label(path.span, format!("not {article} {expected}")); - - err.emit(); + self.dcx() + .create_err(err) + .with_span_label(path.span, format!("not {article} {expected}")) + .emit(); return Ok((self.dummy_ext(kind), Res::Err)); } @@ -830,7 +830,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); err.emit(); } @@ -949,13 +948,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { rule_spans = Vec::new(); } BuiltinMacroState::AlreadySeen(span) => { - struct_span_err!( + struct_span_code_err!( self.dcx(), item.span, E0773, "attempted to define built-in macro more than once" ) - .span_note(span, "previously defined here") + .with_span_note(span, "previously defined here") .emit(); } } diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs index 861091688bb..45ff85f38d2 100644 --- a/compiler/rustc_serialize/tests/opaque.rs +++ b/compiler/rustc_serialize/tests/opaque.rs @@ -1,12 +1,12 @@ #![allow(rustc::internal)] -use rustc_macros::{Decodable, Encodable}; -use rustc_serialize::opaque::{MemDecoder, FileEncoder}; +use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Encodable}; use std::fmt::Debug; use std::fs; -#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] +#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] struct Struct { a: (), b: u8, @@ -209,7 +209,7 @@ fn test_struct() { }]); } -#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] +#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] enum Enum { Variant1, Variant2(usize, u32), @@ -258,7 +258,7 @@ fn test_tuples() { #[test] fn test_unit_like_struct() { - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct UnitLikeStruct; check_round_trip(vec![UnitLikeStruct]); @@ -266,7 +266,7 @@ fn test_unit_like_struct() { #[test] fn test_box() { - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct A { foo: Box<[bool]>, } @@ -279,12 +279,12 @@ fn test_box() { fn test_cell() { use std::cell::{Cell, RefCell}; - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct A { baz: isize, } - #[derive(Encodable, Decodable, PartialEq, Debug)] + #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] struct B { foo: Cell<bool>, bar: RefCell<A>, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 89508c77639..61796d7a6ca 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -125,21 +125,6 @@ pub enum LtoCli { Unspecified, } -/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a -/// document highlighting each span of every statement (including terminators). `Terminator` and -/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a -/// computed span for the block, representing the entire range, covering the block's terminator and -/// all of its statements. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum MirSpanview { - /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` - Statement, - /// `-Z dump_mir_spanview=terminator` - Terminator, - /// `-Z dump_mir_spanview=block` - Block, -} - /// The different settings that the `-C instrument-coverage` flag can have. /// /// Coverage instrumentation now supports combining `-C instrument-coverage` @@ -1161,8 +1146,6 @@ impl UnstableOptions { DiagCtxtFlags { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, - dont_buffer_diagnostics: self.dont_buffer_diagnostics, - report_delayed_bugs: self.report_delayed_bugs, macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, @@ -2051,23 +2034,14 @@ fn check_error_format_stability( early_dcx: &mut EarlyDiagCtxt, unstable_opts: &UnstableOptions, error_format: ErrorOutputType, - json_rendered: HumanReadableErrorType, ) { if !unstable_opts.unstable_options { - if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { - early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json { - pretty: false, - json_rendered, - }); + if let ErrorOutputType::Json { pretty: true, .. } = error_format { early_dcx.early_fatal("`--error-format=pretty-json` is unstable"); } if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = error_format { - early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json { - pretty: false, - json_rendered, - }); early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable"); } } @@ -2665,7 +2639,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let mut unstable_opts = UnstableOptions::build(early_dcx, matches); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); - check_error_format_stability(early_dcx, &unstable_opts, error_format, json_rendered); + check_error_format_stability(early_dcx, &unstable_opts, error_format); if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { early_dcx.early_fatal( diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 0f86773b73f..b672e760feb 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -18,10 +18,9 @@ pub struct FeatureGateError { impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> { - let mut diag = DiagnosticBuilder::new(dcx, level, self.explain); - diag.set_span(self.span); - diag.code(error_code!(E0658)); - diag + DiagnosticBuilder::new(dcx, level, self.explain) + .with_span(self.span) + .with_code(error_code!(E0658)) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8274fd05bc0..c97b18ebd66 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -391,7 +391,6 @@ mod desc { pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; - pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`"; @@ -866,29 +865,6 @@ mod parse { } } - pub(crate) fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = bool_arg.unwrap().then_some(MirSpanview::Statement); - return true; - } - } - - let Some(v) = v else { - *slot = Some(MirSpanview::Statement); - return true; - }; - - *slot = Some(match v.trim_end_matches('s') { - "statement" | "stmt" => MirSpanview::Statement, - "terminator" | "term" => MirSpanview::Terminator, - "block" | "basicblock" => MirSpanview::Block, - _ => return false, - }); - true - } - pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool { match v { None => true, @@ -1577,9 +1553,6 @@ options! { dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), - dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], - "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \ - (default: no)"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1601,11 +1574,6 @@ options! { "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), - dump_mir_spanview: Option<MirSpanview> = (None, parse_mir_spanview, [UNTRACKED], - "in addition to `.mir` files, create `.html` files to view spans for \ - all `statement`s (including terminators), only `terminator` spans, or \ - computed `block` spans (one span encompassing a block's terminator and \ - all statements)."), dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled, parse_switch_with_opt_path, [UNTRACKED], "output statistics about monomorphization collection"), @@ -1841,8 +1809,6 @@ options! { remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), - report_delayed_bugs: bool = (false, parse_bool, [TRACKED], - "immediately print bugs registered with `span_delayed_bug` (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED], @@ -1875,6 +1841,8 @@ written to standard error output)"), query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED], "make the current crate share its generic instantiations"), + shell_argfiles: bool = (false, parse_bool, [UNTRACKED], + "allow argument files to be specified with POSIX \"shell-style\" argument quoting"), show_span: Option<String> = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], @@ -1919,8 +1887,8 @@ written to standard error output)"), #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), - thir_unsafeck: bool = (false, parse_bool, [TRACKED], - "use the THIR unsafety checker (default: no)"), + thir_unsafeck: bool = (true, parse_bool, [TRACKED], + "use the THIR unsafety checker (default: yes)"), /// We default to 1 here since we want to behave like /// a sequential compiler for now. This'll likely be adjusted /// in the future. Note that -Zthreads=0 is the way to get @@ -1991,6 +1959,8 @@ written to standard error output)"), "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), + use_sync_unwind: Option<bool> = (None, parse_opt_bool, [TRACKED], + "Generate sync unwind tables instead of async unwind tables (default: no)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 439fa18b7fa..598178c3c2a 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -143,11 +143,7 @@ pub fn feature_warn_issue( // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; let future_incompatible = lint.future_incompatible.as_ref().unwrap(); - err.code(DiagnosticId::Lint { - name: lint.name_lower(), - has_future_breakage: false, - is_force_warn: false, - }); + err.code(DiagnosticId::Lint { name: lint.name_lower(), has_future_breakage: false }); err.warn(lint.desc); err.note(format!("for more information, see {}", future_incompatible.reference)); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9ee7625e5bf..210dc9e0145 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -14,11 +14,9 @@ use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; -use rustc_data_structures::sync::{ - AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst, -}; -use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; -use rustc_errors::emitter::{DynEmitter, EmitterWriter, HumanReadableErrorType}; +use rustc_data_structures::sync::{AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread}; +use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; +use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ @@ -44,7 +42,7 @@ use std::fmt; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::{atomic::AtomicBool, Arc}; +use std::sync::{atomic::AtomicBool, atomic::Ordering::SeqCst, Arc}; struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. @@ -265,7 +263,7 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. - self.dcx().emit_warning(errors::SkippingConstChecks { + self.dcx().emit_warn(errors::SkippingConstChecks { unleashed_features: unleashed_features .iter() .map(|(span, gate)| { @@ -343,10 +341,7 @@ impl Session { if self.dcx().err_count() == old_count { Ok(result) } else { - Err(self.dcx().span_delayed_bug( - rustc_span::DUMMY_SP, - "`self.err_count()` changed but an error was not emitted", - )) + Err(self.dcx().delayed_bug("`self.err_count()` changed but an error was not emitted")) } } @@ -576,7 +571,7 @@ impl Session { // We only call `msg` in case we can actually emit warnings. // Otherwise, this could cause a `good_path_delayed_bug` to // trigger (issue #79546). - self.dcx().emit_warning(errors::OptimisationFuelExhausted { msg: msg() }); + self.dcx().emit_warn(errors::OptimisationFuelExhausted { msg: msg() }); } fuel.out_of_fuel = true; } else if fuel.remaining > 0 { @@ -1000,7 +995,7 @@ fn default_emitter( let (short, color_config) = kind.unzip(); if let HumanReadableErrorType::AnnotateSnippet(_) = kind { - let emitter = AnnotateSnippetEmitterWriter::new( + let emitter = AnnotateSnippetEmitter::new( Some(source_map), bundle, fallback_bundle, @@ -1009,7 +1004,7 @@ fn default_emitter( ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { - let emitter = EmitterWriter::stderr(color_config, fallback_bundle) + let emitter = HumanEmitter::stderr(color_config, fallback_bundle) .fluent_bundle(bundle) .sm(Some(source_map)) .short_message(short) @@ -1131,7 +1126,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - dcx.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() }); + dcx.emit_warn(errors::FailedToCreateProfiler { err: e.to_string() }); None } } @@ -1274,7 +1269,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // Cannot enable crt-static with sanitizers on Linux - if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() { + if sess.crt_static(None) + && !sess.opts.unstable_opts.sanitizer.is_empty() + && !sess.target.is_like_msvc + { sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux); } @@ -1340,7 +1338,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { - sess.dcx().emit_warning(errors::StackProtectorNotSupportedForTarget { + sess.dcx().emit_warn(errors::StackProtectorNotSupportedForTarget { stack_protector: sess.opts.unstable_opts.stack_protector, target_triple: &sess.opts.target_triple, }); @@ -1446,7 +1444,7 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) { - self.dcx.struct_note(msg).emit() + self.dcx.note(msg) } #[allow(rustc::untranslatable_diagnostic)] @@ -1459,13 +1457,13 @@ impl EarlyDiagCtxt { #[allow(rustc::diagnostic_outside_of_impl)] #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] pub fn early_err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { - self.dcx.struct_err(msg).emit() + self.dcx.err(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! { - self.dcx.struct_fatal(msg).emit() + self.dcx.fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] @@ -1480,7 +1478,7 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) { - self.dcx.struct_warn(msg).emit() + self.dcx.warn(msg) } pub fn initialize_checked_jobserver(&self) { @@ -1488,7 +1486,10 @@ impl EarlyDiagCtxt { jobserver::initialize_checked(|err| { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - self.dcx.struct_warn(err).note("the build environment is likely misconfigured").emit() + self.dcx + .struct_warn(err) + .with_note("the build environment is likely misconfigured") + .emit() }); } } @@ -1501,7 +1502,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> { let emitter: Box<DynEmitter> = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, fallback_bundle).short_message(short)) + Box::new(HumanEmitter::stderr(color_config, fallback_bundle).short_message(short)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic( pretty, diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 17162d0de25..5689e8f3b3d 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -17,7 +17,7 @@ use stable_mir::ty::{ GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx, }; -use stable_mir::{CrateItem, DefId}; +use stable_mir::{CrateItem, CrateNum, DefId}; use super::RustcInternal; @@ -28,6 +28,13 @@ impl<'tcx> RustcInternal<'tcx> for CrateItem { } } +impl<'tcx> RustcInternal<'tcx> for CrateNum { + type T = rustc_span::def_id::CrateNum; + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + rustc_span::def_id::CrateNum::from_usize(*self) + } +} + impl<'tcx> RustcInternal<'tcx> for DefId { type T = rustc_span::def_id::DefId; fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index f84c466cc44..fffc454804d 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -25,8 +25,9 @@ use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef, }; -use stable_mir::{Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol}; +use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; +use std::iter; use crate::rustc_internal::{internal, RustcInternal}; use crate::rustc_smir::builder::BodyBuilder; @@ -68,9 +69,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); + tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() + } + + fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { + let mut tables = self.0.borrow_mut(); tables .tcx - .traits(LOCAL_CRATE) + .traits(crate_num.internal(&mut *tables)) .iter() .map(|trait_def_id| tables.trait_def(*trait_def_id)) .collect() @@ -85,9 +91,19 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + iter::once(LOCAL_CRATE) + .chain(tables.tcx.crates(()).iter().copied()) + .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter()) + .map(|impl_def_id| tables.impl_def(*impl_def_id)) + .collect() + } + + fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { + let mut tables = self.0.borrow_mut(); tables .tcx - .trait_impls_in_crate(LOCAL_CRATE) + .trait_impls_in_crate(crate_num.internal(&mut *tables)) .iter() .map(|impl_def_id| tables.impl_def(*impl_def_id)) .collect() diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index f0f1d798d44..c0ecbfb9914 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables}; impl<'tcx> Stable<'tcx> for ty::AliasKind { type T = stable_mir::ty::AliasKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - use rustc_middle::ty::AliasKind::*; match self { - Projection => stable_mir::ty::AliasKind::Projection, - Inherent => stable_mir::ty::AliasKind::Inherent, - Opaque => stable_mir::ty::AliasKind::Opaque, - Weak => stable_mir::ty::AliasKind::Weak, + ty::Projection => stable_mir::ty::AliasKind::Projection, + ty::Inherent => stable_mir::ty::AliasKind::Inherent, + ty::Opaque => stable_mir::ty::AliasKind::Opaque, + ty::Weak => stable_mir::ty::AliasKind::Weak, } } } @@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind { type T = stable_mir::ty::DynKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - use rustc_middle::ty::DynKind; match self { - DynKind::Dyn => stable_mir::ty::DynKind::Dyn, - DynKind::DynStar => stable_mir::ty::DynKind::DynStar, + ty::Dyn => stable_mir::ty::DynKind::Dyn, + ty::DynStar => stable_mir::ty::DynKind::DynStar, } } } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index e397fab5459..0c811d7dff1 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,11 +1,13 @@ -use crate::{HashStableContext, Symbol}; +use crate::{HashStableContext, SpanDecoder, SpanEncoder, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{ + Hash64, HashStable, StableHasher, StableOrd, ToStableHashKey, +}; use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::Idx; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{Decodable, Encodable}; use std::fmt; use std::hash::{BuildHasherDefault, Hash, Hasher}; @@ -46,20 +48,6 @@ impl fmt::Display for CrateNum { } } -/// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. -/// Therefore, make sure to include the context when encode a `CrateNum`. -impl<E: Encoder> Encodable<E> for CrateNum { - default fn encode(&self, s: &mut E) { - s.emit_u32(self.as_u32()); - } -} - -impl<D: Decoder> Decodable<D> for CrateNum { - default fn decode(d: &mut D) -> CrateNum { - CrateNum::from_u32(d.read_u32()) - } -} - /// A `DefPathHash` is a fixed-size representation of a `DefPath` that is /// stable across crate and compilation session boundaries. It consists of two /// separate 64-bit hashes. The first uniquely identifies the crate this @@ -132,6 +120,11 @@ impl Default for DefPathHash { } } +// Safety: `DefPathHash` sort order is not affected (de)serialization. +unsafe impl StableOrd for DefPathHash { + const CAN_USE_UNSTABLE_SORT: bool = true; +} + /// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all /// `-Cmetadata` arguments, and some other data. It is to [`CrateNum`] what [`DefPathHash`] is to /// [`DefId`]. It is stable across compilation sessions. @@ -220,18 +213,6 @@ rustc_index::newtype_index! { } } -impl<E: Encoder> Encodable<E> for DefIndex { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>()); - } -} - -impl<D: Decoder> Decodable<D> for DefIndex { - default fn decode(_: &mut D) -> DefIndex { - panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>()); - } -} - /// A `DefId` identifies a particular *definition*, by combining a crate /// index and a def index. /// @@ -347,19 +328,6 @@ impl From<LocalDefId> for DefId { } } -impl<E: Encoder> Encodable<E> for DefId { - default fn encode(&self, s: &mut E) { - self.krate.encode(s); - self.index.encode(s); - } -} - -impl<D: Decoder> Decodable<D> for DefId { - default fn decode(d: &mut D) -> DefId { - DefId { krate: Decodable::decode(d), index: Decodable::decode(d) } - } -} - pub fn default_def_id_debug(def_id: DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DefId").field("krate", &def_id.krate).field("index", &def_id.index).finish() } @@ -423,13 +391,13 @@ impl fmt::Debug for LocalDefId { } } -impl<E: Encoder> Encodable<E> for LocalDefId { +impl<E: SpanEncoder> Encodable<E> for LocalDefId { fn encode(&self, s: &mut E) { self.to_def_id().encode(s); } } -impl<D: Decoder> Decodable<D> for LocalDefId { +impl<D: SpanDecoder> Decodable<D> for LocalDefId { fn decode(d: &mut D) -> LocalDefId { DefId::decode(d).expect_local() } @@ -490,6 +458,15 @@ impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum { } } +impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefPathHash { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, _: &CTX) -> DefPathHash { + *self + } +} + macro_rules! typed_def_id { ($Name:ident, $LocalName:ident) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b717229b68d..d03965b539c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -27,7 +27,7 @@ use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use crate::edition::Edition; use crate::symbol::{kw, sym, Symbol}; -use crate::{with_session_globals, HashStableContext, Span, DUMMY_SP}; +use crate::{with_session_globals, HashStableContext, Span, SpanDecoder, SpanEncoder, DUMMY_SP}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher}; @@ -295,11 +295,13 @@ impl ExpnId { pub fn expansion_cause(mut self) -> Option<Span> { let mut last_macro = None; loop { + // Fast path to avoid locking. + if self == ExpnId::root() { + break; + } let expn_data = self.expn_data(); // Stop going up the backtrace once include! is encountered - if expn_data.is_root() - || expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) - { + if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) { break; } self = expn_data.call_site.ctxt().outer_expn(); @@ -433,7 +435,7 @@ impl HygieneData { fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { let mut marks = Vec::new(); - while ctxt != SyntaxContext::root() { + while !ctxt.is_root() { debug!("marks: getting parent of {:?}", ctxt); marks.push(self.outer_mark(ctxt)); ctxt = self.parent_ctxt(ctxt); @@ -443,18 +445,46 @@ impl HygieneData { } fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span { + let orig_span = span; debug!("walk_chain({:?}, {:?})", span, to); debug!("walk_chain: span ctxt = {:?}", span.ctxt()); - while span.from_expansion() && span.ctxt() != to { + while span.ctxt() != to && span.from_expansion() { let outer_expn = self.outer_expn(span.ctxt()); debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn); let expn_data = self.expn_data(outer_expn); debug!("walk_chain({:?}): expn_data={:?}", span, expn_data); span = expn_data.call_site; } + debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span); span } + // We need to walk up and update return span if we meet macro instantiation to be collapsed + fn walk_chain_collapsed( + &self, + mut span: Span, + to: Span, + collapse_debuginfo_enabled: bool, + ) -> Span { + let orig_span = span; + let mut ret_span = span; + + debug!("walk_chain_collapsed({:?}, {:?})", span, to); + debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); + while !span.eq_ctxt(to) && span.from_expansion() { + let outer_expn = self.outer_expn(span.ctxt()); + debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn); + let expn_data = self.expn_data(outer_expn); + debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); + span = expn_data.call_site; + if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo { + ret_span = span; + } + } + debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span); + ret_span + } + fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> { let mut scope = None; while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { @@ -571,6 +601,10 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { HygieneData::with(|data| data.walk_chain(span, to)) } +pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span { + HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled)) +} + pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { // The new contexts that need updating are at the end of the list and have `$crate` as a name. let (len, to_update) = HygieneData::with(|data| { @@ -656,7 +690,7 @@ impl SyntaxContext { } /// Extend a syntax context with a given expansion and transparency. - pub(crate) fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } @@ -850,21 +884,6 @@ impl fmt::Debug for SyntaxContext { } impl Span { - /// Creates a fresh expansion with given properties. - /// Expansions are normally created by macros, but in some cases expansions are created for - /// other compiler-generated code to set per-span properties like allowed unstable features. - /// The returned span belongs to the created expansion and has the new properties, - /// but its location is inherited from the current span. - pub fn fresh_expansion(self, expn_id: LocalExpnId) -> Span { - HygieneData::with(|data| { - self.with_ctxt(data.apply_mark( - self.ctxt(), - expn_id.to_expn_id(), - Transparency::Transparent, - )) - }) - } - /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. pub fn mark_with_reason( @@ -879,7 +898,7 @@ impl Span { ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None) }; let expn_id = LocalExpnId::fresh(expn_data, ctx); - self.fresh_expansion(expn_id) + self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent) } } @@ -1431,30 +1450,18 @@ fn for_all_expns_in( } } -impl<E: Encoder> Encodable<E> for LocalExpnId { +impl<E: SpanEncoder> Encodable<E> for LocalExpnId { fn encode(&self, e: &mut E) { self.to_expn_id().encode(e); } } -impl<E: Encoder> Encodable<E> for ExpnId { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>()); - } -} - -impl<D: Decoder> Decodable<D> for LocalExpnId { +impl<D: SpanDecoder> Decodable<D> for LocalExpnId { fn decode(d: &mut D) -> Self { ExpnId::expect_local(ExpnId::decode(d)) } } -impl<D: Decoder> Decodable<D> for ExpnId { - default fn decode(_: &mut D) -> Self { - panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>()); - } -} - pub fn raw_encode_syntax_context<E: Encoder>( ctxt: SyntaxContext, context: &HygieneEncodeContext, @@ -1466,18 +1473,6 @@ pub fn raw_encode_syntax_context<E: Encoder>( ctxt.0.encode(e); } -impl<E: Encoder> Encodable<E> for SyntaxContext { - default fn encode(&self, _: &mut E) { - panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::<E>()); - } -} - -impl<D: Decoder> Decodable<D> for SyntaxContext { - default fn decode(_: &mut D) -> Self { - panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>()); - } -} - /// Updates the `disambiguator` field of the corresponding `ExpnData` /// such that the `Fingerprint` of the `ExpnData` does not collide with /// any other `ExpnIds`. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8f64eed9a87..4235293823c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -35,6 +35,8 @@ #![feature(rustdoc_internals)] // tidy-alphabetical-end +extern crate self as rustc_span; + #[macro_use] extern crate rustc_macros; @@ -43,6 +45,7 @@ extern crate tracing; use rustc_data_structures::{outline, AtomicRef}; use rustc_macros::HashStable_Generic; +use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; mod caching_source_map_view; @@ -58,7 +61,7 @@ pub use hygiene::{DesugaringKind, ExpnKind, MacroKind}; pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; use rustc_data_structures::stable_hasher::HashingControls; pub mod def_id; -use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE}; +use def_id::{CrateNum, DefId, DefIndex, DefPathHash, LocalDefId, StableCrateId, LOCAL_CRATE}; pub mod edit_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -541,10 +544,6 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn eq_ctxt(self, other: Span) -> bool { - self.data_untracked().ctxt == other.data_untracked().ctxt - } - #[inline] pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { self.data_untracked().with_ctxt(ctxt) } @@ -565,14 +564,7 @@ impl Span { /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { - self.ctxt() != SyntaxContext::root() - } - - /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be - /// collapsed. - pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool { - let outer_expn = self.ctxt().outer_expn_data(); - matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo + !self.ctxt().is_root() } /// Returns `true` if `span` originates in a derive-macro's expansion. @@ -654,15 +646,15 @@ impl Span { /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { - let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self } + let ctxt = self.ctxt(); + if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self } } /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. pub fn parent_callsite(self) -> Option<Span> { - let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { Some(expn_data.call_site) } else { None } + let ctxt = self.ctxt(); + (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site) } /// Walk down the expansion ancestors to find a span that's contained within `outer`. @@ -747,15 +739,14 @@ impl Span { /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. pub fn source_callee(self) -> Option<ExpnData> { - let expn_data = self.ctxt().outer_expn_data(); - - // Create an iterator of call site expansions - iter::successors(Some(expn_data), |expn_data| { - Some(expn_data.call_site.ctxt().outer_expn_data()) - }) - // Find the last expansion which is not root - .take_while(|expn_data| !expn_data.is_root()) - .last() + let mut ctxt = self.ctxt(); + let mut opt_expn_data = None; + while !ctxt.is_root() { + let expn_data = ctxt.outer_expn_data(); + ctxt = expn_data.call_site.ctxt(); + opt_expn_data = Some(expn_data); + } + opt_expn_data } /// Checks if a span is "internal" to a macro in which `#[unstable]` @@ -796,11 +787,12 @@ impl Span { let mut prev_span = DUMMY_SP; iter::from_fn(move || { loop { - let expn_data = self.ctxt().outer_expn_data(); - if expn_data.is_root() { + let ctxt = self.ctxt(); + if ctxt.is_root() { return None; } + let expn_data = ctxt.outer_expn_data(); let is_recursive = expn_data.call_site.source_equal(prev_span); prev_span = self; @@ -826,6 +818,39 @@ impl Span { ) } + /// Prepare two spans to a combine operation like `to` or `between`. + /// FIXME: consider using declarative macro metavariable spans for the given spans if they are + /// better suitable for combining (#119412). + fn prepare_to_combine( + a_orig: Span, + b_orig: Span, + ) -> Result<(SpanData, SpanData, Option<LocalDefId>), Span> { + let (a, b) = (a_orig.data(), b_orig.data()); + + if a.ctxt != b.ctxt { + // Context mismatches usually happen when procedural macros combine spans copied from + // the macro input with spans produced by the macro (`Span::*_site`). + // In that case we consider the combined span to be produced by the macro and return + // the original macro-produced span as the result. + // Otherwise we just fall back to returning the first span. + // Combining locations typically doesn't make sense in case of context mismatches. + // `is_root` here is a fast path optimization. + let a_is_callsite = a.ctxt.is_root() || a.ctxt == b.span().source_callsite().ctxt(); + return Err(if a_is_callsite { b_orig } else { a_orig }); + } + + let parent = if a.parent == b.parent { a.parent } else { None }; + Ok((a, b, parent)) + } + + /// This span, but in a larger context, may switch to the metavariable span if suitable. + pub fn with_neighbor(self, neighbor: Span) -> Span { + match Span::prepare_to_combine(self, neighbor) { + Ok((this, ..)) => Span::new(this.lo, this.hi, this.ctxt, this.parent), + Err(_) => self, + } + } + /// Returns a `Span` that would enclose both `self` and `end`. /// /// Note that this can also be used to extend the span "backwards": @@ -837,26 +862,12 @@ impl Span { /// ^^^^^^^^^^^^^^^^^^^^ /// ``` pub fn to(self, end: Span) -> Span { - let span_data = self.data(); - let end_data = end.data(); - // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). - // Return the macro span on its own to avoid weird diagnostic output. It is preferable to - // have an incomplete span than a completely nonsensical one. - if span_data.ctxt != end_data.ctxt { - if span_data.ctxt.is_root() { - return end; - } else if end_data.ctxt.is_root() { - return self; + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.lo, to.lo), cmp::max(from.hi, to.hi), from.ctxt, parent) } - // Both spans fall within a macro. - // FIXME(estebank): check if it is the *same* macro. + Err(fallback) => fallback, } - Span::new( - cmp::min(span_data.lo, end_data.lo), - cmp::max(span_data.hi, end_data.hi), - if span_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt }, - if span_data.parent == end_data.parent { span_data.parent } else { None }, - ) } /// Returns a `Span` between the end of `self` to the beginning of `end`. @@ -867,14 +878,12 @@ impl Span { /// ^^^^^^^^^^^^^ /// ``` pub fn between(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); - Span::new( - span.hi, - end.lo, - if end.ctxt.is_root() { end.ctxt } else { span.ctxt }, - if span.parent == end.parent { span.parent } else { None }, - ) + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.hi, to.hi), cmp::max(from.lo, to.lo), from.ctxt, parent) + } + Err(fallback) => fallback, + } } /// Returns a `Span` from the beginning of `self` until the beginning of `end`. @@ -885,31 +894,12 @@ impl Span { /// ^^^^^^^^^^^^^^^^^ /// ``` pub fn until(self, end: Span) -> Span { - // Most of this function's body is copied from `to`. - // We can't just do `self.to(end.shrink_to_lo())`, - // because to also does some magic where it uses min/max so - // it can handle overlapping spans. Some advanced mis-use of - // `until` with different ctxts makes this visible. - let span_data = self.data(); - let end_data = end.data(); - // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). - // Return the macro span on its own to avoid weird diagnostic output. It is preferable to - // have an incomplete span than a completely nonsensical one. - if span_data.ctxt != end_data.ctxt { - if span_data.ctxt.is_root() { - return end; - } else if end_data.ctxt.is_root() { - return self; + match Span::prepare_to_combine(self, end) { + Ok((from, to, parent)) => { + Span::new(cmp::min(from.lo, to.lo), cmp::max(from.lo, to.lo), from.ctxt, parent) } - // Both spans fall within a macro. - // FIXME(estebank): check if it is the *same* macro. + Err(fallback) => fallback, } - Span::new( - span_data.lo, - end_data.lo, - if end_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt }, - if span_data.parent == end_data.parent { span_data.parent } else { None }, - ) } pub fn from_inner(self, inner: InnerSpan) -> Span { @@ -1016,20 +1006,203 @@ impl Default for Span { } } -impl<E: Encoder> Encodable<E> for Span { - default fn encode(&self, s: &mut E) { - let span = self.data(); - span.lo.encode(s); - span.hi.encode(s); +rustc_index::newtype_index! { + #[orderable] + #[debug_format = "AttrId({})"] + pub struct AttrId {} +} + +/// This trait is used to allow encoder specific encodings of certain types. +/// It is similar to rustc_type_ir's TyEncoder. +pub trait SpanEncoder: Encoder { + fn encode_span(&mut self, span: Span); + fn encode_symbol(&mut self, symbol: Symbol); + fn encode_expn_id(&mut self, expn_id: ExpnId); + fn encode_syntax_context(&mut self, syntax_context: SyntaxContext); + /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx. + /// Therefore, make sure to include the context when encode a `CrateNum`. + fn encode_crate_num(&mut self, crate_num: CrateNum); + fn encode_def_index(&mut self, def_index: DefIndex); + fn encode_def_id(&mut self, def_id: DefId); +} + +impl SpanEncoder for FileEncoder { + fn encode_span(&mut self, span: Span) { + let span = span.data(); + span.lo.encode(self); + span.hi.encode(self); + } + + fn encode_symbol(&mut self, symbol: Symbol) { + self.emit_str(symbol.as_str()); + } + + fn encode_expn_id(&mut self, _expn_id: ExpnId) { + panic!("cannot encode `ExpnId` with `FileEncoder`"); + } + + fn encode_syntax_context(&mut self, _syntax_context: SyntaxContext) { + panic!("cannot encode `SyntaxContext` with `FileEncoder`"); + } + + fn encode_crate_num(&mut self, crate_num: CrateNum) { + self.emit_u32(crate_num.as_u32()); + } + + fn encode_def_index(&mut self, _def_index: DefIndex) { + panic!("cannot encode `DefIndex` with `FileEncoder`"); + } + + fn encode_def_id(&mut self, def_id: DefId) { + def_id.krate.encode(self); + def_id.index.encode(self); + } +} + +impl<E: SpanEncoder> Encodable<E> for Span { + fn encode(&self, s: &mut E) { + s.encode_span(*self); + } +} + +impl<E: SpanEncoder> Encodable<E> for Symbol { + fn encode(&self, s: &mut E) { + s.encode_symbol(*self); + } +} + +impl<E: SpanEncoder> Encodable<E> for ExpnId { + fn encode(&self, s: &mut E) { + s.encode_expn_id(*self) + } +} + +impl<E: SpanEncoder> Encodable<E> for SyntaxContext { + fn encode(&self, s: &mut E) { + s.encode_syntax_context(*self) } } -impl<D: Decoder> Decodable<D> for Span { - default fn decode(s: &mut D) -> Span { - let lo = Decodable::decode(s); - let hi = Decodable::decode(s); + +impl<E: SpanEncoder> Encodable<E> for CrateNum { + fn encode(&self, s: &mut E) { + s.encode_crate_num(*self) + } +} + +impl<E: SpanEncoder> Encodable<E> for DefIndex { + fn encode(&self, s: &mut E) { + s.encode_def_index(*self) + } +} + +impl<E: SpanEncoder> Encodable<E> for DefId { + fn encode(&self, s: &mut E) { + s.encode_def_id(*self) + } +} + +impl<E: SpanEncoder> Encodable<E> for AttrId { + fn encode(&self, _s: &mut E) { + // A fresh id will be generated when decoding + } +} + +/// This trait is used to allow decoder specific encodings of certain types. +/// It is similar to rustc_type_ir's TyDecoder. +pub trait SpanDecoder: Decoder { + fn decode_span(&mut self) -> Span; + fn decode_symbol(&mut self) -> Symbol; + fn decode_expn_id(&mut self) -> ExpnId; + fn decode_syntax_context(&mut self) -> SyntaxContext; + fn decode_crate_num(&mut self) -> CrateNum; + fn decode_def_index(&mut self) -> DefIndex; + fn decode_def_id(&mut self) -> DefId; + fn decode_attr_id(&mut self) -> AttrId; +} + +impl SpanDecoder for MemDecoder<'_> { + fn decode_span(&mut self) -> Span { + let lo = Decodable::decode(self); + let hi = Decodable::decode(self); Span::new(lo, hi, SyntaxContext::root(), None) } + + fn decode_symbol(&mut self) -> Symbol { + Symbol::intern(self.read_str()) + } + + fn decode_expn_id(&mut self) -> ExpnId { + panic!("cannot decode `ExpnId` with `MemDecoder`"); + } + + fn decode_syntax_context(&mut self) -> SyntaxContext { + panic!("cannot decode `SyntaxContext` with `MemDecoder`"); + } + + fn decode_crate_num(&mut self) -> CrateNum { + CrateNum::from_u32(self.read_u32()) + } + + fn decode_def_index(&mut self) -> DefIndex { + panic!("cannot decode `DefIndex` with `MemDecoder`"); + } + + fn decode_def_id(&mut self) -> DefId { + DefId { krate: Decodable::decode(self), index: Decodable::decode(self) } + } + + fn decode_attr_id(&mut self) -> AttrId { + panic!("cannot decode `AttrId` with `MemDecoder`"); + } +} + +impl<D: SpanDecoder> Decodable<D> for Span { + fn decode(s: &mut D) -> Span { + s.decode_span() + } +} + +impl<D: SpanDecoder> Decodable<D> for Symbol { + fn decode(s: &mut D) -> Symbol { + s.decode_symbol() + } +} + +impl<D: SpanDecoder> Decodable<D> for ExpnId { + fn decode(s: &mut D) -> ExpnId { + s.decode_expn_id() + } +} + +impl<D: SpanDecoder> Decodable<D> for SyntaxContext { + fn decode(s: &mut D) -> SyntaxContext { + s.decode_syntax_context() + } +} + +impl<D: SpanDecoder> Decodable<D> for CrateNum { + fn decode(s: &mut D) -> CrateNum { + s.decode_crate_num() + } +} + +impl<D: SpanDecoder> Decodable<D> for DefIndex { + fn decode(s: &mut D) -> DefIndex { + s.decode_def_index() + } +} + +impl<D: SpanDecoder> Decodable<D> for DefId { + fn decode(s: &mut D) -> DefId { + s.decode_def_id() + } +} + +impl<D: SpanDecoder> Decodable<D> for AttrId { + fn decode(s: &mut D) -> AttrId { + s.decode_attr_id() + } } /// Insert `source_map` into the session globals for the duration of the @@ -1360,7 +1533,7 @@ impl Clone for SourceFile { } } -impl<S: Encoder> Encodable<S> for SourceFile { +impl<S: SpanEncoder> Encodable<S> for SourceFile { fn encode(&self, s: &mut S) { self.name.encode(s); self.src_hash.encode(s); @@ -1434,7 +1607,7 @@ impl<S: Encoder> Encodable<S> for SourceFile { } } -impl<D: Decoder> Decodable<D> for SourceFile { +impl<D: SpanDecoder> Decodable<D> for SourceFile { fn decode(d: &mut D) -> SourceFile { let name: FileName = Decodable::decode(d); let src_hash: SourceFileHash = Decodable::decode(d); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index c61dbcaae95..8253ffefcaa 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,9 +23,15 @@ mod tests; /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_data` chain. pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { - let expn_data1 = sp.ctxt().outer_expn_data(); - let expn_data2 = enclosing_sp.ctxt().outer_expn_data(); - if expn_data1.is_root() || !expn_data2.is_root() && expn_data1.call_site == expn_data2.call_site + let ctxt = sp.ctxt(); + if ctxt.is_root() { + return sp; + } + + let enclosing_ctxt = enclosing_sp.ctxt(); + let expn_data1 = ctxt.outer_expn_data(); + if !enclosing_ctxt.is_root() + && expn_data1.call_site == enclosing_ctxt.outer_expn_data().call_site { sp } else { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 130522a302d..5788d11ed43 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -18,7 +18,7 @@ impl SourceMap { /// * the LHS span must start at or before the RHS span. fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> { // Ensure we're at the same expansion ID. - if sp_lhs.ctxt() != sp_rhs.ctxt() { + if !sp_lhs.eq_ctxt(sp_rhs) { return None; } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index f7d17a267d6..e162695a13b 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -210,12 +210,10 @@ impl Span { } } - /// This function is used as a fast path when decoding the full `SpanData` is not necessary. - /// It's a cut-down version of `data_untracked`. - #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")] - #[inline] - pub fn ctxt(self) -> SyntaxContext { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + // Returns either syntactic context, if it can be retrieved without taking the interner lock, + // or an index into the interner if it cannot. + fn inline_ctxt(self) -> Result<SyntaxContext, usize> { + Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) @@ -223,17 +221,36 @@ impl Span { // Inline-parent format. We know that the SyntaxContext is root. SyntaxContext::root() } + } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. This path avoids looking up the + // interned value, and is the whole point of the + // partially-interned format. + SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) } else { - if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. This path avoids looking up the - // interned value, and is the whole point of the - // partially-interned format. - SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) - } else { - // Fully-interned format. - let index = self.lo_or_index; - with_span_interner(|interner| interner.spans[index as usize].ctxt) + // Fully-interned format. + return Err(self.lo_or_index as usize); + }) + } + + /// This function is used as a fast path when decoding the full `SpanData` is not necessary. + /// It's a cut-down version of `data_untracked`. + #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")] + #[inline] + pub fn ctxt(self) -> SyntaxContext { + self.inline_ctxt() + .unwrap_or_else(|index| with_span_interner(|interner| interner.spans[index].ctxt)) + } + + #[inline] + pub fn eq_ctxt(self, other: Span) -> bool { + match (self.inline_ctxt(), other.inline_ctxt()) { + (Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2, + (Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => { + with_span_interner(|interner| ctxt == interner.spans[index].ctxt) } + (Err(index1), Err(index2)) => with_span_interner(|interner| { + interner.spans[index1].ctxt == interner.spans[index2].ctxt + }), } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0b44071496e..8ed1255c010 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -4,10 +4,11 @@ use rustc_arena::DroplessArena; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{ + HashStable, StableCompare, StableHasher, ToStableHashKey, +}; use rustc_data_structures::sync::Lock; use rustc_macros::HashStable_Generic; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::hash::{Hash, Hasher}; @@ -1041,6 +1042,7 @@ symbols! { mir_offset, mir_retag, mir_return, + mir_return_to, mir_set_discriminant, mir_static, mir_static_mut, @@ -2075,19 +2077,6 @@ impl ToString for Symbol { } } -impl<S: Encoder> Encodable<S> for Symbol { - default fn encode(&self, s: &mut S) { - s.emit_str(self.as_str()); - } -} - -impl<D: Decoder> Decodable<D> for Symbol { - #[inline] - default fn decode(d: &mut D) -> Symbol { - Symbol::intern(d.read_str()) - } -} - impl<CTX> HashStable<CTX> for Symbol { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { @@ -2103,6 +2092,14 @@ impl<CTX> ToStableHashKey<CTX> for Symbol { } } +impl StableCompare for Symbol { + const CAN_USE_UNSTABLE_SORT: bool = true; + + fn stable_cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + pub(crate) struct Interner(Lock<InternerInner>); // The `&'static str`s in this type actually point into the arena. diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index 06a2b3ca9c4..2d076f7b225 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -18,9 +18,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TestOutput { let TestOutput { span, kind, content } = self; #[allow(rustc::untranslatable_diagnostic)] - let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")); - diag.set_span(span); - diag + DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")).with_span(span) } } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a274790bffc..24e49ff648f 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -120,11 +120,11 @@ impl<'a> Layout<'a> { /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. /// /// Currently, that means that the type is pointer-sized, pointer-aligned, - /// and has a scalar ABI. + /// and has a initialized (non-union), scalar ABI. pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(..)) + && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) } } diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 0a50064f587..b8afeb824d8 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -6,6 +6,7 @@ use std::fmt; def_reg_class! { S390x S390xInlineAsmRegClass { reg, + reg_addr, freg, } } @@ -36,7 +37,7 @@ impl S390xInlineAsmRegClass { arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<Symbol>)] { match (self, arch) { - (Self::reg, _) => types! { _: I8, I16, I32, I64; }, + (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; }, (Self::freg, _) => types! { _: F32, F64; }, } } @@ -45,19 +46,19 @@ impl S390xInlineAsmRegClass { def_regs! { S390x S390xInlineAsmReg S390xInlineAsmRegClass { r0: reg = ["r0"], - r1: reg = ["r1"], - r2: reg = ["r2"], - r3: reg = ["r3"], - r4: reg = ["r4"], - r5: reg = ["r5"], - r6: reg = ["r6"], - r7: reg = ["r7"], - r8: reg = ["r8"], - r9: reg = ["r9"], - r10: reg = ["r10"], - r12: reg = ["r12"], - r13: reg = ["r13"], - r14: reg = ["r14"], + r1: reg, reg_addr = ["r1"], + r2: reg, reg_addr = ["r2"], + r3: reg, reg_addr = ["r3"], + r4: reg, reg_addr = ["r4"], + r5: reg, reg_addr = ["r5"], + r6: reg, reg_addr = ["r6"], + r7: reg, reg_addr = ["r7"], + r8: reg, reg_addr = ["r8"], + r9: reg, reg_addr = ["r9"], + r10: reg, reg_addr = ["r10"], + r12: reg, reg_addr = ["r12"], + r13: reg, reg_addr = ["r13"], + r14: reg, reg_addr = ["r14"], f0: freg = ["f0"], f1: freg = ["f1"], f2: freg = ["f2"], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 9d25388b90f..8e26327196a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1601,6 +1601,8 @@ supported_targets! { ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), + ("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf), + ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs index ba80c23196e..5abc3017bf8 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs @@ -1,9 +1,10 @@ -use crate::spec::{base, LinkerFlavor, Lld, Target}; +use crate::spec::{base, LinkerFlavor, Lld, SanitizerSet, Target}; pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); + base.supported_sanitizers = SanitizerSet::ADDRESS; base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs index 9102673ef77..6884e078c27 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_hurd_gnu.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentiumpro".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-hurd-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs new file mode 100644 index 00000000000..6c7c920bd18 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_esp_espidf.rs @@ -0,0 +1,30 @@ +use crate::spec::{cvs, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "espidf".into(), + env: "newlib".into(), + vendor: "espressif".into(), + linker: Some("riscv32-esp-elf-gcc".into()), + cpu: "generic-rv32".into(), + + max_atomic_width: Some(32), + atomic_cas: true, + + llvm_abiname: "ilp32f".into(), + features: "+m,+a,+c,+f".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs index 7d6276a0c2d..3a4da91c244 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs @@ -1,10 +1,11 @@ -use crate::spec::{base, Target}; +use crate::spec::{base, SanitizerSet, Target}; pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); + base.supported_sanitizers = SanitizerSet::ADDRESS; Target { llvm_target: "x86_64-pc-windows-msvc".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index f0515615b19..5b19ed1b5ff 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-fuchsia".into(), diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index bea6fbd6ac5..5eff52afbca 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -66,12 +66,9 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_ ) -> rustc_errors::DiagnosticBuilder<'_, G> { let mut diag = DiagnosticBuilder::new(dcx, level, fluent::trait_selection_negative_positive_conflict); - diag.set_arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); - diag.set_arg( - "self_desc", - self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string()), - ); - diag.set_span(self.impl_span); + diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); + diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); + diag.span(self.impl_span); diag.code(rustc_errors::error_code!(E0751)); match self.negative_impl_span { Ok(span) => { @@ -79,7 +76,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_ } Err(cname) => { diag.note(fluent::trait_selection_negative_implementation_in_crate); - diag.set_arg("negative_impl_cname", cname.to_string()); + diag.arg("negative_impl_cname", cname.to_string()); } } match self.positive_impl_span { @@ -88,7 +85,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for NegativePositiveConflict<'_ } Err(cname) => { diag.note(fluent::trait_selection_positive_implementation_in_crate); - diag.set_arg("positive_impl_cname", cname.to_string()); + diag.arg("positive_impl_cname", cname.to_string()); } } diag @@ -115,7 +112,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow { { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { - diag.set_arg("len", to_borrow.len()); + diag.arg("len", to_borrow.len()); diag.multipart_suggestion_verbose( fluent::trait_selection_adjust_signature_borrow, to_borrow, @@ -123,7 +120,7 @@ impl AddToDiagnostic for AdjustSignatureBorrow { ); } AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => { - diag.set_arg("len", remove_borrow.len()); + diag.arg("len", remove_borrow.len()); diag.multipart_suggestion_verbose( fluent::trait_selection_adjust_signature_remove_borrow, remove_borrow, diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 626569fb40f..c05c9961750 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -2,15 +2,29 @@ //! Doing this via a separate goal is called "deferred alias relation" and part //! of our more general approach to "lazy normalization". //! -//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches: -//! * normalizes-to: If `A` is a projection, we can prove the equivalent -//! projection predicate with B as the right-hand side of the projection. -//! This goal is computed in both directions, if both are aliases. -//! * subst-relate: Equate `A` and `B` by their substs, if they're both -//! aliases with the same def-id. -//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both -//! may apply, then we can compute the "intersection" of both normalizes-to by -//! performing them together. This is used specifically to resolve ambiguities. +//! This is done by first normalizing both sides of the goal, ending up in +//! either a concrete type, rigid projection, opaque, or an infer variable. +//! These are related further according to the rules below: +//! +//! (1.) If we end up with a rigid projection and a rigid projection, then we +//! relate those projections structurally. +//! +//! (2.) If we end up with a rigid projection and an alias, then the opaque will +//! have its hidden type defined to be that rigid projection. +//! +//! (3.) If we end up with an opaque and an opaque, then we assemble two +//! candidates, one defining the LHS to be the hidden type of the RHS, and vice +//! versa. +//! +//! (4.) If we end up with an infer var and an opaque or rigid projection, then +//! we assign the alias to the infer var. +//! +//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we +//! define the hidden type of the opaque to be the rigid type. +//! +//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types, +//! relate them structurally. + use super::{EvalCtxt, GoalSource}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::query::NoSolution; @@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.relate(param_env, lhs, variance, rhs)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else if alias.is_opaque(tcx) { + // FIXME: This doesn't account for variance. self.define_opaque(param_env, alias, rhs) } else { Err(NoSolution) @@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.relate(param_env, lhs, variance, rhs)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else if alias.is_opaque(tcx) { + // FIXME: This doesn't account for variance. self.define_opaque(param_env, alias, lhs) } else { Err(NoSolution) @@ -72,6 +88,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. /// Normalize the `term` to equate it later. This does not define opaque types. #[instrument(level = "debug", skip(self, param_env), ret)] fn try_normalize_term( diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 2f3111a2414..7c8f885a1f2 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack, QueryResult, Response, }; +use rustc_middle::traits::Reveal; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, @@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Some(ty); }; - // We do no always define opaque types eagerly to allow non-defining uses in the defining scope. - if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) { - if let Some(def_id) = alias.def_id.as_local() { - if self - .unify_existing_opaque_tys( - param_env, - OpaqueTypeKey { def_id, args: alias.args }, - self.next_ty_infer(), - ) - .is_empty() - { - return Some(ty); - } + // We do no always define opaque types eagerly to allow non-defining uses + // in the defining scope. However, if we can unify this opaque to an existing + // opaque, then we should attempt to eagerly reveal the opaque, and we fall + // through. + if let DefineOpaqueTypes::No = define_opaque_types + && let Reveal::UserFacing = param_env.reveal() + && let ty::Opaque = kind + && let Some(def_id) = alias.def_id.as_local() + && self.can_define_opaque_ty(def_id) + { + if self + .unify_existing_opaque_tys( + param_env, + OpaqueTypeKey { def_id, args: alias.args }, + self.next_ty_infer(), + ) + .is_empty() + { + return Some(ty); } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 533fe32f70d..ecbb92ca5b9 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -10,7 +10,7 @@ use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; +use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::structural_normalize::StructurallyNormalizeExt; use crate::traits::NormalizeExt; use crate::traits::SkipLeakCheck; @@ -31,7 +31,6 @@ use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; -use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; @@ -197,7 +196,7 @@ fn overlap<'tcx>( .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) .build(); - let selcx = &mut SelectionContext::new(&infcx); + let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx); if track_ambiguity_causes.is_yes() { selcx.enable_tracking_intercrate_ambiguity_causes(); } @@ -224,61 +223,10 @@ fn overlap<'tcx>( ); if overlap_mode.use_implicit_negative() { - for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] { - if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| { - impl_intersection_has_impossible_obligation(selcx, &obligations) - }) { - if matches!(mode, TreatInductiveCycleAs::Recur) { - let first_local_impl = impl1_header - .impl_def_id - .as_local() - .or(impl2_header.impl_def_id.as_local()) - .expect("expected one of the impls to be local"); - infcx.tcx.struct_span_lint_hir( - COINDUCTIVE_OVERLAP_IN_COHERENCE, - infcx.tcx.local_def_id_to_hir_id(first_local_impl), - infcx.tcx.def_span(first_local_impl), - format!( - "implementations {} will conflict in the future", - match impl1_header.trait_ref { - Some(trait_ref) => { - let trait_ref = infcx.resolve_vars_if_possible(trait_ref); - format!( - "of `{}` for `{}`", - trait_ref.print_trait_sugared(), - trait_ref.self_ty() - ) - } - None => format!( - "for `{}`", - infcx.resolve_vars_if_possible(impl1_header.self_ty) - ), - }, - ), - |lint| { - lint.note( - "impls that are not considered to overlap may be considered to \ - overlap in the future", - ) - .span_label( - infcx.tcx.def_span(impl1_header.impl_def_id), - "the first impl is here", - ) - .span_label( - infcx.tcx.def_span(impl2_header.impl_def_id), - "the second impl is here", - ); - lint.note(format!( - "`{}` may be considered to hold in future releases, \ - causing the impls to overlap", - infcx.resolve_vars_if_possible(failing_obligation.predicate) - )); - }, - ); - } - - return None; - } + if let Some(_failing_obligation) = + impl_intersection_has_impossible_obligation(selcx, &obligations) + { + return None; } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 451e0823c25..522c645253a 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -122,8 +122,8 @@ pub fn is_const_evaluatable<'tcx>( if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def) } else { span }, "failed to evaluate generic const expression", ) - .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") - .span_suggestion_verbose( + .with_note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`") + .with_span_suggestion_verbose( rustc_span::DUMMY_SP, "consider enabling this feature", "#![feature(generic_const_exprs)]\n", diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 90e2c1531b4..864580afe62 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -1,7 +1,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::Node; use rustc_middle::ty::{self, Ty}; @@ -140,7 +140,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let expected_str = args_str(&expected_args, &found_args); let found_str = args_str(&found_args, &expected_args); - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0593, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 52f91d282f0..100c9a70aaa 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_ast::AttrKind; use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, ErrorGuaranteed}; +use rustc_errors::{struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::GenericArgsRef; @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::iter; use crate::errors::{ @@ -521,7 +521,7 @@ impl<'tcx> OnUnimplementedDirective { pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> { if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { return Self::parse_attribute(attr, false, tcx, item_def_id); - } else if tcx.features().diagnostic_namespace { + } else { tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]) .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose()) .try_fold(None, |aggr: Option<Self>, directive| { @@ -592,8 +592,6 @@ impl<'tcx> OnUnimplementedDirective { Ok(Some(directive)) } }) - } else { - Ok(None) } } @@ -659,9 +657,7 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } else { - let reported = tcx - .dcx() - .span_delayed_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); + let reported = tcx.dcx().delayed_bug("of_item: neither meta_item_list nor value_str"); return Err(reported); }; debug!("of_item({:?}) = {:?}", item_def_id, result); @@ -799,7 +795,7 @@ impl<'tcx> OnUnimplementedFormatString { }, ); } else { - result = Err(struct_span_err!( + result = Err(struct_span_code_err!( tcx.dcx(), self.span, E0230, @@ -818,7 +814,7 @@ impl<'tcx> OnUnimplementedFormatString { } // `{:1}` and `{}` are not to be used Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { - let reported = struct_span_err!( + let reported = struct_span_code_err!( tcx.dcx(), self.span, E0231, 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 f63314081d6..6c0909d2853 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -13,17 +13,16 @@ use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, + error_code, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; +use rustc_hir::intravisit::{Map, Visitor}; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; -use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; -use rustc_hir::{Expr, HirId}; +use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; @@ -2008,7 +2007,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; err.code(error_code!(E0746)); - err.set_primary_message("return type cannot have an unboxed trait object"); + err.primary_message("return type cannot have an unboxed trait object"); err.children.clear(); let span = obligation.cause.span; @@ -2089,7 +2088,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ty = self.resolve_vars_if_possible(returned_ty); if ty.references_error() { // don't print out the [type error] here - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } else { err.span_label(expr.span, format!("this returned value is of type `{ty}`")); } @@ -2146,7 +2145,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Coroutine(..) => "coroutine", _ => "function", }; - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0631, @@ -2713,7 +2712,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; err.clear_code(); - err.set_primary_message(format!( + err.primary_message(format!( "{future_or_coroutine} cannot be {trait_verb} between threads safely" )); @@ -2801,7 +2800,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}")); span.push_span_label(original_span, message); - err.set_span(span); + err.span(span); format!("is not {trait_name}") } else { @@ -3200,35 +3199,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.help("unsized locals are gated as an unstable feature"); } } - ObligationCauseCode::SizedArgumentType(ty_span) => { - if let Some(span) = ty_span { - if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() - && let ty::ClauseKind::Trait(trait_pred) = clause - && let ty::Dynamic(..) = trait_pred.self_ty().kind() - { - let span = if let Ok(snippet) = - self.tcx.sess.source_map().span_to_snippet(span) - && snippet.starts_with("dyn ") - { - let pos = snippet.len() - snippet[3..].trim_start().len(); - span.with_hi(span.lo() + BytePos(pos as u32)) - } else { - span.shrink_to_lo() - }; - err.span_suggestion_verbose( - span, - "you can use `impl Trait` as the argument type", - "impl ".to_string(), - Applicability::MaybeIncorrect, - ); + ObligationCauseCode::SizedArgumentType(hir_id) => { + let mut ty = None; + let borrowed_msg = "function arguments must have a statically known size, borrowed \ + types always have a known size"; + if let Some(hir_id) = hir_id + && let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id) + && let Some(item) = self.tcx.hir().find_parent(hir_id) + && let Some(decl) = item.fn_decl() + && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span)) + { + // We use `contains` because the type might be surrounded by parentheses, + // which makes `ty_span` and `t.span` disagree with each other, but one + // fully contains the other: `foo: (dyn Foo + Bar)` + // ^-------------^ + // || + // |t.span + // param._ty_span + ty = Some(t); + } else if let Some(hir_id) = hir_id + && let Some(hir::Node::Ty(t)) = self.tcx.hir().find(hir_id) + { + ty = Some(t); + } + if let Some(ty) = ty { + match ty.kind { + hir::TyKind::TraitObject(traits, _, _) => { + let (span, kw) = match traits { + [first, ..] if first.span.lo() == ty.span.lo() => { + // Missing `dyn` in front of trait object. + (ty.span.shrink_to_lo(), "dyn ") + } + [first, ..] => (ty.span.until(first.span), ""), + [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), + }; + let needs_parens = traits.len() != 1; + err.span_suggestion_verbose( + span, + "you can use `impl Trait` as the argument type", + "impl ".to_string(), + Applicability::MaybeIncorrect, + ); + let sugg = if !needs_parens { + vec![(span.shrink_to_lo(), format!("&{kw}"))] + } else { + vec![ + (span.shrink_to_lo(), format!("&({kw}")), + (ty.span.shrink_to_hi(), ")".to_string()), + ] + }; + err.multipart_suggestion_verbose( + borrowed_msg, + sugg, + Applicability::MachineApplicable, + ); + } + hir::TyKind::Slice(_ty) => { + err.span_suggestion_verbose( + ty.span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed \ + slices always have a known size", + "&", + Applicability::MachineApplicable, + ); + } + hir::TyKind::Path(_) => { + err.span_suggestion_verbose( + ty.span.shrink_to_lo(), + borrowed_msg, + "&", + Applicability::MachineApplicable, + ); + } + _ => {} } - err.span_suggestion_verbose( - span.shrink_to_lo(), - "function arguments must have a statically known size, borrowed types \ - always have a known size", - "&", - Applicability::MachineApplicable, - ); } else { err.note("all function arguments must have a statically known size"); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index d2598b0defe..47a700805fa 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -19,7 +19,7 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey, Style, }; use rustc_hir as hir; @@ -228,7 +228,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - self.dcx().span_delayed_bug(DUMMY_SP, "expected fulfillment errors") + self.dcx().delayed_bug("expected fulfillment errors") } /// Reports that an overflow has occurred and halts compilation. We @@ -280,7 +280,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate.print(&mut cx).unwrap(); pred_str = cx.into_buffer(); } - let mut err = struct_span_err!( + let mut err = struct_span_code_err!( self.dcx(), span, E0275, @@ -525,7 +525,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { (err_msg, None) }; - let mut err = struct_span_err!(self.dcx(), span, E0277, "{}", err_msg); + let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); let mut suggested = false; if is_try_conversion { @@ -816,7 +816,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, trait_def_id, violations) + report_object_safety_error(self.tcx, span, None, trait_def_id, violations) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { @@ -924,7 +924,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, did, violations) + report_object_safety_error(self.tcx, span, None, did, violations) } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { @@ -1236,7 +1236,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span_bug!(span, "const param tys cannot mention other generic parameters"); } ty::Float(_) => { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0741, @@ -1244,7 +1244,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } ty::FnPtr(_) => { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0741, @@ -1252,7 +1252,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } ty::RawPtr(_) => { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0741, @@ -1261,7 +1261,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::Adt(def, _) => { // We should probably see if we're *allowed* to derive `ConstParamTy` on the type... - let mut diag = struct_span_err!( + let mut diag = struct_span_code_err!( self.dcx(), span, E0741, @@ -1293,7 +1293,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { diag } _ => { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0741, @@ -1731,7 +1731,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { cx.into_buffer() })) }); - let mut diag = struct_span_err!(self.dcx(), obligation.cause.span, E0271, "{msg}"); + let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}"); let secondary_span = (|| { let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = @@ -2421,7 +2421,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { true, ) } else { - struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0283, @@ -2525,14 +2525,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Replace the more general E0283 with a more specific error err.cancel(); - err = self.dcx().struct_span_err_with_code( + err = self.dcx().struct_span_err( span, format!( "cannot {verb} associated {noun} on trait without specifying the \ corresponding `impl` type", ), - rustc_errors::error_code!(E0790), ); + err.code(rustc_errors::error_code!(E0790)); if let Some(local_def_id) = data.trait_ref.def_id.as_local() && let Some(hir::Node::Item(hir::Item { @@ -2654,26 +2654,24 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); if let Some(subst) = subst { - let mut err = self.emit_inference_failure_err( + self.emit_inference_failure_err( obligation.cause.body_id, span, subst, ErrorCode::E0284, true, - ); - err.note(format!("cannot satisfy `{predicate}`")); - err + ) + .with_note(format!("cannot satisfy `{predicate}`")) } else { // If we can't find a substitution, just print a generic error - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) } } @@ -2693,30 +2691,28 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } else { // If we can't find a substitution, just print a generic error - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) } } _ => { if self.dcx().has_errors().is_some() || self.tainted_by_errors().is_some() { return; } - let mut err = struct_span_err!( + struct_span_code_err!( self.dcx(), span, E0284, "type annotations needed: cannot satisfy `{}`", predicate, - ); - err.span_label(span, format!("cannot satisfy `{predicate}`")); - err + ) + .with_span_label(span, format!("cannot satisfy `{predicate}`")) } }; self.note_obligation_cause(&mut err, obligation); @@ -3163,14 +3159,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) { match obligation_cause_code { ObligationCauseCode::RustCall => { - err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); + err.primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); } ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ItemObligation(def_id) if self.tcx.is_fn_trait(*def_id) => { err.code(rustc_errors::error_code!(E0059)); - err.set_primary_message(format!( + err.primary_message(format!( "type parameter to bare `{}` trait must be a tuple", self.tcx.def_path_str(*def_id) )); @@ -3548,17 +3544,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span: Span, ) -> Option<DiagnosticBuilder<'tcx>> { if !self.tcx.features().generic_const_exprs { - let mut err = self - .dcx() - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - // - // Note that with `feature(generic_const_exprs)` this case should not - // be reachable. - err.note("this may fail depending on what value the parameter takes"); - err.emit(); + self.dcx() + .struct_span_err(span, "constant expression depends on a generic parameter") + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + // + // Note that with `feature(generic_const_exprs)` this case should not + // be reachable. + .with_note("this may fail depending on what value the parameter takes") + .emit(); return None; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c52b8f37ef3..080ad7bd549 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -279,6 +279,12 @@ pub fn normalize_param_env_or_error<'tcx>( } fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + // FIXME(return_type_notation): track binders in this normalizer, as + // `ty::Const::normalize` can only work with properly preserved binders. + + if c.has_escaping_bound_vars() { + return ty::Const::new_misc_error(self.0, c.ty()); + } // While it is pretty sus to be evaluating things with an empty param env, it // should actually be okay since without `feature(generic_const_exprs)` the only // const arguments that have a non-empty param env are array repeat counts. These diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 9749ff9cbc1..5b349d576b6 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -65,8 +65,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { assert!(!ty.has_non_region_infer()); let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_ty = - self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values); + let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values); let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else { return vec![]; }; 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 d812d537d8c..31e34096fb0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -87,10 +87,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) } else { assert!(!self.intercrate); - let c_pred = self.canonicalize_query_keep_static( - param_env.and(obligation.predicate), - &mut _orig_values, - ); + let c_pred = + self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e8867187a40..0b73fefd2da 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -239,16 +239,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> } let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); + let mut concrete_ty = generic_ty.instantiate(self.interner(), args); self.anon_depth += 1; if concrete_ty == ty { - bug!( - "infinite recursion generic_ty: {:#?}, args: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", - generic_ty, - args, - concrete_ty, - ty + concrete_ty = Ty::new_error_with_message( + self.interner(), + DUMMY_SP, + "recursive opaque type", ); } let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); @@ -275,10 +272,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); - // HACK(matthewjasper) `'static` is special-cased in selection, - // so we cannot canonicalize it. - let c_data = infcx - .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values); + let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match kind { @@ -292,10 +286,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { - tcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("unexpected ambiguity: {c_data:?} {result:?}"), - ); + tcx.dcx() + .delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}")); } return Err(NoSolution); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index f4baae2711f..d533e69a4fa 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -6,7 +6,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{TyCtxt, TypeFoldable}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::fmt; @@ -88,10 +88,9 @@ where if errors.is_empty() { Ok(value) } else { - Err(infcx.dcx().span_delayed_bug( - DUMMY_SP, - format!("errors selecting obligation during MIR typeck: {errors:?}"), - )) + Err(infcx + .dcx() + .delayed_bug(format!("errors selecting obligation during MIR typeck: {errors:?}"))) } })?; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index cab2a62ed7e..957de925dd3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -111,14 +111,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't return Ok((result, None, vec![], Certainty::Proven)); } - // FIXME(#33684) -- We need to use - // `canonicalize_query_keep_static` here because of things - // like the subtype query, which go awry around - // `'static` otherwise. let mut canonical_var_values = OriginalQueryValues::default(); let old_param_env = query_key.param_env; - let canonical_self = - infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values); + let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values); let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; let InferOk { value, obligations } = infcx 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 54b91ab1d4d..342b12ba498 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -969,7 +969,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx().def_span(impl_def_id), "multiple drop impls found", ) - .span_note(self.tcx().def_span(old_impl_def_id), "other impl here") + .with_span_note( + self.tcx().def_span(old_impl_def_id), + "other impl here", + ) .delay_as_bug(); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c45925295ee..61fe2c8efe3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -239,20 +239,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - // Sets the `TreatInductiveCycleAs` mode temporarily in the selection context - pub fn with_treat_inductive_cycle_as<T>( - &mut self, - treat_inductive_cycle: TreatInductiveCycleAs, - f: impl FnOnce(&mut Self) -> T, - ) -> T { + pub fn with_treat_inductive_cycle_as_ambig( + infcx: &'cx InferCtxt<'tcx>, + ) -> SelectionContext<'cx, 'tcx> { // Should be executed in a context where caching is disabled, // otherwise the cache is poisoned with the temporary result. - assert!(self.is_intercrate()); - let treat_inductive_cycle = - std::mem::replace(&mut self.treat_inductive_cycle, treat_inductive_cycle); - let value = f(self); - self.treat_inductive_cycle = treat_inductive_cycle; - value + assert!(infcx.intercrate); + SelectionContext { + treat_inductive_cycle: TreatInductiveCycleAs::Ambig, + ..SelectionContext::new(infcx) + } } pub fn with_query_mode( diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index d43ab0c8e85..10329c623b3 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -345,7 +345,7 @@ fn report_negative_positive_conflict<'tcx>( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let mut err = tcx.dcx().create_err(NegativePositiveConflict { + let err = tcx.dcx().create_err(NegativePositiveConflict { impl_span: tcx.def_span(local_impl_def_id), trait_desc: overlap.trait_ref, self_ty: overlap.self_ty, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 19eae93df9c..c40ed10e52f 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -271,7 +271,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>( TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()), }; - let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() { + let trait_ref = if tcx.has_host_param(fn_trait_def_id) { ty::TraitRef::new( tcx, fn_trait_def_id, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 49f24f66b24..86a077ee808 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -199,6 +199,7 @@ pub(crate) mod rustc { match err { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, + LayoutError::Cycle(err) => Self::TypeError(*err), err => unimplemented!("{:?}", err), } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index db89fba2a89..b8351463c55 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::symbol::Symbol; -use rustc_span::DUMMY_SP; use rustc_target::abi::*; use std::fmt::Debug; @@ -91,7 +90,7 @@ fn univariant_uninterned<'tcx>( let dl = cx.data_layout(); let pack = repr.pack; if pack.is_some() && repr.align.is_some() { - cx.tcx.dcx().span_delayed_bug(DUMMY_SP, "struct cannot be packed and aligned"); + cx.tcx.dcx().delayed_bug("struct cannot be packed and aligned"); return Err(cx.tcx.arena.alloc(LayoutError::Unknown(ty))); } @@ -344,10 +343,7 @@ fn layout_of_uncached<'tcx>( ty::Adt(def, args) if def.repr().simd() => { if !def.is_struct() { // Should have yielded E0517 by now. - tcx.dcx().span_delayed_bug( - DUMMY_SP, - "#[repr(simd)] was applied to an ADT that is not a struct", - ); + tcx.dcx().delayed_bug("#[repr(simd)] was applied to an ADT that is not a struct"); return Err(error(cx, LayoutError::Unknown(ty))); } @@ -374,8 +370,7 @@ fn layout_of_uncached<'tcx>( // (should be caught by typeck) for fi in fields { if fi.ty(tcx, args) != f0_ty { - tcx.dcx().span_delayed_bug( - DUMMY_SP, + tcx.dcx().delayed_bug( "#[repr(simd)] was applied to an ADT with heterogeneous field type", ); return Err(error(cx, LayoutError::Unknown(ty))); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 38f0eb82180..59966423f7f 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -11,6 +11,7 @@ rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } smallvec = { version = "1.8.1" } # tidy-alphabetical-end @@ -21,6 +22,7 @@ nightly = [ "smallvec/union", "rustc_index/nightly", "rustc_serialize", + "rustc_span", "rustc_data_structures", "rustc_macros", ] diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index 2fbc8f76fa4..71f9eb0ef8a 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -1,7 +1,7 @@ use crate::{Interner, PredicateKind}; use rustc_data_structures::fx::FxHashMap; -use rustc_serialize::{Decoder, Encoder}; +use rustc_span::{SpanDecoder, SpanEncoder}; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -22,7 +22,7 @@ pub trait RefDecodable<'tcx, D: TyDecoder> { fn decode(d: &mut D) -> &'tcx Self; } -pub trait TyEncoder: Encoder { +pub trait TyEncoder: SpanEncoder { type I: Interner; const CLEAR_CROSS_CRATE: bool; @@ -35,7 +35,7 @@ pub trait TyEncoder: Encoder { fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId); } -pub trait TyDecoder: Decoder { +pub trait TyDecoder: SpanDecoder { type I: Interner; const CLEAR_CROSS_CRATE: bool; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index f52e506059b..fb83dae5714 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -16,8 +16,8 @@ use crate::ty::{ TraitDef, Ty, TyKind, VariantDef, }; use crate::{ - mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol, - TraitDecls, + mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind, + Symbol, TraitDecls, }; /// This trait defines the interface between stable_mir and the Rust compiler. @@ -32,8 +32,10 @@ pub trait Context { /// Check whether the body of a function is available. fn has_body(&self, item: DefId) -> bool; fn all_trait_decls(&self) -> TraitDecls; + fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls; fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; fn all_trait_impls(&self) -> ImplTraitDecls; + fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls; fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait; fn generics_of(&self, def_id: DefId) -> Generics; fn predicates_of(&self, def_id: DefId) -> GenericPredicates; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 9194f1e6bdb..de5dfcdf207 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -31,7 +31,7 @@ pub use crate::error::*; use crate::mir::pretty::function_name; use crate::mir::Body; use crate::mir::Mutability; -use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty}; +use crate::ty::{ImplDef, IndexedVal, Span, TraitDef, Ty}; pub mod abi; #[macro_use] @@ -86,6 +86,18 @@ pub struct Crate { pub is_local: bool, } +impl Crate { + /// The list of traits declared in this crate. + pub fn trait_decls(&self) -> TraitDecls { + with(|cx| cx.trait_decls(self.id)) + } + + /// The list of trait implementations in this crate. + pub fn trait_impls(&self) -> ImplTraitDecls { + with(|cx| cx.trait_impls(self.id)) + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum ItemKind { Fn, @@ -169,18 +181,10 @@ pub fn all_trait_decls() -> TraitDecls { with(|cx| cx.all_trait_decls()) } -pub fn trait_decl(trait_def: &TraitDef) -> TraitDecl { - with(|cx| cx.trait_decl(trait_def)) -} - pub fn all_trait_impls() -> ImplTraitDecls { with(|cx| cx.all_trait_impls()) } -pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { - with(|cx| cx.trait_impl(trait_impl)) -} - /// A type that provides internal information but that can still be used for debug purpose. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Opaque(String); diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 9e6ecbe8315..eba2ac57012 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -714,9 +714,16 @@ crate_def! { } crate_def! { + /// A trait's definition. pub TraitDef; } +impl TraitDef { + pub fn declaration(trait_def: &TraitDef) -> TraitDecl { + with(|cx| cx.trait_decl(trait_def)) + } +} + crate_def! { pub GenericDef; } @@ -726,9 +733,17 @@ crate_def! { } crate_def! { + /// A trait impl definition. pub ImplDef; } +impl ImplDef { + /// Retrieve information about this implementation. + pub fn trait_impl(&self) -> ImplTrait { + with(|cx| cx.trait_impl(self)) + } +} + crate_def! { pub RegionDef; } |
