diff options
Diffstat (limited to 'compiler')
239 files changed, 3451 insertions, 3331 deletions
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index e549724b1c0..5031e7a6705 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" rand = { version = "0.8.4", default-features = false, optional = true } rand_xoshiro = { version = "0.6.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index eb42803f93e..549927d5898 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -29,10 +29,12 @@ pub use layout::LayoutCalculator; /// instead of implementing everything in `rustc_middle`. pub trait HashStableContext {} +#[derive(Clone, Copy, PartialEq, Eq, Default)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] +pub struct ReprFlags(u8); + bitflags! { - #[derive(Default)] - #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] - pub struct ReprFlags: u8 { + impl ReprFlags: u8 { const IS_C = 1 << 0; const IS_SIMD = 1 << 1; const IS_TRANSPARENT = 1 << 2; @@ -42,11 +44,12 @@ bitflags! { // the seed stored in `ReprOptions.layout_seed` const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. - const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits - | ReprFlags::IS_SIMD.bits - | ReprFlags::IS_LINEAR.bits; + const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits() + | ReprFlags::IS_SIMD.bits() + | ReprFlags::IS_LINEAR.bits(); } } +rustc_data_structures::external_bitflags_debug! { ReprFlags } #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))] diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 59e3d85589a..937ee4bcd42 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" memchr = "2.5.0" rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9a9c769fd7c..1812cc335a4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2171,9 +2171,10 @@ pub enum InlineAsmRegOrRegClass { RegClass(Symbol), } +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] +pub struct InlineAsmOptions(u16); bitflags::bitflags! { - #[derive(Encodable, Decodable, HashStable_Generic)] - pub struct InlineAsmOptions: u16 { + impl InlineAsmOptions: u16 { const PURE = 1 << 0; const NOMEM = 1 << 1; const READONLY = 1 << 2; @@ -2186,6 +2187,12 @@ bitflags::bitflags! { } } +impl std::fmt::Debug for InlineAsmOptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + bitflags::parser::to_writer(self, f) + } +} + #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)] pub enum InlineAsmTemplatePiece { String(String), diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 4c0c496584e..053468ff936 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -26,7 +26,7 @@ use rustc_span::{sym, Span, 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) @@ -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 5a1b1c799eb..fd94e7e9341 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -45,8 +45,6 @@ ast_lowering_closure_cannot_be_static = closures cannot be static ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) -ast_lowering_default_parameter_in_binder = default parameter is not allowed in this binder - ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers @@ -58,6 +56,9 @@ ast_lowering_functional_record_update_destructuring_assignment = functional record updates are not allowed in destructuring assignments .suggestion = consider removing the trailing pattern +ast_lowering_generic_param_default_in_binder = + defaults for generic parameters are not allowed in `for<...>` binders + ast_lowering_generic_type_with_parentheses = parenthesized type parameters may only be used with a `Fn` trait .label = only `Fn` traits may use parentheses diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 718a5b03cf2..710690d0d86 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -397,8 +397,8 @@ pub enum BadReturnTypeNotation { } #[derive(Diagnostic)] -#[diag(ast_lowering_default_parameter_in_binder)] -pub(crate) struct UnexpectedDefaultParameterInBinder { +#[diag(ast_lowering_generic_param_default_in_binder)] +pub(crate) struct GenericParamDefaultInBinder { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e568da9bbc0..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 mut 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); @@ -578,10 +565,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } } else if let Some(body) = &arm.body { self.dcx().emit_err(NeverPatternWithBody { span: body.span }); - guard = None; } else if let Some(g) = &arm.guard { self.dcx().emit_err(NeverPatternWithGuard { span: g.span }); - guard = None; } // We add a fake `loop {}` arm body so that it typecks to `!`. diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 45357aca533..c618953461c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1241,11 +1241,13 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option<CoroutineKind>, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); + // Don't pass along the user-provided constness of trait associated functions; we don't want to + // synthesize a host effect param for them. We reject `const` on them during AST validation. + let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 92fd29c47af..fb59770d48a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -66,7 +66,6 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{DesugaringKind, Span, DUMMY_SP}; use smallvec::SmallVec; -use std::borrow::Cow; use std::collections::hash_map::Entry; use thin_vec::ThinVec; @@ -884,27 +883,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { binder: NodeId, generic_params: &[GenericParam], ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = generic_params - .iter() - .map(|param| { - let param = match param.kind { - GenericParamKind::Type { ref default } if let Some(ty) = default => { - // Default type is not permitted in non-lifetime binders. - // So we emit an error and default to `None` to prevent - // potential ice. - self.dcx().emit_err(errors::UnexpectedDefaultParameterInBinder { - span: ty.span(), - }); - let param = GenericParam { - kind: GenericParamKind::Type { default: None }, - ..param.clone() - }; - Cow::Owned(param) - } - _ => Cow::Borrowed(param), - }; - self.lower_generic_param(param.as_ref(), hir::GenericParamSource::Binder) - }) + let mut generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) .collect(); let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); @@ -1454,19 +1434,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)); @@ -2136,7 +2118,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind(param); + let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2155,6 +2137,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_param_kind( &mut self, param: &GenericParam, + source: hir::GenericParamSource, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2173,22 +2156,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (param_name, kind) } GenericParamKind::Type { default, .. } => { - let kind = hir::GenericParamKind::Type { - default: default.as_ref().map(|x| { + // Not only do we deny type param defaults in binders but we also map them to `None` + // since later compiler stages cannot handle them (and shouldn't need to be able to). + let default = default + .as_ref() + .filter(|_| match source { + hir::GenericParamSource::Generics => true, + hir::GenericParamSource::Binder => { + self.dcx().emit_err(errors::GenericParamDefaultInBinder { + span: param.span(), + }); + + false + } + }) + .map(|def| { self.lower_ty( - x, + def, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), ) - }), - synthetic: false, - }; + }); + + let kind = hir::GenericParamKind::Type { default, synthetic: false }; (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, kw_span: _, default } => { let ty = self .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); - let default = default.as_ref().map(|def| self.lower_anon_const(def)); + + // Not only do we deny const param defaults in binders but we also map them to `None` + // since later compiler stages cannot handle them (and shouldn't need to be able to). + let default = default + .as_ref() + .filter(|_| match source { + hir::GenericParamSource::Generics => true, + hir::GenericParamSource::Binder => { + self.dcx().emit_err(errors::GenericParamDefaultInBinder { + span: param.span(), + }); + + false + } + }) + .map(|def| self.lower_anon_const(def)); + ( hir::ParamName::Plain(self.lower_ident(param.ident)), hir::GenericParamKind::Const { ty, default, is_host_effect: false }, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b5612c1820d..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 @@ -233,8 +236,21 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here .item = this item cannot have `~const` trait bounds ast_passes_trait_fn_const = - functions in traits cannot be declared const - .label = functions in traits cannot be const + functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be declared const + .label = functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be const + .const_context_label = this declares all associated functions implicitly const + .remove_const_sugg = remove the `const`{$requires_multiple_changes -> + [true] {" ..."} + *[false] {""} + } + .make_impl_const_sugg = ... and declare the impl to be const instead + .make_trait_const_sugg = ... and declare the trait to be a `#[const_trait]` instead ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bc5cf463f12..7f78f687055 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -46,6 +46,21 @@ enum DisallowTildeConstContext<'a> { Item, } +enum TraitOrTraitImpl<'a> { + Trait { span: Span, constness: Option<Span> }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, +} + +impl<'a> TraitOrTraitImpl<'a> { + fn constness(&self) -> Option<Span> { + match self { + Self::Trait { constness: Some(span), .. } + | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), + _ => None, + } + } +} + struct AstValidator<'a> { session: &'a Session, features: &'a Features, @@ -53,11 +68,7 @@ struct AstValidator<'a> { /// The span of the `extern` in an `extern { ... }` block, if any. extern_mod: Option<&'a Item>, - /// Are we inside a trait impl? - in_trait_impl: bool, - - /// Are we inside a const trait defn or impl? - in_const_trait_or_impl: bool, + outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>, has_proc_macro_decls: bool, @@ -78,24 +89,28 @@ struct AstValidator<'a> { impl<'a> AstValidator<'a> { fn with_in_trait_impl( &mut self, - is_in: bool, - constness: Option<Const>, + trait_: Option<(Const, ImplPolarity, &'a TraitRef)>, f: impl FnOnce(&mut Self), ) { - let old = mem::replace(&mut self.in_trait_impl, is_in); - let old_const = mem::replace( - &mut self.in_const_trait_or_impl, - matches!(constness, Some(Const::Yes(_))), + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { + constness, + polarity, + trait_ref, + }), ); f(self); - self.in_trait_impl = old; - self.in_const_trait_or_impl = old_const; + self.outer_trait_or_trait_impl = old; } - fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.in_const_trait_or_impl, is_const); + fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) { + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + Some(TraitOrTraitImpl::Trait { span, constness }), + ); f(self); - self.in_const_trait_or_impl = old; + self.outer_trait_or_trait_impl = old; } fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { @@ -291,10 +306,48 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Const) { - if let Const::Yes(span) = constness { - self.dcx().emit_err(errors::TraitFnConst { span }); - } + fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { + let Const::Yes(span) = constness else { + return; + }; + + let make_impl_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::TraitImpl { + constness: Const::No, + polarity: ImplPolarity::Positive, + trait_ref, + } = parent + { + Some(trait_ref.path.span.shrink_to_lo()) + } else { + None + }; + + let make_trait_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::Trait { span, constness: None } = parent + { + Some(span.shrink_to_lo()) + } else { + None + }; + + let parent_constness = parent.constness(); + self.dcx().emit_err(errors::TraitFnConst { + span, + in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), + const_context_label: parent_constness, + remove_const_sugg: ( + self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + match parent_constness { + Some(_) => rustc_errors::Applicability::MachineApplicable, + None => rustc_errors::Applicability::MaybeIncorrect, + }, + ), + requires_multiple_changes: make_impl_const_sugg.is_some() + || make_trait_const_sugg.is_some(), + make_impl_const_sugg, + make_trait_const_sugg, + }); } fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { @@ -817,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items, }) => { - self.with_in_trait_impl(true, Some(*constness), |this| { + self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { this.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, @@ -963,8 +1016,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { - let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait); - self.with_in_trait(is_const_trait, |this| { + let is_const_trait = + attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + self.with_in_trait(item.span, is_const_trait, |this| { if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. this.deny_generic_params(generics, item.ident.span); @@ -977,8 +1031,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // context for the supertraits. this.visit_vis(&item.vis); this.visit_ident(item.ident); - let disallowed = - (!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span)); + let disallowed = is_const_trait + .is_none() + .then(|| DisallowTildeConstContext::Trait(item.span)); this.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) @@ -1257,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 => {} } } @@ -1342,7 +1408,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) - || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl); + || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))) + && self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some(); let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); @@ -1353,7 +1424,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_nomangle_item_asciionly(item.ident, item.span); } - if ctxt == AssocCtxt::Trait || !self.in_trait_impl { + if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { self.check_defaultness(item.span, item.kind.defaultness()); } @@ -1401,10 +1472,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); } - if ctxt == AssocCtxt::Trait || self.in_trait_impl { + if let Some(parent) = &self.outer_trait_or_trait_impl { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.check_trait_fn_not_const(sig.header.constness); + self.check_trait_fn_not_const(sig.header.constness, parent); } } @@ -1414,7 +1485,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match &item.kind { AssocItemKind::Fn(box Fn { sig, generics, body, .. }) - if self.in_const_trait_or_impl + if self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some() || ctxt == AssocCtxt::Trait || matches!(sig.header.constness, Const::Yes(_)) => { @@ -1430,8 +1505,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); self.visit_fn(kind, item.span, item.id); } - _ => self - .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), + _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), } } } @@ -1547,8 +1621,7 @@ pub fn check_crate( session, features, extern_mod: None, - in_trait_impl: false, - in_const_trait_or_impl: false, + outer_trait_or_trait_impl: None, has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 0cec4374be2..fcf19ce52ec 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::AddToDiagnostic; +use rustc_errors::{AddToDiagnostic, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -49,6 +49,24 @@ pub struct TraitFnConst { #[primary_span] #[label] pub span: Span, + pub in_impl: bool, + #[label(ast_passes_const_context_label)] + pub const_context_label: Option<Span>, + #[suggestion(ast_passes_remove_const_sugg, code = "")] + pub remove_const_sugg: (Span, Applicability), + pub requires_multiple_changes: bool, + #[suggestion( + ast_passes_make_impl_const_sugg, + code = "const ", + applicability = "maybe-incorrect" + )] + pub make_impl_const_sugg: Option<Span>, + #[suggestion( + ast_passes_make_trait_const_sugg, + code = "#[const_trait]\n", + applicability = "maybe-incorrect" + )] + pub make_trait_const_sugg: Option<Span>, } #[derive(Diagnostic)] @@ -707,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); } } @@ -746,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_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index fd2b0866867..fdb5d66bf62 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -55,10 +55,10 @@ 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.span(self.span); diag.code(error_code!(E0541)); - diag.set_arg("item", self.item); - diag.set_arg("expected", expected.join(", ")); + diag.arg("item", self.item); + diag.arg("expected", expected.join(", ")); diag.span_label(self.span, fluent::attr_label); diag } @@ -215,7 +215,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/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3ec07572d1d..9ce753134fb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3067,7 +3067,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option<AnnotatedBorrowFnSignature<'tcx>> { // Define a fallback for when we can't match a closure. let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id()); + let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id()); if is_closure { None } else { @@ -3277,7 +3277,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { sig: ty::PolyFnSig<'tcx>, ) -> Option<AnnotatedBorrowFnSignature<'tcx>> { debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure(did.to_def_id()); + let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id()); let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; @@ -3590,7 +3590,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/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index f717d91c35c..61b6bef3b87 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -22,7 +22,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self, body), level = "debug")] pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { let mir_def_id = body.source.def_id().expect_local(); - if !self.tcx().is_closure(mir_def_id.to_def_id()) { + if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) { return; } let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); @@ -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/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index e07eb2e490b..f9ddffcc155 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); } @@ -808,7 +808,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { level, crate::fluent_generated::builtin_macros_asm_clobber_no_reg, ); - diag.set_span(self.spans.clone()); + diag.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, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 2af46f175d7..568f8247b28 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -395,10 +395,10 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) // 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 }, + _ => 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, diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 05dc28d0745..9bbb18fc37f 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -175,14 +175,10 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Cache cargo bin dir - uses: actions/cache@v3 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - name: Install hyperfine - run: cargo install hyperfine || true + run: | + sudo apt update + sudo apt install -y hyperfine - name: Prepare dependencies run: ./y.sh prepare @@ -257,14 +253,14 @@ jobs: - name: Upload prebuilt cg_clif if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - name: Upload prebuilt cg_clif (cross compile) if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cg_clif-${{ runner.os }}-cross-x86_64-mingw path: cg_clif.tar.xz @@ -283,7 +279,7 @@ jobs: - uses: actions/checkout@v3 - name: Download all built artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts/ diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index cb5dd51fee3..8085dc58263 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -43,6 +43,11 @@ jobs: path: build/cg_clif key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + - name: Install ripgrep + run: | + sudo apt update + sudo apt install -y ripgrep + - name: Prepare dependencies run: ./y.sh prepare diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index e1e1760c597..a086c029360 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-24" +channel = "nightly-2023-12-31" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 731828caae2..684a5d07293 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we +# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as # the LLVM backend isn't compiled in here. export CG_CLIF_FORCE_GNU_AS=1 @@ -11,20 +11,19 @@ export CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build echo "[SETUP] Rust fork" -git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true +git clone --quiet https://github.com/rust-lang/rust.git --filter=tree:0 || true pushd rust git fetch -git checkout -- . -git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" +git checkout --no-progress -- . +git checkout --no-progress "$(rustc -V | cut -d' ' -f3 | tr -d '(')" + +git submodule update --quiet --init src/tools/cargo library/backtrace library/stdarch git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \ am ../patches/*-stdlib-*.patch cat > config.toml <<EOF -change-id = 115898 - -[llvm] -ninja = false +change-id = 999999 [build] rustc = "$(pwd)/../dist/bin/rustc-clif" diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 7905ec8402d..a8d8fb189e2 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -321,7 +321,7 @@ fn dep_symbol_lookup_fn( Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = crate_info.crate_name[&cnum]; - let mut err = sess.struct_err(format!("Can't load static lib {}", name)); + 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(); } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index af99239d815..da07b66c762 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -154,6 +154,8 @@ pub(crate) fn compile_global_asm( } } else { let mut child = Command::new(std::env::current_exe().unwrap()) + // Avoid a warning about the jobserver fd not being passed + .env_remove("CARGO_MAKEFLAGS") .arg("--target") .arg(&config.target) .arg("--crate-type") 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_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 7122c055e7e..c12142e302d 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -8,7 +8,7 @@ test = false [dependencies] # tidy-alphabetical-start -bitflags = "1.0" +bitflags = "2.4.1" itertools = "0.11" libc = "0.2" measureme = "10.0.0" 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/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 3cc33b83434..b3fa7b7cd44 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -481,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // `+multivalue` feature because the purpose of the wasm abi is to match // the WebAssembly specification, which has this feature. This won't be // needed when LLVM enables this `multivalue` feature by default. - if !cx.tcx.is_closure(instance.def_id()) { + if !cx.tcx.is_closure_or_coroutine(instance.def_id()) { let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); if abi == Abi::Wasm { function_features.push("+multivalue".to_string()); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c607533a08e..45be85934b4 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -416,7 +416,7 @@ fn report_inline_asm( cookie = 0; } let level = match level { - llvm::DiagnosticLevel::Error => Level::Error { lint: false }, + llvm::DiagnosticLevel::Error => Level::Error, llvm::DiagnosticLevel::Warning => Level::Warning(None), llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; 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/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 33bfde03a31..51df14df644 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -58,11 +58,6 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { return; } - // The entries of the map are only used to get a list of all files with - // coverage info. In the end the list of files is passed into - // `GlobalFileTable::new()` which internally do `.sort_unstable_by()`, so - // the iteration order here does not matter. - #[allow(rustc::potential_query_instability)] let function_coverage_entries = function_coverage_map .into_iter() .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 0befbb5a39b..733a77d24c2 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::{ BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods, StaticMethods, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; @@ -30,7 +30,7 @@ const VAR_ALIGN_BYTES: usize = 8; pub struct CrateCoverageContext<'ll, 'tcx> { /// Coverage data for each instrumented function identified by DefId. pub(crate) function_coverage_map: - RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>, + RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>, pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>, } @@ -44,8 +44,8 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { pub fn take_function_coverage_map( &self, - ) -> FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> { - self.function_coverage_map.replace(FxHashMap::default()) + ) -> FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> { + self.function_coverage_map.replace(FxIndexMap::default()) } } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 8db97d577ca..422e8edff5f 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -107,7 +107,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_ let mut diag = DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config); - diag.set_arg("error", message); + diag.arg("error", message); diag } } @@ -130,12 +130,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 } } @@ -205,8 +205,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> { 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.primary_message(msg_with_llvm_err); + diag.arg("llvm_err", self.1); diag } } 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/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 81702baa8c0..aefca6b34f5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -722,7 +722,7 @@ pub mod debuginfo { // These values **must** match with LLVMRustDIFlags!! bitflags! { #[repr(transparent)] - #[derive(Default)] + #[derive(Clone, Copy, Default)] pub struct DIFlags: u32 { const FlagZero = 0; const FlagPrivate = 1; @@ -751,7 +751,7 @@ pub mod debuginfo { // These values **must** match with LLVMRustDISPFlags!! bitflags! { #[repr(transparent)] - #[derive(Default)] + #[derive(Clone, Copy, Default)] pub struct DISPFlags: u32 { const SPFlagZero = 0; const SPFlagVirtual = 1; 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/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3f2ed257d08..7d2f5bb193a 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start ar_archive_writer = "0.1.5" -bitflags = "1.2.1" +bitflags = "2.4.1" cc = "1.0.69" itertools = "0.11" jobserver = "0.1.27" diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4ff497f2fdd..215649f33ff 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -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 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..d2c6b6e0c7b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1848,9 +1848,9 @@ impl SharedEmitterMain { } 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, + Level::Error => Level::Error, + Level::Warning(_) => Level::Warning(None), + Level::Note => Level::Note, _ => bug!("Invalid inline asm diagnostic level"), }; let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); @@ -1860,7 +1860,7 @@ impl SharedEmitterMain { 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 f5f2416abb6..63fd7b42f7b 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -232,7 +232,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { - let is_closure = tcx.is_closure(did.to_def_id()); + let is_closure = tcx.is_closure_or_coroutine(did.to_def_id()); if !is_closure && let Some(fn_sig) = fn_sig() @@ -277,7 +277,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } sym::target_feature => { - if !tcx.is_closure(did.to_def_id()) + if !tcx.is_closure_or_coroutine(did.to_def_id()) && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal { @@ -531,7 +531,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. if tcx.features().target_feature_11 - && tcx.is_closure(did.to_def_id()) + && tcx.is_closure_or_coroutine(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { let owner_id = tcx.parent(did.to_def_id()); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 2b628d2aa69..c1086bebb8d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -244,30 +244,30 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } thorin::Error::NamelessSection(_, offset) => { diag = build(fluent::codegen_ssa_thorin_section_without_name); - diag.set_arg("offset", format!("0x{offset:08x}")); + diag.arg("offset", format!("0x{offset:08x}")); diag } 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.arg("section", section); + diag.arg("offset", format!("0x{offset:08x}")); diag } 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.arg("section", section); + diag.arg("offset", format!("0x{offset:08x}")); diag } 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.arg("section", section); + diag.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.arg("id", format!("0x{id:08x}")); diag } thorin::Error::NoCompilationUnits => { @@ -284,7 +284,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } thorin::Error::MissingRequiredSection(section) => { diag = build(fluent::codegen_ssa_thorin_missing_required_section); - diag.set_arg("section", section); + diag.arg("section", section); diag } thorin::Error::ParseUnitAbbreviations(_) => { @@ -305,34 +305,34 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } 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.arg("section", section); + diag.arg("actual", actual); + diag.arg("format", format); diag } thorin::Error::OffsetAtIndex(_, index) => { diag = build(fluent::codegen_ssa_thorin_offset_at_index); - diag.set_arg("index", index); + diag.arg("index", index); diag } thorin::Error::StrAtOffset(_, offset) => { diag = build(fluent::codegen_ssa_thorin_str_at_offset); - diag.set_arg("offset", format!("0x{offset:08x}")); + diag.arg("offset", format!("0x{offset:08x}")); diag } thorin::Error::ParseIndex(_, section) => { diag = build(fluent::codegen_ssa_thorin_parse_index); - diag.set_arg("section", section); + diag.arg("section", section); diag } thorin::Error::UnitNotInIndex(unit) => { diag = build(fluent::codegen_ssa_thorin_unit_not_in_index); - diag.set_arg("unit", format!("0x{unit:08x}")); + diag.arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::RowNotInIndex(_, row) => { diag = build(fluent::codegen_ssa_thorin_row_not_in_index); - diag.set_arg("row", row); + diag.arg("row", row); diag } thorin::Error::SectionNotInRow => { @@ -341,7 +341,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } thorin::Error::EmptyUnit(unit) => { diag = build(fluent::codegen_ssa_thorin_empty_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); + diag.arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::MultipleDebugInfoSection => { @@ -358,12 +358,12 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } thorin::Error::DuplicateUnit(unit) => { diag = build(fluent::codegen_ssa_thorin_duplicate_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); + diag.arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::MissingReferencedUnit(unit) => { diag = build(fluent::codegen_ssa_thorin_missing_referenced_unit); - diag.set_arg("unit", format!("0x{unit:08x}")); + diag.arg("unit", format!("0x{unit:08x}")); diag } thorin::Error::NoOutputObjectCreated => { @@ -376,27 +376,27 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ThorinErrorWrapper { } thorin::Error::Io(e) => { diag = build(fluent::codegen_ssa_thorin_io); - diag.set_arg("error", format!("{e}")); + diag.arg("error", format!("{e}")); diag } thorin::Error::ObjectRead(e) => { diag = build(fluent::codegen_ssa_thorin_object_read); - diag.set_arg("error", format!("{e}")); + diag.arg("error", format!("{e}")); diag } thorin::Error::ObjectWrite(e) => { diag = build(fluent::codegen_ssa_thorin_object_write); - diag.set_arg("error", format!("{e}")); + diag.arg("error", format!("{e}")); diag } thorin::Error::GimliRead(e) => { diag = build(fluent::codegen_ssa_thorin_gimli_read); - diag.set_arg("error", format!("{e}")); + diag.arg("error", format!("{e}")); diag } thorin::Error::GimliWrite(e) => { diag = build(fluent::codegen_ssa_thorin_gimli_write); - diag.set_arg("error", format!("{e}")); + diag.arg("error", format!("{e}")); diag } _ => unimplemented!("Untranslated thorin error"), @@ -414,8 +414,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/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9b60f0844a0..0d88df63280 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -110,6 +110,7 @@ pub enum ModuleKind { } bitflags::bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MemFlags: u8 { const VOLATILE = 1 << 0; const NONTEMPORAL = 1 << 1; 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..b6bb1607a09 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 }; 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/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index fbc95072802..98276ff2e68 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn fn_sig(&self) -> PolyFnSig<'tcx> { let did = self.def_id().to_def_id(); - if self.tcx.is_closure(did) { + if self.tcx.is_closure_or_coroutine(did) { let ty = self.tcx.type_of(did).instantiate_identity(); let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") }; args.as_closure().sig() 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/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 4732783a12d..23949deaade 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -bitflags = "1.2.1" +bitflags = "2.4.1" elsa = "=1.7.1" ena = "0.14.2" indexmap = { version = "2.0.0" } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 3ef87684fa5..93b4032c310 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -150,3 +150,14 @@ pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl // See comments in src/librustc_middle/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} + +#[macro_export] +macro_rules! external_bitflags_debug { + ($Name:ident) => { + impl ::std::fmt::Debug for $Name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::bitflags::parser::to_writer(self, f) + } + } + }; +} diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index ef7375a7320..e29d4811980 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -101,6 +101,7 @@ use parking_lot::RwLock; use smallvec::SmallVec; bitflags::bitflags! { + #[derive(Clone, Copy)] struct EventFilter: u16 { const GENERIC_ACTIVITIES = 1 << 0; const QUERY_PROVIDERS = 1 << 1; @@ -114,14 +115,14 @@ bitflags::bitflags! { const INCR_RESULT_HASHING = 1 << 8; const ARTIFACT_SIZES = 1 << 9; - const DEFAULT = Self::GENERIC_ACTIVITIES.bits | - Self::QUERY_PROVIDERS.bits | - Self::QUERY_BLOCKED.bits | - Self::INCR_CACHE_LOADS.bits | - Self::INCR_RESULT_HASHING.bits | - Self::ARTIFACT_SIZES.bits; + const DEFAULT = Self::GENERIC_ACTIVITIES.bits() | + Self::QUERY_PROVIDERS.bits() | + Self::QUERY_BLOCKED.bits() | + Self::INCR_CACHE_LOADS.bits() | + Self::INCR_RESULT_HASHING.bits() | + Self::ARTIFACT_SIZES.bits(); - const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits; + const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits(); } } 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/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 47c56eba7ad..bd4dff6f62f 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 } } @@ -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 } @@ -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). /// diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index ca6b0afc76a..fd925b62702 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)] @@ -1249,8 +1250,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 +1393,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, )); diff --git a/compiler/rustc_error_codes/src/error_codes/E0379.md b/compiler/rustc_error_codes/src/error_codes/E0379.md index ab438e41447..35f546cfdb7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0379.md +++ b/compiler/rustc_error_codes/src/error_codes/E0379.md @@ -6,6 +6,10 @@ Erroneous code example: trait Foo { const fn bar() -> u32; // error! } + +impl Foo for () { + const fn bar() -> u32 { 0 } // error! +} ``` Trait methods cannot be declared `const` by design. For more information, see diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 48e48f59a99..5c0e210f147 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,9 +86,7 @@ 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::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error, Level::Warning(_) => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help | Level::OnceHelp => AnnotationType::Help, @@ -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 c226b2d41bd..701c1c02ab0 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -3,7 +3,7 @@ use crate::{ CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; @@ -212,6 +212,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,11 +244,9 @@ 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::Note @@ -259,7 +260,7 @@ impl Diagnostic { pub(crate) fn update_unstable_expectation_id( &mut self, - unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, + unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>, ) { if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) = &mut self.level @@ -308,25 +309,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 +347,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 { @@ -876,7 +879,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 +887,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 +906,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 +918,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..e018c14a4a5 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -31,7 +31,7 @@ where { 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.span(self.span); diag } } @@ -207,11 +207,11 @@ macro_rules! forward { // Forward pattern for &mut self -> &mut Self ( $(#[$attrs:meta])* - pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self + pub fn $n:ident(&mut self $(, $name:ident: $ty:ty)* $(,)?) -> &mut Self ) => { $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] - pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { + pub fn $n(&mut self $(, $name: $ty)*) -> &mut Self { self.diagnostic.$n($($name),*); self } @@ -356,35 +356,16 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { 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( + forward!(pub fn span_label( + &mut self, + span: Span, + label: impl Into<SubdiagnosticMessage> + ) -> &mut Self); + forward!(pub fn span_labels( &mut self, spans: impl IntoIterator<Item = Span>, label: &str, ) -> &mut Self); - forward!(pub fn note_expected_found( &mut self, expected_label: &dyn fmt::Display, @@ -392,7 +373,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { found_label: &dyn fmt::Display, found: DiagnosticStyledString, ) -> &mut Self); - forward!(pub fn note_expected_found_extra( &mut self, expected_label: &dyn fmt::Display, @@ -402,7 +382,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { 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( @@ -428,10 +407,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { 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 is_lint(&mut self) -> &mut Self); + forward!(pub fn disable_suggestions(&mut self) -> &mut Self); forward!(pub fn multipart_suggestion( &mut self, msg: impl Into<SubdiagnosticMessage>, @@ -498,16 +475,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { 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 primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self); + forward!(pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); - forward!(pub fn set_arg( + forward!(pub fn arg( &mut self, name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg, ) -> &mut Self); - forward!(pub fn subdiagnostic( &mut self, subdiagnostic: impl crate::AddToDiagnostic diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 29cb304e8b5..de27c6e910b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -254,29 +254,29 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> 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.arg("addr_space", addr_space); + diag.arg("cause", cause); + diag.arg("err", err); diag } 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.arg("kind", kind); + diag.arg("bit", bit); + diag.arg("cause", cause); + diag.arg("err", err); diag } TargetDataLayoutErrors::MissingAlignment { cause } => { diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_missing_alignment); - diag.set_arg("cause", cause); + diag.arg("cause", cause); diag } 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.arg("cause", cause); + diag.arg("err_kind", err.diag_ident()); + diag.arg("align", err.align()); diag } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { @@ -285,8 +285,8 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> level, fluent::errors_target_inconsistent_architecture, ); - diag.set_arg("dl", dl); - diag.set_arg("target", target); + diag.arg("dl", dl); + diag.arg("target", target); diag } TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { @@ -295,13 +295,13 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetDataLayoutErrors<'_> level, fluent::errors_target_inconsistent_pointer_width, ); - diag.set_arg("pointer_size", pointer_size); - diag.set_arg("target", target); + diag.arg("pointer_size", pointer_size); + diag.arg("target", target); diag } TargetDataLayoutErrors::InvalidBitsSize { err } => { diag = DiagnosticBuilder::new(dcx, level, fluent::errors_target_invalid_bits_size); - diag.set_arg("err", err); + diag.arg("err", err); diag } } 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/lib.rs b/compiler/rustc_errors/src/lib.rs index e436591fdd9..25bec9f766b 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -53,9 +53,9 @@ 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::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::AtomicRef; @@ -525,9 +525,6 @@ pub struct DiagCtxtFlags { /// 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, @@ -574,7 +571,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 { @@ -673,7 +670,7 @@ impl DiagCtxt { let key = (span.with_parent(None), key); if diag.is_error() { - if matches!(diag.level, Error { lint: true }) { + if diag.level == Error && diag.is_lint { inner.lint_err_count += 1; } else { inner.err_count += 1; @@ -697,7 +694,7 @@ 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.level == Error && diag.is_lint { inner.lint_err_count -= 1; } else { inner.err_count -= 1; @@ -732,7 +729,7 @@ impl DiagCtxt { msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()> { let mut result = self.struct_warn(msg); - result.set_span(span); + result.span(span); result } @@ -789,7 +786,7 @@ impl DiagCtxt { msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_> { let mut result = self.struct_err(msg); - result.set_span(span); + result.span(span); result } @@ -812,7 +809,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) + DiagnosticBuilder::new(self, Error, msg) } /// Construct a builder at the `Error` level with the `msg` and the `code`. @@ -850,7 +847,7 @@ impl DiagCtxt { msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, FatalAbort> { let mut result = self.struct_fatal(msg); - result.set_span(span); + result.span(span); result } @@ -878,16 +875,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<'_, ()> { @@ -917,7 +904,7 @@ impl DiagCtxt { msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, BugAbort> { let mut result = self.struct_bug(msg); - result.set_span(span); + result.span(span); result } @@ -1004,11 +991,10 @@ 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); + diagnostic.span(sp); self.emit_diagnostic(diagnostic).unwrap() } @@ -1016,11 +1002,7 @@ impl DiagCtxt { // 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)); } @@ -1039,7 +1021,7 @@ impl DiagCtxt { msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()> { let mut db = DiagnosticBuilder::new(self, Note, msg); - db.set_span(span); + db.span(span); db } @@ -1222,7 +1204,7 @@ 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] @@ -1318,7 +1300,7 @@ impl DiagCtxt { pub fn update_unstable_expectation_id( &self, - unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, + unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>, ) { let mut inner = self.inner.borrow_mut(); let diags = std::mem::take(&mut inner.unstable_expect_diagnostics); @@ -1377,7 +1359,7 @@ 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.level == Error && diag.is_lint { self.lint_err_count -= 1; } else { self.err_count -= 1; @@ -1408,7 +1390,7 @@ impl DiagCtxtInner { &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 +1412,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() { @@ -1509,7 +1489,7 @@ impl DiagCtxtInner { } } if diagnostic.is_error() { - if matches!(diagnostic.level, Error { lint: true }) { + if diagnostic.level == Error && diagnostic.is_lint { self.bump_lint_err_count(); } else { self.bump_err_count(); @@ -1698,18 +1678,14 @@ 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. /// @@ -1768,7 +1744,7 @@ 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(_) => { @@ -1789,7 +1765,7 @@ impl Level { pub fn to_str(self) -> &'static str { match self { Bug | DelayedBug => "error: internal compiler error", - Fatal | Error { .. } => "error", + Fatal | Error => "error", Warning(_) => "warning", Note | OnceNote => "note", Help | OnceHelp => "help", diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 676f9f17976..5a616e0ffbf 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -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/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e9736d6f2c8..e9797abcbdf 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,7 +213,7 @@ 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.emit(); @@ -221,37 +221,6 @@ fn expand_macro<'cx>( } }; - // 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); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index f2a9875ffd2..c969ca7ef89 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}; @@ -42,6 +42,7 @@ enum Frame<'a> { tts: &'a [mbe::TokenTree], idx: usize, sep: Option<Token>, + kleene_op: KleeneOp, }, } @@ -207,7 +208,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 +228,7 @@ pub(super) fn transcribe<'a>( idx: 0, sep: seq.separator.clone(), tts: &delimited.tts, + kleene_op: seq.kleene.op, }); } } @@ -243,7 +245,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 +310,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/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5eb6aed7253..66695e020f1 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -379,7 +379,7 @@ 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::Error => rustc_errors::Level::Error, Level::Warning => rustc_errors::Level::Warning(None), Level::Note => rustc_errors::Level::Note, Level::Help => rustc_errors::Level::Help, @@ -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)); } 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 763bd4fc391..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. @@ -525,7 +525,7 @@ declare_features! ( /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows using `#[naked]` on functions. - (unstable, naked_functions, "1.9.0", Some(32408)), + (unstable, naked_functions, "1.9.0", Some(90957)), /// Allows specifying the as-needed link modifier (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)), /// Allow negative trait implementations. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b76edd554f8..e88b876534e 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, @@ -2110,12 +2090,6 @@ pub enum YieldSource { Yield, } -impl YieldSource { - pub fn is_await(&self) -> bool { - matches!(self, YieldSource::Await { .. }) - } -} - impl fmt::Display for YieldSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { 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/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 91b3807d744..d403f1a850d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -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); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index f17f19bb77c..5e1c29440a5 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -6,6 +6,7 @@ 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_data_structures::unord::UnordMap; use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -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() @@ -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..3f0ad6584b6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -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") + .primary_message("unresolved item provided when a constant was expected") .emit(); } Res::Def(DefKind::TyParam, src_def_id) => { diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index f3b93c91ae9..6675f517cfa 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) = @@ -98,7 +214,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { 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() { + 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/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index a614d4abf25..8a3df79cb25 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -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, ) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d2e96ac74df..5ccb7ac3896 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 _}; @@ -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; @@ -440,40 +440,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 +473,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 +486,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 +500,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; }; @@ -589,19 +580,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>( @@ -1309,16 +1300,6 @@ pub(super) fn check_type_params_are_used<'tcx>( } } -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`") 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..cc4dc5aca0d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,6 +1,6 @@ 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_hir as hir; @@ -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 = @@ -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)) => { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index faec72cfeb6..f60d6950670 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -75,7 +75,6 @@ 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}; @@ -110,7 +109,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..542e69a6c34 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -177,6 +177,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 +192,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); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 580d4bd5b02..5f26da9c87f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -172,7 +172,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: // @@ -271,7 +271,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> { @@ -1909,7 +1913,11 @@ 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<'_> { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8aeab2ca67e..0a13949a688 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; @@ -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 { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 5abc752309a..b44b2eefabb 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -315,7 +315,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if is_host_effect { if let Some(idx) = host_effect_index { - bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + tcx.dcx().span_delayed_bug( + param.span, + format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), + ); } host_effect_index = Some(index as usize); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 75e7a5524a7..9124d502110 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() diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 81d8982eb15..b9e7500c894 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -200,18 +200,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_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/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 0ca0f7d2daf..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,13 +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(fn_def_id.into()) { + 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) }, ), ); @@ -146,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 @@ -200,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/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 7d753216534..44d9f1ed818 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, @@ -349,7 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Index(base, idx, brackets_span) => { self.check_expr_index(base, idx, expr, brackets_span) } - ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), + ExprKind::Yield(value, _) => self.check_expr_yield(value, expr), hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), } } @@ -3162,22 +3163,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, value: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, - src: &'tcx hir::YieldSource, ) -> 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 } - // Given that this `yield` expression was generated as a result of lowering a `.await`, - // we know that the yield type must be `()`; however, the context won't contain this - // information. Hence, we check the source of the yield expression here and check its - // value's type against `()` (this check should always hold). - None if src.is_await() => { - self.check_expr_coercible_to_type(value, Ty::new_unit(self.tcx), None); - Ty::new_unit(self.tcx) - } _ => { self.dcx().emit_err(YieldExprOutsideOfCoroutine { span: expr.span }); // Avoid expressions without types during writeback (#78653). 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..cb109a2e024 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`. 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 0cca779b156..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, @@ -150,11 +151,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // ascription, or if it's an implicit `self` parameter traits::SizedArgumentType( if ty_span == ident.span - && self.fcx.tcx.is_closure(self.fcx.body_id.into()) + && self.fcx.tcx.is_closure_or_coroutine(self.fcx.body_id.into()) { 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/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index da9a2bde783..6044b1fdd40 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -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)] diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 47fdd64796e..58db2f10bd0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -913,7 +913,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 +961,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); @@ -2252,6 +2252,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 +2323,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 +2339,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 +2388,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 +2410,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..7b49a7cc009 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -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 => { @@ -375,7 +375,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) } }; @@ -852,7 +853,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/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/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index e68195acee0..b459f82f23e 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -55,18 +55,12 @@ where debug!("save: remove old file"); } Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => { - sess.dcx().emit_err(errors::DeleteOld { name, path: path_buf, err }); - return; - } + Err(err) => sess.dcx().emit_fatal(errors::DeleteOld { name, path: path_buf, err }), } let mut encoder = match FileEncoder::new(&path_buf) { Ok(encoder) => encoder, - Err(err) => { - sess.dcx().emit_err(errors::CreateNew { name, path: path_buf, err }); - return; - } + Err(err) => sess.dcx().emit_fatal(errors::CreateNew { name, path: path_buf, err }), }; write_file_header(&mut encoder, sess); @@ -80,9 +74,7 @@ where ); debug!("save: data written to disk successfully"); } - Err((path, err)) => { - sess.dcx().emit_err(errors::WriteNew { name, path, err }); - } + Err((path, err)) => sess.dcx().emit_fatal(errors::WriteNew { name, path, err }), } } 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_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/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 11ab86277c1..c7cab048db1 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -5,7 +5,7 @@ //! Freshening is used primarily to get a good type for inserting into a cache. The result //! summarizes what the type inferencer knows "so far". The primary place it is used right now is //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type -//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in +//! matches some other type X -- *without* affecting `X`. That means that if the type `X` is in //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending //! on what type that type variable is ultimately assigned, the match may or may not succeed. //! @@ -21,7 +21,7 @@ //! Because of the manipulation required to handle closures, doing arbitrary operations on //! freshened types is not recommended. However, in addition to doing equality/hash //! comparisons (for caching), it is possible to do a `ty::_match` operation between -//! 2 freshened types - this works even with the closure encoding. +//! two freshened types - this works even with the closure encoding. //! //! __An important detail concerning regions.__ The freshener also replaces *all* free regions with //! 'erased. The reason behind this is that, in general, we do not take region relationships into diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index d89c205da3f..e91411ffc7a 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_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; @@ -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> { @@ -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/passes.rs b/compiler/rustc_interface/src/passes.rs index 559874641c3..ce76c2cba93 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -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 1ea3db26e21..07bbe78dc2d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -332,7 +332,7 @@ impl Compiler { // the global context. _timer = Some(self.sess.timer("free_global_ctxt")); if let Err((path, error)) = queries.finish() { - self.sess.dcx().emit_err(errors::FailedWritingFile { path: &path, error }); + self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error }); } ret diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c4a1f3a0e51..f3f59b05682 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; @@ -666,7 +666,6 @@ fn test_unstable_options_tracking_hash() { 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); @@ -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_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/context.rs b/compiler/rustc_lint/src/context.rs index 39c965e75d6..d0fd019a8b1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -18,34 +18,32 @@ use self::TargetLint::*; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; -use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder, DiagnosticMessage}; -use rustc_errors::{Applicability, DecorateLint, MultiSpan, SuggestionStyle}; +use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError}; use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt}; -use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::{LintStoreMarker, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::Span; use rustc_target::abi; use std::cell::Cell; use std::iter; use std::slice; +mod diagnostics; + type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync; type LateLintPassFactory = dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; @@ -432,6 +430,8 @@ impl LintStore { // Note: find_best_match_for_name depends on the sort order of its input vector. // To ensure deterministic output, sort elements of the lint_groups hash map. // Also, never suggest deprecated lint groups. + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut groups: Vec<_> = self .lint_groups .iter() @@ -531,447 +531,9 @@ pub trait LintContext { diagnostic: BuiltinLintDiagnostics, ) { // We first generate a blank diagnostic. - self.lookup(lint, span, msg,|db| { + self.lookup(lint, span, msg, |db| { // Now, set up surrounding context. - let sess = self.sess(); - match diagnostic { - BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => { - let spans: Vec<_> = content - .char_indices() - .filter_map(|(i, c)| { - TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { - let lo = span.lo() + BytePos(2 + i as u32); - (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) - }) - }) - .collect(); - let (an, s) = match spans.len() { - 1 => ("an ", ""), - _ => ("", "s"), - }; - db.span_label(span, format!( - "this comment contains {an}invisible unicode text flow control codepoint{s}", - )); - for (c, span) in &spans { - db.span_label(*span, format!("{c:?}")); - } - db.note( - "these kind of unicode codepoints change the way text flows on \ - applications that support them, but can cause confusion because they \ - change the order of characters on the screen", - ); - if !spans.is_empty() { - db.multipart_suggestion_with_style( - "if their presence wasn't intentional, you can remove them", - spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(), - Applicability::MachineApplicable, - SuggestionStyle::HideCodeAlways, - ); - } - }, - BuiltinLintDiagnostics::Normal => (), - BuiltinLintDiagnostics::AbsPathWithModule(span) => { - let (sugg, app) = match sess.source_map().span_to_snippet(span) { - Ok(ref s) => { - // FIXME(Manishearth) ideally the emitting code - // can tell us whether or not this is global - let opt_colon = - if s.trim_start().starts_with("::") { "" } else { "::" }; - - (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) - } - Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders), - }; - db.span_suggestion(span, "use `crate`", sugg, app); - } - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { - db.span_label( - span, - "names from parent modules are not accessible without an explicit import", - ); - } - BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths( - span_def, - ) => { - db.span_note(span_def, "the macro is defined here"); - } - BuiltinLintDiagnostics::ElidedLifetimesInPaths( - n, - path_span, - incl_angl_brckt, - insertion_span, - ) => { - add_elided_lifetime_in_path_suggestion( - sess.source_map(), - db, - n, - path_span, - incl_angl_brckt, - insertion_span, - ); - } - BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { - db.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect); - } - BuiltinLintDiagnostics::UnusedImports(message, replaces, in_test_module) => { - if !replaces.is_empty() { - db.tool_only_multipart_suggestion( - message, - replaces, - Applicability::MachineApplicable, - ); - } - - if let Some(span) = in_test_module { - db.span_help( - self.sess().source_map().guess_head_span(span), - "consider adding a `#[cfg(test)]` to the containing module", - ); - } - } - BuiltinLintDiagnostics::RedundantImport(spans, ident) => { - for (span, is_imported) in spans { - let introduced = if is_imported { "imported" } else { "defined" }; - db.span_label( - span, - format!("the item `{ident}` is already {introduced} here"), - ); - } - } - BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { - stability::deprecation_suggestion(db, "macro", suggestion, span) - } - BuiltinLintDiagnostics::UnusedDocComment(span) => { - db.span_label(span, "rustdoc does not generate documentation for macro invocations"); - db.help("to document an item produced by a macro, \ - the macro must produce the documentation as part of its expansion"); - } - BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => { - db.span_suggestion(span, "remove `mut` from the parameter", ident, Applicability::MachineApplicable); - } - BuiltinLintDiagnostics::MissingAbi(span, default_abi) => { - db.span_label(span, "ABI should be specified here"); - db.help(format!("the default ABI is {}", default_abi.name())); - } - BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => { - db.span_label(span, "the attribute is introduced here"); - } - BuiltinLintDiagnostics::ProcMacroBackCompat(note) => { - db.note(note); - } - BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => { - db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable); - } - BuiltinLintDiagnostics::ReservedPrefix(span) => { - db.span_label(span, "unknown prefix"); - db.span_suggestion_verbose( - span.shrink_to_hi(), - "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", - " ", - Applicability::MachineApplicable, - ); - } - BuiltinLintDiagnostics::UnusedBuiltinAttribute { - attr_name, - macro_name, - invoc_span - } => { - db.span_note( - invoc_span, - format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`") - ); - } - BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => { - if is_trailing { - db.note("macro invocations at the end of a block are treated as expressions"); - db.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`")); - } - } - BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => { - db.multipart_suggestion( - "wrap this expression in parentheses", - vec![(span.shrink_to_lo(), "(".to_string()), - (span.shrink_to_hi(), ")".to_string())], - Applicability::MachineApplicable - ); - } - BuiltinLintDiagnostics::NamedAsmLabel(help) => { - db.help(help); - db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); - }, - BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => { - let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().copied().collect(); - let is_from_cargo = std::env::var_os("CARGO").is_some(); - let mut is_feature_cfg = name == sym::feature; - - if is_feature_cfg && is_from_cargo { - db.help("consider defining some features in `Cargo.toml`"); - // Suggest the most probable if we found one - } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { - if let Some(ExpectedValues::Some(best_match_values)) = - sess.parse_sess.check_config.expecteds.get(&best_match) { - let mut possibilities = best_match_values.iter() - .flatten() - .map(Symbol::as_str) - .collect::<Vec<_>>(); - possibilities.sort(); - - let mut should_print_possibilities = true; - if let Some((value, value_span)) = value { - if best_match_values.contains(&Some(value)) { - db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect); - should_print_possibilities = false; - } else if best_match_values.contains(&None) { - db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect); - should_print_possibilities = false; - } else if let Some(first_value) = possibilities.first() { - db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect); - } else { - db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect); - }; - } else { - db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); - } - - if !possibilities.is_empty() && should_print_possibilities { - let possibilities = possibilities.join("`, `"); - db.help(format!("expected values for `{best_match}` are: `{possibilities}`")); - } - } else { - db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); - } - - is_feature_cfg |= best_match == sym::feature; - } else if !possibilities.is_empty() { - let mut possibilities = possibilities.iter() - .map(Symbol::as_str) - .collect::<Vec<_>>(); - possibilities.sort(); - let possibilities = possibilities.join("`, `"); - - // The list of expected names can be long (even by default) and - // so the diagnostic produced can take a lot of space. To avoid - // cloging the user output we only want to print that diagnostic - // once. - db.help_once(format!("expected names are: `{possibilities}`")); - } - - let inst = if let Some((value, _value_span)) = value { - let pre = if is_from_cargo { "\\" } else { "" }; - format!("cfg({name}, values({pre}\"{value}{pre}\"))") - } else { - format!("cfg({name})") - }; - - if is_from_cargo { - if !is_feature_cfg { - db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); - } - db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); - } else { - db.help(format!("to expect this configuration use `--check-cfg={inst}`")); - db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); - } - }, - BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { - let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else { - bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values"); - }; - let mut have_none_possibility = false; - let possibilities: Vec<Symbol> = values.iter() - .inspect(|a| have_none_possibility |= a.is_none()) - .copied() - .flatten() - .collect(); - let is_from_cargo = std::env::var_os("CARGO").is_some(); - - // Show the full list if all possible values for a given name, but don't do it - // for names as the possibilities could be very long - if !possibilities.is_empty() { - { - let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>(); - possibilities.sort(); - - let possibilities = possibilities.join("`, `"); - let none = if have_none_possibility { "(none), " } else { "" }; - - db.note(format!("expected values for `{name}` are: {none}`{possibilities}`")); - } - - if let Some((value, value_span)) = value { - // Suggest the most probable if we found one - if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) { - db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect); - - } - } else if name == sym::feature && is_from_cargo { - db.help(format!("consider defining `{name}` as feature in `Cargo.toml`")); - } else if let &[first_possibility] = &possibilities[..] { - db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect); - } - } else if have_none_possibility { - db.note(format!("no expected value for `{name}`")); - if let Some((_value, value_span)) = value { - db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect); - } - } - - let inst = if let Some((value, _value_span)) = value { - let pre = if is_from_cargo { "\\" } else { "" }; - format!("cfg({name}, values({pre}\"{value}{pre}\"))") - } else { - format!("cfg({name})") - }; - - if is_from_cargo { - if name == sym::feature { - if let Some((value, _value_span)) = value { - db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); - } - } else { - db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); - } - db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); - } else { - db.help(format!("to expect this configuration use `--check-cfg={inst}`")); - db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); - } - }, - BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { - db.multipart_suggestion( - "move it to the end of the type declaration", - vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)], - Applicability::MachineApplicable, - ); - db.note( - "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", - ); - }, - BuiltinLintDiagnostics::SingleUseLifetime { - param_span, - use_span: Some((use_span, elide)), - deletion_span, - } => { - debug!(?param_span, ?use_span, ?deletion_span); - db.span_label(param_span, "this lifetime..."); - db.span_label(use_span, "...is used only here"); - if let Some(deletion_span) = deletion_span { - let msg = "elide the single-use lifetime"; - let (use_span, replace_lt) = if elide { - let use_span = sess.source_map().span_extend_while( - use_span, - char::is_whitespace, - ).unwrap_or(use_span); - (use_span, String::new()) - } else { - (use_span, "'_".to_owned()) - }; - debug!(?deletion_span, ?use_span); - - // issue 107998 for the case such as a wrong function pointer type - // `deletion_span` is empty and there is no need to report lifetime uses here - let suggestions = if deletion_span.is_empty() { - vec![(use_span, replace_lt)] - } else { - vec![(deletion_span, String::new()), (use_span, replace_lt)] - }; - db.multipart_suggestion( - msg, - suggestions, - Applicability::MachineApplicable, - ); - } - }, - BuiltinLintDiagnostics::SingleUseLifetime { - param_span: _, - use_span: None, - deletion_span, - } => { - debug!(?deletion_span); - if let Some(deletion_span) = deletion_span { - db.span_suggestion( - deletion_span, - "elide the unused lifetime", - "", - Applicability::MachineApplicable, - ); - } - }, - BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => { - db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string"); - if let Some(positional_arg_for_msg) = position_sp_for_msg { - let msg = format!("this formatting argument uses named argument `{named_arg_name}` by position"); - db.span_label(positional_arg_for_msg, msg); - } - - if let Some(positional_arg_to_replace) = position_sp_to_replace { - let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name }; - let span_to_replace = if let Ok(positional_arg_content) = - self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(':') { - positional_arg_to_replace.shrink_to_lo() - } else { - positional_arg_to_replace - }; - db.span_suggestion_verbose( - span_to_replace, - "use the named argument by name to avoid ambiguity", - name, - Applicability::MaybeIncorrect, - ); - } - } - BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { - db.help("consider implementing the trait by hand, or remove the `packed` attribute"); - } - BuiltinLintDiagnostics::UnusedExternCrate { removal_span }=> { - db.span_suggestion( - removal_span, - "remove it", - "", - Applicability::MachineApplicable, - ); - } - BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span }=> { - let suggestion_span = vis_span.between(ident_span); - db.span_suggestion_verbose( - suggestion_span, - "convert it to a `use`", - if vis_span.is_empty() { "use " } else { " use " }, - Applicability::MachineApplicable, - ); - } - BuiltinLintDiagnostics::AmbiguousGlobImports { diag } => { - rustc_errors::report_ambiguity_error(db, diag); - } - BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => { - db.span_label(first_reexport_span, format!("the name `{name}` in the {namespace} namespace is first re-exported here")); - db.span_label(duplicate_reexport_span, format!("but the name `{name}` in the {namespace} namespace is also re-exported here")); - } - BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => { - db.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here")); - db.span_note(private_item_span, "but the private item here shadows it".to_owned()); - } - BuiltinLintDiagnostics::UnusedQualifications { removal_span } => { - db.span_suggestion_verbose( - removal_span, - "remove the unnecessary path segments", - "", - Applicability::MachineApplicable - ); - } - BuiltinLintDiagnostics::AssociatedConstElidedLifetime { elided, span } => { - db.span_suggestion_verbose( - if elided { span.shrink_to_hi() } else { span }, - "use the `'static` lifetime", - if elided { "'static " } else { "'static" }, - Applicability::MachineApplicable - ); - }, - BuiltinLintDiagnostics::RedundantImportVisibility { max_vis, span } => { - db.span_note(span, format!("the most public imported item is `{max_vis}`")); - db.help("reduce the glob import's visibility or increase visibility of imported items"); - } - } + diagnostics::builtin(self.sess(), diagnostic, db); // Rewrap `db`, and pass control to the user. decorate(db) }); diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs new file mode 100644 index 00000000000..75756c6946a --- /dev/null +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -0,0 +1,537 @@ +use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; +use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder}; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_middle::middle::stability; +use rustc_session::config::ExpectedValues; +use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::Session; +use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::BytePos; + +pub(super) fn builtin( + sess: &Session, + diagnostic: BuiltinLintDiagnostics, + db: &mut DiagnosticBuilder<'_, ()>, +) { + match diagnostic { + BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => { + let spans: Vec<_> = content + .char_indices() + .filter_map(|(i, c)| { + TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { + let lo = span.lo() + BytePos(2 + i as u32); + (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + }) + }) + .collect(); + let (an, s) = match spans.len() { + 1 => ("an ", ""), + _ => ("", "s"), + }; + db.span_label( + span, + format!( + "this comment contains {an}invisible unicode text flow control codepoint{s}", + ), + ); + for (c, span) in &spans { + db.span_label(*span, format!("{c:?}")); + } + db.note( + "these kind of unicode codepoints change the way text flows on \ + applications that support them, but can cause confusion because they \ + change the order of characters on the screen", + ); + if !spans.is_empty() { + db.multipart_suggestion_with_style( + "if their presence wasn't intentional, you can remove them", + spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(), + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); + } + } + BuiltinLintDiagnostics::Normal => (), + BuiltinLintDiagnostics::AbsPathWithModule(span) => { + let (sugg, app) = match sess.source_map().span_to_snippet(span) { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; + + (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) + } + Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders), + }; + db.span_suggestion(span, "use `crate`", sugg, app); + } + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { + db.span_label( + span, + "names from parent modules are not accessible without an explicit import", + ); + } + BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { + db.span_note(span_def, "the macro is defined here"); + } + BuiltinLintDiagnostics::ElidedLifetimesInPaths( + n, + path_span, + incl_angl_brckt, + insertion_span, + ) => { + add_elided_lifetime_in_path_suggestion( + sess.source_map(), + db, + n, + path_span, + incl_angl_brckt, + insertion_span, + ); + } + BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { + db.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect); + } + BuiltinLintDiagnostics::UnusedImports(message, replaces, in_test_module) => { + if !replaces.is_empty() { + db.tool_only_multipart_suggestion( + message, + replaces, + Applicability::MachineApplicable, + ); + } + + if let Some(span) = in_test_module { + db.span_help( + sess.source_map().guess_head_span(span), + "consider adding a `#[cfg(test)]` to the containing module", + ); + } + } + BuiltinLintDiagnostics::RedundantImport(spans, ident) => { + for (span, is_imported) in spans { + let introduced = if is_imported { "imported" } else { "defined" }; + db.span_label(span, format!("the item `{ident}` is already {introduced} here")); + } + } + BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { + stability::deprecation_suggestion(db, "macro", suggestion, span) + } + BuiltinLintDiagnostics::UnusedDocComment(span) => { + db.span_label(span, "rustdoc does not generate documentation for macro invocations"); + db.help("to document an item produced by a macro, \ + the macro must produce the documentation as part of its expansion"); + } + BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => { + db.span_suggestion( + span, + "remove `mut` from the parameter", + ident, + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::MissingAbi(span, default_abi) => { + db.span_label(span, "ABI should be specified here"); + db.help(format!("the default ABI is {}", default_abi.name())); + } + BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => { + db.span_label(span, "the attribute is introduced here"); + } + BuiltinLintDiagnostics::ProcMacroBackCompat(note) => { + db.note(note); + } + BuiltinLintDiagnostics::OrPatternsBackCompat(span, suggestion) => { + db.span_suggestion( + span, + "use pat_param to preserve semantics", + suggestion, + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::ReservedPrefix(span) => { + db.span_label(span, "unknown prefix"); + db.span_suggestion_verbose( + span.shrink_to_hi(), + "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", + " ", + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { + db.span_note( + invoc_span, + format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`") + ); + } + BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => { + if is_trailing { + db.note("macro invocations at the end of a block are treated as expressions"); + db.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`")); + } + } + BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => { + db.multipart_suggestion( + "wrap this expression in parentheses", + vec![ + (span.shrink_to_lo(), "(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::NamedAsmLabel(help) => { + db.help(help); + db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); + } + BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => { + let possibilities: Vec<Symbol> = + sess.parse_sess.check_config.expecteds.keys().copied().collect(); + let is_from_cargo = std::env::var_os("CARGO").is_some(); + let mut is_feature_cfg = name == sym::feature; + + if is_feature_cfg && is_from_cargo { + db.help("consider defining some features in `Cargo.toml`"); + // Suggest the most probable if we found one + } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { + if let Some(ExpectedValues::Some(best_match_values)) = + sess.parse_sess.check_config.expecteds.get(&best_match) + { + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] + let mut possibilities = + best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>(); + possibilities.sort(); + + let mut should_print_possibilities = true; + if let Some((value, value_span)) = value { + if best_match_values.contains(&Some(value)) { + db.span_suggestion( + name_span, + "there is a config with a similar name and value", + best_match, + Applicability::MaybeIncorrect, + ); + should_print_possibilities = false; + } else if best_match_values.contains(&None) { + db.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and no value", + best_match, + Applicability::MaybeIncorrect, + ); + should_print_possibilities = false; + } else if let Some(first_value) = possibilities.first() { + db.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and different values", + format!("{best_match} = \"{first_value}\""), + Applicability::MaybeIncorrect, + ); + } else { + db.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and different values", + best_match, + Applicability::MaybeIncorrect, + ); + }; + } else { + db.span_suggestion( + name_span, + "there is a config with a similar name", + best_match, + Applicability::MaybeIncorrect, + ); + } + + if !possibilities.is_empty() && should_print_possibilities { + let possibilities = possibilities.join("`, `"); + db.help(format!( + "expected values for `{best_match}` are: `{possibilities}`" + )); + } + } else { + db.span_suggestion( + name_span, + "there is a config with a similar name", + best_match, + Applicability::MaybeIncorrect, + ); + } + + is_feature_cfg |= best_match == sym::feature; + } else if !possibilities.is_empty() { + let mut possibilities = + possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); + + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); + } + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if !is_feature_cfg { + db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); + } else { + db.help(format!("to expect this configuration use `--check-cfg={inst}`")); + db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); + } + } + BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { + let Some(ExpectedValues::Some(values)) = + &sess.parse_sess.check_config.expecteds.get(&name) + else { + bug!( + "it shouldn't be possible to have a diagnostic on a value whose name is not in values" + ); + }; + let mut have_none_possibility = false; + // We later sort possibilities if it is not empty, so the + // order here does not matter. + #[allow(rustc::potential_query_instability)] + let possibilities: Vec<Symbol> = values + .iter() + .inspect(|a| have_none_possibility |= a.is_none()) + .copied() + .flatten() + .collect(); + let is_from_cargo = std::env::var_os("CARGO").is_some(); + + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long + if !possibilities.is_empty() { + { + let mut possibilities = + possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>(); + possibilities.sort(); + + let possibilities = possibilities.join("`, `"); + let none = if have_none_possibility { "(none), " } else { "" }; + + db.note(format!("expected values for `{name}` are: {none}`{possibilities}`")); + } + + if let Some((value, value_span)) = value { + // Suggest the most probable if we found one + if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) + { + db.span_suggestion( + value_span, + "there is a expected value with a similar name", + format!("\"{best_match}\""), + Applicability::MaybeIncorrect, + ); + } + } else if let &[first_possibility] = &possibilities[..] { + db.span_suggestion( + name_span.shrink_to_hi(), + "specify a config value", + format!(" = \"{first_possibility}\""), + Applicability::MaybeIncorrect, + ); + } + } else if have_none_possibility { + db.note(format!("no expected value for `{name}`")); + if let Some((_value, value_span)) = value { + db.span_suggestion( + name_span.shrink_to_hi().to(value_span), + "remove the value", + "", + Applicability::MaybeIncorrect, + ); + } + } + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if name == sym::feature { + if let Some((value, _value_span)) = value { + db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); + } + } else { + db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); + } else { + db.help(format!("to expect this configuration use `--check-cfg={inst}`")); + db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); + } + } + BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { + db.multipart_suggestion( + "move it to the end of the type declaration", + vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)], + Applicability::MachineApplicable, + ); + db.note( + "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", + ); + } + BuiltinLintDiagnostics::SingleUseLifetime { + param_span, + use_span: Some((use_span, elide)), + deletion_span, + } => { + debug!(?param_span, ?use_span, ?deletion_span); + db.span_label(param_span, "this lifetime..."); + db.span_label(use_span, "...is used only here"); + if let Some(deletion_span) = deletion_span { + let msg = "elide the single-use lifetime"; + let (use_span, replace_lt) = if elide { + let use_span = sess + .source_map() + .span_extend_while(use_span, char::is_whitespace) + .unwrap_or(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let suggestions = if deletion_span.is_empty() { + vec![(use_span, replace_lt)] + } else { + vec![(deletion_span, String::new()), (use_span, replace_lt)] + }; + db.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable); + } + } + BuiltinLintDiagnostics::SingleUseLifetime { + param_span: _, + use_span: None, + deletion_span, + } => { + debug!(?deletion_span); + if let Some(deletion_span) = deletion_span { + db.span_suggestion( + deletion_span, + "elide the unused lifetime", + "", + Applicability::MachineApplicable, + ); + } + } + BuiltinLintDiagnostics::NamedArgumentUsedPositionally { + position_sp_to_replace, + position_sp_for_msg, + named_arg_sp, + named_arg_name, + is_formatting_arg, + } => { + db.span_label( + named_arg_sp, + "this named argument is referred to by position in formatting string", + ); + if let Some(positional_arg_for_msg) = position_sp_for_msg { + let msg = format!( + "this formatting argument uses named argument `{named_arg_name}` by position" + ); + db.span_label(positional_arg_for_msg, msg); + } + + if let Some(positional_arg_to_replace) = position_sp_to_replace { + let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name }; + let span_to_replace = if let Ok(positional_arg_content) = + sess.source_map().span_to_snippet(positional_arg_to_replace) + && positional_arg_content.starts_with(':') + { + positional_arg_to_replace.shrink_to_lo() + } else { + positional_arg_to_replace + }; + db.span_suggestion_verbose( + span_to_replace, + "use the named argument by name to avoid ambiguity", + name, + Applicability::MaybeIncorrect, + ); + } + } + BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { + db.help("consider implementing the trait by hand, or remove the `packed` attribute"); + } + BuiltinLintDiagnostics::UnusedExternCrate { removal_span } => { + db.span_suggestion(removal_span, "remove it", "", Applicability::MachineApplicable); + } + BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span } => { + let suggestion_span = vis_span.between(ident_span); + db.span_suggestion_verbose( + suggestion_span, + "convert it to a `use`", + if vis_span.is_empty() { "use " } else { " use " }, + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::AmbiguousGlobImports { diag } => { + rustc_errors::report_ambiguity_error(db, diag); + } + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name, + namespace, + first_reexport_span, + duplicate_reexport_span, + } => { + db.span_label( + first_reexport_span, + format!("the name `{name}` in the {namespace} namespace is first re-exported here"), + ); + db.span_label( + duplicate_reexport_span, + format!( + "but the name `{name}` in the {namespace} namespace is also re-exported here" + ), + ); + } + BuiltinLintDiagnostics::HiddenGlobReexports { + name, + namespace, + glob_reexport_span, + private_item_span, + } => { + db.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here")); + db.span_note(private_item_span, "but the private item here shadows it".to_owned()); + } + BuiltinLintDiagnostics::UnusedQualifications { removal_span } => { + db.span_suggestion_verbose( + removal_span, + "remove the unnecessary path segments", + "", + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::AssociatedConstElidedLifetime { elided, span } => { + db.span_suggestion_verbose( + if elided { span.shrink_to_hi() } else { span }, + "use the `'static` lifetime", + if elided { "'static " } else { "'static" }, + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::RedundantImportVisibility { max_vis, span } => { + db.span_note(span, format!("the most public imported item is `{max_vis}`")); + db.help("reduce the glob import's visibility or increase visibility of imported items"); + } + } +} 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/levels.rs b/compiler/rustc_lint/src/levels.rs index c229728cb79..49821437b76 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -15,7 +15,7 @@ use crate::{ }; use rustc_ast as ast; use rustc_ast_pretty::pprust; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_feature::{Features, GateIssue}; use rustc_hir as hir; @@ -73,7 +73,7 @@ rustc_index::newtype_index! { struct LintSet { // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which // flag. - specs: FxHashMap<LintId, LevelAndSource>, + specs: FxIndexMap<LintId, LevelAndSource>, parent: LintStackIndex, } @@ -86,7 +86,7 @@ impl LintLevelSets { &self, lint: &'static Lint, idx: LintStackIndex, - aux: Option<&FxHashMap<LintId, LevelAndSource>>, + aux: Option<&FxIndexMap<LintId, LevelAndSource>>, sess: &Session, ) -> LevelAndSource { let lint = LintId::of(lint); @@ -101,7 +101,7 @@ impl LintLevelSets { &self, id: LintId, mut idx: LintStackIndex, - aux: Option<&FxHashMap<LintId, LevelAndSource>>, + aux: Option<&FxIndexMap<LintId, LevelAndSource>>, ) -> (Option<Level>, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { @@ -132,8 +132,8 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp cur: hir::CRATE_HIR_ID, specs: ShallowLintLevelMap::default(), expectations: Vec::new(), - unstable_to_stable_ids: FxHashMap::default(), - empty: FxHashMap::default(), + unstable_to_stable_ids: FxIndexMap::default(), + empty: FxIndexMap::default(), }, lint_added_lints: false, store, @@ -161,7 +161,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe tcx, cur: owner.into(), specs: ShallowLintLevelMap::default(), - empty: FxHashMap::default(), + empty: FxIndexMap::default(), attrs, }, lint_added_lints: false, @@ -209,14 +209,14 @@ pub struct TopDown { } pub trait LintLevelsProvider { - fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource>; + fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource>; fn insert(&mut self, id: LintId, lvl: LevelAndSource); fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource; fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {} } impl LintLevelsProvider for TopDown { - fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> { &self.sets.list[self.cur].specs } @@ -234,12 +234,12 @@ struct LintLevelQueryMap<'tcx> { cur: HirId, specs: ShallowLintLevelMap, /// Empty hash map to simplify code. - empty: FxHashMap<LintId, LevelAndSource>, + empty: FxIndexMap<LintId, LevelAndSource>, attrs: &'tcx hir::AttributeMap<'tcx>, } impl LintLevelsProvider for LintLevelQueryMap<'_> { - fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> { self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) } fn insert(&mut self, id: LintId, lvl: LevelAndSource) { @@ -257,13 +257,13 @@ struct QueryMapExpectationsWrapper<'tcx> { /// Level map for `cur`. specs: ShallowLintLevelMap, expectations: Vec<(LintExpectationId, LintExpectation)>, - unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>, + unstable_to_stable_ids: FxIndexMap<LintExpectationId, LintExpectationId>, /// Empty hash map to simplify code. - empty: FxHashMap<LintId, LevelAndSource>, + empty: FxIndexMap<LintId, LevelAndSource>, } impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { - fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> { self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) } fn insert(&mut self, id: LintId, lvl: LevelAndSource) { @@ -486,7 +486,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { .provider .sets .list - .push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE }); + .push(LintSet { specs: FxIndexMap::default(), parent: COMMAND_LINE }); self.add_command_line(); } @@ -512,7 +512,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { ) -> BuilderPush { let prev = self.provider.cur; self.provider.cur = - self.provider.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); + self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev }); self.add(attrs, is_crate_node, source_hir_id); @@ -547,7 +547,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.features } - fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> { + fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> { self.provider.current_specs() } @@ -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 0fc24e88b3b..76c630fc456 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,7 +25,6 @@ //! //! This API is completely unstable and subject to change. -#![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] @@ -329,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 diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ca6408bdf3d..614c3ecbcae 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() @@ -953,12 +935,9 @@ pub struct NonBindingLetSub { } 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, { diag.span_suggestion_verbose( self.suggestion, @@ -1147,8 +1126,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 +1145,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 +1203,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 +1318,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 +1335,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 +1399,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 +1606,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 +1619,7 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_improper_ctypes } } @@ -1776,10 +1749,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 +1762,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { } } - fn msg(&self) -> rustc_errors::DiagnosticMessage { + fn msg(&self) -> DiagnosticMessage { fluent::lint_unused_def } } @@ -1859,14 +1832,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 4f92fcd71c6..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! { @@ -174,6 +175,8 @@ impl EarlyLintPass for NonAsciiIdents { // Sort by `Span` so that error messages make sense with respect to the // order of identifier locations in the code. + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut symbols: Vec<_> = symbols.iter().collect(); symbols.sort_by_key(|k| k.1); @@ -192,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() { @@ -246,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); @@ -287,6 +290,8 @@ impl EarlyLintPass for NonAsciiIdents { } if has_suspicious { + // The end result is put in `lint_reports` which is sorted. + #[allow(rustc::potential_query_instability)] let verified_augmented_script_sets = script_states .iter() .flat_map(|(k, v)| match v { @@ -299,6 +304,8 @@ impl EarlyLintPass for NonAsciiIdents { let mut lint_reports: BTreeMap<(Span, Vec<char>), AugmentedScriptSet> = BTreeMap::new(); + // The end result is put in `lint_reports` which is sorted. + #[allow(rustc::potential_query_instability)] 'outerloop: for (augment_script_set, usage) in script_states { let ScriptSetUsage::Suspicious(mut ch_list, sp) = usage else { continue }; diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 9fcd70ba0b5..f0bbc03d747 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -121,7 +121,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc #[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 +180,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 +191,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_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 399e6968fae..19da51b7dcf 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -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 @@ -2817,8 +2795,8 @@ declare_lint! { /// [`ptr::from_exposed_addr`]. /// /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 - /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr - /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr + /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr + /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html pub FUZZY_PROVENANCE_CASTS, Allow, "a fuzzy integer to pointer cast is used", @@ -2863,8 +2841,8 @@ declare_lint! { /// about the semantics. /// /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 - /// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr - /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr + /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr + /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_addr pub LOSSY_PROVENANCE_CASTS, Allow, "a lossy pointer to integer cast is used", 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_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_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index a4012592c09..08cc8173eb0 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" libloading = "0.7.1" odht = { version = "0.3.1", features = ["nightly"] } rustc_ast = { path = "../rustc_ast" } 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..d13a1664ade 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}; @@ -31,7 +31,6 @@ use rustc_span::{BytePos, Pos, SpanData, 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. @@ -1818,11 +1817,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 +1838,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 +1859,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 aca7a66596e..1d12b853b53 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; @@ -1914,14 +1912,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 +2032,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)| { @@ -2255,12 +2250,12 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { // If we forget this, compilation can succeed with an incomplete rmeta file, // causing an ICE when the rmeta file is read by another compilation. if let Err((path, err)) = ecx.opaque.finish() { - tcx.dcx().emit_err(FailWriteFile { path: &path, err }); + tcx.dcx().emit_fatal(FailWriteFile { path: &path, err }); } let file = ecx.opaque.file(); if let Err(err) = encode_root_position(file, root.position.get()) { - tcx.dcx().emit_err(FailWriteFile { path: ecx.opaque.path(), err }); + tcx.dcx().emit_fatal(FailWriteFile { path: ecx.opaque.path(), err }); } // Record metadata size for self-profiling 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/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d356984c1e9..8e6ca645f80 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" derive_more = "0.99.17" either = "1.5.0" field-offset = "0.3.5" 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 d34d9160d55..d45ec8e4646 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,6 +1,6 @@ use std::cmp; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; @@ -61,7 +61,7 @@ pub type LevelAndSource = (Level, LintLevelSource); /// by the attributes for *a single HirId*. #[derive(Default, Debug, HashStable)] pub struct ShallowLintLevelMap { - pub specs: SortedMap<ItemLocalId, FxHashMap<LintId, LevelAndSource>>, + pub specs: SortedMap<ItemLocalId, FxIndexMap<LintId, LevelAndSource>>, } /// From an initial level and source, verify the effect of special annotations: @@ -314,14 +314,14 @@ pub fn struct_lint_level( } 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::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,7 +348,7 @@ 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); // 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. diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index f758c1d5e6f..e11c9371118 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -45,9 +45,10 @@ pub struct CodegenFnAttrs { pub alignment: Option<u32>, } +#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +pub struct CodegenFnAttrFlags(u32); bitflags! { - #[derive(TyEncodable, TyDecodable, HashStable)] - pub struct CodegenFnAttrFlags: u32 { + impl CodegenFnAttrFlags: u32 { /// `#[cold]`: a hint to LLVM that this function, when called, is never on /// the hot path. const COLD = 1 << 0; @@ -104,6 +105,7 @@ bitflags! { const NO_BUILTINS = 1 << 20; } } +rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } impl CodegenFnAttrs { pub const EMPTY: &'static Self = &Self::new(); 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/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 105ac66e4a8..45dbfe6b8a7 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>>, @@ -385,6 +387,7 @@ impl<'tcx> Body<'tcx> { coroutine: coroutine_kind.map(|coroutine_kind| { Box::new(CoroutineInfo { yield_ty: None, + resume_ty: None, coroutine_drop: None, coroutine_layout: None, coroutine_kind, @@ -552,6 +555,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 +728,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 +950,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. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8e7aaee065f..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 @@ -520,7 +509,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: let kind = tcx.def_kind(def_id); let is_function = match kind { DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), + _ => tcx.is_closure_or_coroutine(def_id), }; match (kind, body.source.promoted) { (_, Some(i)) => write!(w, "{i:?} in ")?, 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/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/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3a54f5f6b3d..7d5abaceb20 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) } } @@ -1542,7 +1537,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 +1550,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 +1662,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 +1678,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 +1734,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 +1786,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 +2077,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..8abf4a9e341 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}; @@ -764,7 +764,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 { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b6759d35210..2b5983314ee 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -519,20 +519,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/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index b95ae5881e2..685c3e87dac 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -24,9 +24,10 @@ use std::str; use super::{Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, VariantDiscr}; +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] +pub struct AdtFlags(u16); bitflags! { - #[derive(HashStable, TyEncodable, TyDecodable)] - pub struct AdtFlags: u16 { + impl AdtFlags: u16 { const NO_ADT_FLAGS = 0; /// Indicates whether the ADT is an enum. const IS_ENUM = 1 << 0; @@ -51,6 +52,7 @@ bitflags! { const IS_UNSAFE_CELL = 1 << 9; } } +rustc_data_structures::external_bitflags_debug! { AdtFlags } /// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`. /// diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8c29bc5a428..8ff5b135aca 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -197,7 +197,7 @@ pub struct ClosureTypeInfo<'tcx> { } fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> { - debug_assert!(tcx.is_closure(def.to_def_id())); + debug_assert!(tcx.is_closure_or_coroutine(def.to_def_id())); let typeck_results = tcx.typeck(def); let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); @@ -217,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { - if !self.is_closure(def_id.to_def_id()) { + if !self.is_closure_or_coroutine(def_id.to_def_id()) { return &[]; }; self.closure_typeinfo(def_id).captures diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1b6d59ab257..2ac3cddfa15 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -426,7 +426,10 @@ impl<'tcx> Instance<'tcx> { ) -> Option<Instance<'tcx>> { debug!("resolve(def_id={:?}, args={:?})", def_id, args); // Use either `resolve_closure` or `resolve_for_vtable` - assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); + assert!( + !tcx.is_closure_or_coroutine(def_id), + "Called `resolve_for_fn_ptr` on closure: {def_id:?}" + ); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -488,7 +491,7 @@ impl<'tcx> Instance<'tcx> { }) ) { - if tcx.is_closure(def) { + if tcx.is_closure_or_coroutine(def) { debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", def, def_id, args); @@ -658,12 +661,10 @@ fn polymorphize<'tcx>( // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). let def_id = instance.def_id(); - let upvars_ty = if tcx.is_closure(def_id) { - Some(args.as_closure().tupled_upvars_ty()) - } else if tcx.type_of(def_id).skip_binder().is_coroutine() { - Some(args.as_coroutine().tupled_upvars_ty()) - } else { - None + let upvars_ty = match tcx.type_of(def_id).skip_binder().kind() { + ty::Closure(..) => Some(args.as_closure().tupled_upvars_ty()), + ty::Coroutine(..) => Some(args.as_coroutine().tupled_upvars_ty()), + _ => None, }; let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty()); debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0653796ec7f..4af82f12471 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}; @@ -333,7 +334,8 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NotConst => f.write_str("normal"), - _ => write!(f, "`{self}`"), + Self::Const => f.write_str("const"), + Self::ConstIfConst => f.write_str("~const"), } } } @@ -654,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> { @@ -1771,9 +1773,10 @@ pub struct Destructor { pub constness: hir::Constness, } +#[derive(Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub struct VariantFlags(u8); bitflags! { - #[derive(HashStable, TyEncodable, TyDecodable)] - pub struct VariantFlags: u8 { + impl VariantFlags: u8 { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; @@ -1782,6 +1785,7 @@ bitflags! { const IS_RECOVERED = 1 << 1; } } +rustc_data_structures::external_bitflags_debug! { VariantFlags } /// Definition of a variant -- a struct's fields or an enum variant. #[derive(Debug, HashStable, TyEncodable, TyDecodable)] @@ -2655,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/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 99384e34222..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( @@ -1697,6 +1727,25 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }) } + fn pretty_print_bound_constness( + &mut self, + trait_ref: ty::TraitRef<'tcx>, + ) -> Result<(), PrintError> { + define_scoped_cx!(self); + + let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else { + return Ok(()); + }; + let arg = trait_ref.args.const_at(idx); + + if arg == self.tcx().consts.false_ { + p!("const "); + } else if arg != self.tcx().consts.true_ && !arg.has_infer() { + p!("~const "); + } + Ok(()) + } + fn should_print_verbose(&self) -> bool { self.tcx().sess.verbose_internals() } @@ -2866,13 +2915,7 @@ define_print_and_forward_display! { } TraitPredPrintModifiersAndPath<'tcx> { - if let Some(idx) = cx.tcx().generics_of(self.0.trait_ref.def_id).host_effect_index - { - let arg = self.0.trait_ref.args.const_at(idx); - if arg != cx.tcx().consts.true_ && !arg.has_infer() { - p!("~const "); - } - } + p!(pretty_print_bound_constness(self.0.trait_ref)); if let ty::ImplPolarity::Negative = self.0.polarity { p!("!") } @@ -2905,11 +2948,7 @@ define_print_and_forward_display! { ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); - if let Some(idx) = cx.tcx().generics_of(self.trait_ref.def_id).host_effect_index { - if self.trait_ref.args.const_at(idx) != cx.tcx().consts.true_ { - p!("~const "); - } - } + p!(pretty_print_bound_constness(self.trait_ref)); if let ty::ImplPolarity::Negative = self.polarity { p!("!"); } @@ -3040,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/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 5e24b47fbd2..3a6fbaec9fd 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -547,7 +547,7 @@ impl<'tcx> TyCtxt<'tcx> { /// closure appears (and, sadly, a corresponding `NodeId`, since /// those are not yet phased out). The parent of the closure's /// `DefId` will also be the context where it appears. - pub fn is_closure(self, def_id: DefId) -> bool { + pub fn is_closure_or_coroutine(self, def_id: DefId) -> bool { matches!(self.def_kind(def_id), DefKind::Closure) } @@ -1483,7 +1483,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( 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_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/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..c4cade83947 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -488,7 +488,7 @@ fn construct_fn<'tcx>( let arguments = &thir.params; - let (yield_ty, return_ty) = if coroutine_kind.is_some() { + let (resume_ty, 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(), @@ -496,9 +496,9 @@ fn construct_fn<'tcx>( span_bug!(span, "coroutine w/o coroutine type: {:?}", coroutine_ty) } }; - (Some(coroutine_sig.yield_ty), coroutine_sig.return_ty) + (Some(coroutine_sig.resume_ty), Some(coroutine_sig.yield_ty), coroutine_sig.return_ty) } else { - (None, fn_sig.output()) + (None, None, fn_sig.output()) }; if let Some(custom_mir_attr) = @@ -562,9 +562,12 @@ fn construct_fn<'tcx>( } else { None }; - if yield_ty.is_some() { + + if coroutine_kind.is_some() { body.coroutine.as_mut().unwrap().yield_ty = yield_ty; + body.coroutine.as_mut().unwrap().resume_ty = resume_ty; } + body } @@ -631,18 +634,18 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - 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, resume_ty, yield_ty) = match tcx.def_kind(def_id) { DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst - | DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None), + | DefKind::Static(_) => (vec![], tcx.type_of(def_id).instantiate_identity(), None, None), DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => { let sig = tcx.liberate_late_bound_regions( def_id.to_def_id(), tcx.fn_sig(def_id).instantiate_identity(), ); - (sig.inputs().to_vec(), sig.output(), None) + (sig.inputs().to_vec(), sig.output(), None, None) } DefKind::Closure if coroutine_kind.is_some() => { let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); @@ -650,9 +653,10 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - bug!("expected type of coroutine-like closure to be a coroutine") }; let args = args.as_coroutine(); + let resume_ty = args.resume_ty(); let yield_ty = args.yield_ty(); let return_ty = args.return_ty(); - (vec![coroutine_ty, args.resume_ty()], return_ty, Some(yield_ty)) + (vec![coroutine_ty, args.resume_ty()], return_ty, Some(resume_ty), Some(yield_ty)) } DefKind::Closure => { let closure_ty = tcx.type_of(def_id).instantiate_identity(); @@ -666,7 +670,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - 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) + ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None, None) } dk => bug!("{:?} is not a body: {:?}", def_id, dk), }; @@ -705,7 +709,10 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - Some(guar), ); - body.coroutine.as_mut().map(|gen| gen.yield_ty = yield_ty); + body.coroutine.as_mut().map(|gen| { + gen.yield_ty = yield_ty; + gen.resume_ty = resume_ty; + }); body } 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/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..e9da12d118e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -100,20 +100,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]); @@ -554,7 +544,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 +962,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 +1102,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/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index ce1a36cf670..33e305497b5 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1733,6 +1733,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/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index d995d562521..8c11dea5d4e 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -61,27 +61,27 @@ pub(super) struct CoverageCounters { } impl CoverageCounters { - pub(super) fn new(basic_coverage_blocks: &CoverageGraph) -> Self { + /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or + /// indirectly associated with coverage spans, and accumulates additional `Expression`s + /// representing intermediate values. + pub(super) fn make_bcb_counters( + basic_coverage_blocks: &CoverageGraph, + bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + ) -> Self { let num_bcbs = basic_coverage_blocks.num_nodes(); - Self { + let mut this = Self { next_counter_id: CounterId::START, bcb_counters: IndexVec::from_elem_n(None, num_bcbs), bcb_edge_counters: FxIndexMap::default(), bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs), expressions: IndexVec::new(), - } - } + }; - /// Makes [`BcbCounter`] `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or - /// indirectly associated with coverage spans, and accumulates additional `Expression`s - /// representing intermediate values. - pub fn make_bcb_counters( - &mut self, - basic_coverage_blocks: &CoverageGraph, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, - ) { - MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans) + MakeBcbCounters::new(&mut this, basic_coverage_blocks) + .make_bcb_counters(bcb_has_coverage_spans); + + this } fn make_counter(&mut self) -> BcbCounter { @@ -189,8 +189,8 @@ impl CoverageCounters { .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind)) } - pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> { - std::mem::take(&mut self.expressions) + pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> { + self.expressions } } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 078612aa59c..aa7b6b02f74 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,7 +8,7 @@ mod spans; mod tests; use self::counters::{BcbCounter, CoverageCounters}; -use self::graph::CoverageGraph; +use self::graph::{BasicCoverageBlock, CoverageGraph}; use self::spans::CoverageSpans; use crate::MirPass; @@ -70,7 +70,6 @@ struct Instrumentor<'a, 'tcx> { mir_body: &'a mut mir::Body<'tcx>, hir_info: ExtractedHirInfo, basic_coverage_blocks: CoverageGraph, - coverage_counters: CoverageCounters, } impl<'a, 'tcx> Instrumentor<'a, 'tcx> { @@ -80,9 +79,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); - let coverage_counters = CoverageCounters::new(&basic_coverage_blocks); - Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters } + Self { tcx, mir_body, hir_info, basic_coverage_blocks } } fn inject_counters(&'a mut self) { @@ -103,25 +101,31 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); - self.coverage_counters - .make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans); + let coverage_counters = CoverageCounters::make_bcb_counters( + &self.basic_coverage_blocks, + bcb_has_coverage_spans, + ); - let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans); + let mappings = self.create_mappings(&coverage_spans, &coverage_counters); + self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: self.hir_info.function_source_hash, - num_counters: self.coverage_counters.num_counters(), - expressions: self.coverage_counters.take_expressions(), + num_counters: coverage_counters.num_counters(), + expressions: coverage_counters.into_expressions(), mappings, })); } - /// For each [`BcbCounter`] associated with a BCB node or BCB edge, create - /// any corresponding mappings (for BCB nodes only), and inject any necessary - /// coverage statements into MIR. - fn create_mappings_and_inject_coverage_statements( - &mut self, + /// For each coverage span extracted from MIR, create a corresponding + /// mapping. + /// + /// Precondition: All BCBs corresponding to those spans have been given + /// coverage counters. + fn create_mappings( + &self, coverage_spans: &CoverageSpans, + coverage_counters: &CoverageCounters, ) -> Vec<Mapping> { let source_map = self.tcx.sess.source_map(); let body_span = self.hir_info.body_span; @@ -131,30 +135,42 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let file_name = Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); - let mut mappings = Vec::new(); - - // Process the counters and spans associated with BCB nodes. - for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() { - let spans = coverage_spans.spans_for_bcb(bcb); - let has_mappings = !spans.is_empty(); - - // If this BCB has any coverage spans, add corresponding mappings to - // the mappings table. - if has_mappings { - let term = counter_kind.as_term(); - mappings.extend(spans.iter().map(|&span| { - let code_region = make_code_region(source_map, file_name, span, body_span); - Mapping { code_region, term } - })); - } + coverage_spans + .bcbs_with_coverage_spans() + // For each BCB with spans, get a coverage term for its counter. + .map(|(bcb, spans)| { + let term = coverage_counters + .bcb_counter(bcb) + .expect("all BCBs with spans were given counters") + .as_term(); + (term, spans) + }) + // 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 } + }) + .collect::<Vec<_>>() + } + /// For each BCB node or BCB edge that has an associated coverage counter, + /// inject any necessary coverage statements into MIR. + fn inject_coverage_statements( + &mut self, + bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + coverage_counters: &CoverageCounters, + ) { + // Process the counters associated with BCB nodes. + for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { let do_inject = match counter_kind { // Counter-increment statements always need to be injected. BcbCounter::Counter { .. } => true, // The only purpose of expression-used statements is to detect // when a mapping is unreachable, so we only inject them for // expressions with one or more mappings. - BcbCounter::Expression { .. } => has_mappings, + BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), }; if do_inject { inject_statement( @@ -166,7 +182,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { } // Process the counters associated with BCB edges. - for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() { + for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { let do_inject = match counter_kind { // Counter-increment statements always need to be injected. BcbCounter::Counter { .. } => true, @@ -192,8 +208,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // Inject a counter into the newly-created BB. inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb); } - - mappings } fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { @@ -345,7 +359,7 @@ fn get_body_span<'tcx>( ) -> Span { let mut body_span = hir_body.value.span; - if tcx.is_closure(def_id.to_def_id()) { + if tcx.is_closure_or_coroutine(def_id.to_def_id()) { // If the current function is a closure, and its "body" span was created // by macro expansion or compiler desugaring, try to walk backwards to // the pre-expansion call site or body. diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ae43a18ad4e..ed091752187 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -48,8 +48,13 @@ impl CoverageSpans { !self.bcb_to_spans[bcb].is_empty() } - pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] { - &self.bcb_to_spans[bcb] + pub(super) fn bcbs_with_coverage_spans( + &self, + ) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> { + self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| { + // Only yield BCBs that have at least one coverage span. + (!spans.is_empty()).then_some((bcb, spans.as_slice())) + }) } } 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 ff6545e9d25..8f6592afe85 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -74,7 +74,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let expn_span = filtered_statement_span(statement)?; let span = unexpand_into_body_span(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement))) + Some(CoverageSpan::new(span, expn_span, bcb, is_closure_or_coroutine(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { @@ -88,7 +88,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( }) } -fn is_closure(statement: &Statement<'_>) -> bool { +fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool { match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true, diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 931bc8e58ff..d9a3c0cb162 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -630,8 +630,10 @@ fn test_make_bcb_counters() { // coverage spans for BCBs 1 and 2. Now we skip that step and just tell // BCB counter construction that those BCBs have spans. let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize()); - let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks); - coverage_counters.make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); + let coverage_counters = counters::CoverageCounters::make_bcb_counters( + &basic_coverage_blocks, + bcb_has_coverage_spans, + ); assert_eq!(coverage_counters.num_expressions(), 0); assert_eq!( diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 15502adfb5a..cd80f423466 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -133,7 +133,6 @@ use std::collections::hash_map::{Entry, OccupiedEntry}; -use crate::simplify::remove_dead_blocks; use crate::MirPass; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::BitSet; @@ -241,12 +240,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); } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 17916e16daf..bde442049b1 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()); } } } @@ -183,7 +183,7 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { 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); + diag.arg("details", desc); diag.span_label(self.details.span, self.details.label()); self.details.add_subdiagnostics(diag); @@ -213,7 +213,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 +280,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/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5562ae7f3bd..164b6b9c4f5 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -285,9 +285,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. 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/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_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 54464600d99..44beafa0873 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1119,7 +1119,10 @@ fn create_fn_mono_item<'tcx>( source: Span, ) -> Spanned<MonoItem<'tcx>> { let def_id = instance.def_id(); - if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) { + if tcx.sess.opts.unstable_opts.profile_closures + && def_id.is_local() + && tcx.is_closure_or_coroutine(def_id) + { crate::util::dump_closure_profile(tcx, instance); } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 592e71251b8..2ca14673a58 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 diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 02f9f35f0f5..f5623323168 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.0" +bitflags = "2.4.1" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } 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..4819ed6021d 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}; @@ -252,7 +250,7 @@ impl<'a> StringReader<'a> { 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.span(span); diag.stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); @@ -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) { @@ -568,13 +554,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( diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f06aeed8628..579c3cffcfb 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 }) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index fb8ad05f25d..c8629069968 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -174,7 +174,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, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 77bca2f138a..aed5e11133b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -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)), diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bf6151b64d3..0b24e784126 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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( @@ -1907,15 +1971,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. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 19226f37abe..b201d36455e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -46,6 +46,7 @@ use crate::errors::{ }; bitflags::bitflags! { + #[derive(Clone, Copy)] struct Restrictions: u8 { const STMT_EXPR = 1 << 0; const NO_STRUCT_LITERAL = 1 << 1; @@ -924,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; @@ -950,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..7d17b1d4c4d 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}; @@ -579,6 +580,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 +594,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 +819,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 +849,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? 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/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/errors.rs b/compiler/rustc_passes/src/errors.rs index 856256a0641..9bd9dd41cf6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -868,8 +868,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 +881,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 +1018,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); @@ -1162,7 +1162,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 +1273,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 +1294,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 +1340,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/liveness.rs b/compiler/rustc_passes/src/liveness.rs index cfe829f170f..8fa4fa1e384 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -351,10 +351,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); } @@ -921,14 +918,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 +1322,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); } } 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/upvars.rs b/compiler/rustc_passes/src/upvars.rs index d87df706cc8..ded20c38543 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -11,7 +11,7 @@ use rustc_span::Span; pub fn provide(providers: &mut Providers) { providers.upvars_mentioned = |tcx, def_id| { - if !tcx.is_closure(def_id) { + if !tcx.is_closure_or_coroutine(def_id) { return None; } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index e01b571ede1..8ea8dd61ab4 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -61,8 +61,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. @@ -114,6 +112,7 @@ pub fn analyze_match<'p, 'tcx>( ) -> rustc::UsefulnessReport<'p, 'tcx> { // 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 }; diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index cb712fe640c..83210a4a556 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -1,7 +1,7 @@ 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; @@ -12,10 +12,9 @@ use crate::errors::{ OverlappingRangeEndpoints, Uncovered, }; 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". @@ -48,14 +47,8 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { fn is_empty(&self) -> bool { self.patterns.is_empty() } - fn head_ty(&self, cx: MatchCtxt<'_, 'p, 'tcx>) -> Option<Ty<'tcx>> { - if self.patterns.len() == 0 { - return None; - } - - 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. @@ -117,7 +110,7 @@ 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 { + let Some(ty) = column.head_ty() else { return Vec::new(); }; let pcx = &PlaceCtxt::new_dummy(cx, ty); @@ -164,7 +157,7 @@ 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>, ) { let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx; if !matches!( @@ -182,7 +175,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,7 +197,7 @@ 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(); } @@ -218,7 +211,7 @@ 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 { + let Some(ty) = column.head_ty() else { return; }; let pcx = &PlaceCtxt::new_dummy(cx, ty); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index b09d565f076..b6f67b7c56f 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -41,6 +41,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 +98,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 +150,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 +162,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 +185,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 +208,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 +238,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 +265,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 +302,7 @@ 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>) -> ConstructorSet<'p, 'tcx> { let cx = self; let make_uint_range = |start, end| { IntRange::from_range( @@ -328,7 +376,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 +401,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`. @@ -379,7 +429,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { 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 +452,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 +465,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 +503,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 +520,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 +535,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 +550,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 +593,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 +613,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 +638,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 +677,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 +687,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 +701,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 +715,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 +746,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 +821,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 +841,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 +943,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> { } impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { - type Ty = Ty<'tcx>; + type Ty = RevealedTy<'tcx>; type VariantIdx = VariantIdx; type StrLit = Const<'tcx>; type ArmData = HirId; @@ -900,10 +953,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) } diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index d2e621a6b98..68da13861aa 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -847,8 +847,11 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { self.pats.len() } + fn head_opt(&self) -> Option<&'p DeconstructedPat<'p, Cx>> { + self.pats.first().copied() + } fn head(&self) -> &'p DeconstructedPat<'p, Cx> { - self.pats[0] + self.head_opt().unwrap() } fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> { @@ -1028,14 +1031,8 @@ 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.wildcard_row.head_opt().map(|pat| pat.ty()) } fn column_count(&self) -> usize { self.wildcard_row.len() @@ -1345,7 +1342,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( return 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() { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 59812efc324..d5883f52819 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,9 +3,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] -// this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref -#![feature(const_mut_refs)] -#![feature(const_refs_to_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 34f2c01f890..51842664eeb 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -44,6 +44,18 @@ enum QueryResult { Poisoned, } +impl QueryResult { + /// Unwraps the query job expecting that it has started. + fn expect_job(self) -> QueryJob { + match self { + Self::Started(job) => job, + Self::Poisoned => { + panic!("job for query failed to start and was poisoned") + } + } + } +} + impl<K> QueryState<K> where K: Eq + Hash + Copy + Debug, @@ -169,10 +181,7 @@ where let job = { let mut lock = state.active.lock_shard_by_value(&key); - match lock.remove(&key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - } + lock.remove(&key).unwrap().expect_job() }; job.signal_complete(); @@ -190,10 +199,8 @@ where let state = self.state; let job = { let mut shard = state.active.lock_shard_by_value(&self.key); - let job = match shard.remove(&self.key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - }; + let job = shard.remove(&self.key).unwrap().expect_job(); + shard.insert(self.key, QueryResult::Poisoned); job }; @@ -277,11 +284,14 @@ where // We didn't find the query result in the query cache. Check if it was // poisoned due to a panic instead. let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock(); + match lock.get(&key) { - // The query we waited on panicked. Continue unwinding here. - Some(QueryResult::Poisoned) => FatalError.raise(), + Some(QueryResult::Poisoned) => { + panic!("query '{}' not cached due to poisoning", query.name()) + } _ => panic!( - "query result must in the cache or the query must be poisoned after a wait" + "query '{}' result must be in the cache or the query must be poisoned after a wait", + query.name() ), } }) diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index ff9d6d8739f..a1a353ce057 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" pulldown-cmark = { version = "0.9.3", default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8743b734926..c1cb20f6bb0 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -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>, @@ -1146,10 +1148,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 +1200,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 +1216,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 +1229,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 +1268,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { descr: res.descr(), path, accessible: child_accessible, + doc_visible: child_doc_visible, note, via_import, }); @@ -1277,7 +1289,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)); } } } @@ -2687,8 +2699,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 +2817,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/ident.rs b/compiler/rustc_resolve/src/ident.rs index e559ca8e7cc..3a31addb109 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -377,6 +377,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ignore_binding: Option<NameBinding<'a>>, ) -> Result<NameBinding<'a>, Determinacy> { bitflags::bitflags! { + #[derive(Clone, Copy)] struct Flags: u8 { const MACRO_RULES = 1 << 0; const MODULE = 1 << 1; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c3026e52430..a82f7bdfbf3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -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..0fe606cacf5 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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( @@ -2191,15 +2191,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 +2214,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 +2226,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { descr: "module", path, accessible: true, + doc_visible, note: None, via_import: false, }, @@ -2226,7 +2234,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)); } } } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 1f51dd6c975..ba8f67982f5 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" getopts = "0.2" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e1640d7fca9..12d8293ecd2 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` @@ -1021,6 +1006,7 @@ impl OutputFilenames { bitflags::bitflags! { /// Scopes used to determined if it need to apply to --remap-path-prefix + #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct RemapPathScopeComponents: u8 { /// Apply remappings to the expansion of std::file!() macro const MACRO = 1 << 0; @@ -1041,7 +1027,7 @@ bitflags::bitflags! { /// An alias for macro,unsplit-debuginfo,split-debuginfo-path. This /// ensures all paths in compiled executables or libraries are remapped /// but not elsewhere. - const OBJECT = Self::MACRO.bits | Self::UNSPLIT_DEBUGINFO.bits | Self::SPLIT_DEBUGINFO_PATH.bits; + const OBJECT = Self::MACRO.bits() | Self::UNSPLIT_DEBUGINFO.bits() | Self::SPLIT_DEBUGINFO_PATH.bits(); } } @@ -1161,7 +1147,6 @@ impl UnstableOptions { 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, @@ -2050,23 +2035,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"); } } @@ -2664,7 +2640,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..758c3122404 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -19,7 +19,7 @@ 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.span(self.span); diag.code(error_code!(E0658)); diag } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8274fd05bc0..842bf1d60f6 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, @@ -1601,11 +1577,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 +1812,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], @@ -1919,8 +1888,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 diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9ee7625e5bf..ce166ae352f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -17,8 +17,8 @@ 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_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::{ @@ -1000,7 +1000,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 +1009,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) @@ -1274,7 +1274,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); } @@ -1501,7 +1504,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_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index e397fab5459..9f1db227a7c 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,6 +1,8 @@ use crate::{HashStableContext, 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; @@ -132,6 +134,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. @@ -490,6 +497,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/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0b44071496e..03af77cb3fb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -4,7 +4,9 @@ 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}; @@ -1041,6 +1043,7 @@ symbols! { mir_offset, mir_retag, mir_return, + mir_return_to, mir_set_discriminant, mir_static, mir_static_mut, @@ -2103,6 +2106,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/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index ff3f1ad646f..0ce522c9cab 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" punycode = "0.4.0" rustc-demangle = "0.1.21" rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index 06a2b3ca9c4..0fa59d2ddfb 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -19,7 +19,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TestOutput { #[allow(rustc::untranslatable_diagnostic)] let mut diag = DiagnosticBuilder::new(dcx, level, format!("{kind}({content})")); - diag.set_span(span); + diag.span(span); diag } } diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index cda16e3a3f5..838d9d774b2 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -11,6 +11,7 @@ use twox_hash::XxHash64; bitflags! { /// Options for typeid_for_fnabi and typeid_for_fnsig. + #[derive(Clone, Copy, Debug)] pub struct TypeIdOptions: u32 { const GENERALIZE_POINTERS = 1; const GENERALIZE_REPR_C = 2; diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 94dfeb12dc9..2cb8ac7e8bf 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index e9730947389..fafc10e7163 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -93,9 +93,10 @@ pub use attr_impl::ArgAttribute; #[allow(unused)] mod attr_impl { // The subset of llvm::Attribute needed for arguments, packed into a bitfield. + #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, HashStable_Generic)] + pub struct ArgAttribute(u8); bitflags::bitflags! { - #[derive(Default, HashStable_Generic)] - pub struct ArgAttribute: u8 { + impl ArgAttribute: u8 { const NoAlias = 1 << 1; const NoCapture = 1 << 2; const NonNull = 1 << 3; @@ -104,6 +105,7 @@ mod attr_impl { const NoUndef = 1 << 6; } } + rustc_data_structures::external_bitflags_debug! { ArgAttribute } } /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum 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 4789a9be151..9d25388b90f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -39,7 +39,6 @@ use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; use crate::spec::crt_objects::CrtObjects; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::try_canonicalize; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -592,7 +591,7 @@ impl LinkSelfContainedDefault { } bitflags::bitflags! { - #[derive(Default)] + #[derive(Clone, Copy, PartialEq, Eq, Default)] /// The `-C link-self-contained` components that can individually be enabled or disabled. pub struct LinkSelfContainedComponents: u8 { /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) @@ -609,6 +608,7 @@ bitflags::bitflags! { const MINGW = 1 << 5; } } +rustc_data_structures::external_bitflags_debug! { LinkSelfContainedComponents } impl LinkSelfContainedComponents { /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. @@ -667,19 +667,6 @@ impl LinkSelfContainedComponents { } } -impl IntoIterator for LinkSelfContainedComponents { - type Item = LinkSelfContainedComponents; - type IntoIter = std::vec::IntoIter<LinkSelfContainedComponents>; - - fn into_iter(self) -> Self::IntoIter { - LinkSelfContainedComponents::all_components() - .into_iter() - .filter(|&s| self.contains(s)) - .collect::<Vec<_>>() - .into_iter() - } -} - impl ToJson for LinkSelfContainedComponents { fn to_json(&self) -> Json { let components: Vec<_> = Self::all_components() @@ -1219,9 +1206,10 @@ impl ToJson for StackProbeType { } } +#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] +pub struct SanitizerSet(u16); bitflags::bitflags! { - #[derive(Default, Encodable, Decodable)] - pub struct SanitizerSet: u16 { + impl SanitizerSet: u16 { const ADDRESS = 1 << 0; const LEAK = 1 << 1; const MEMORY = 1 << 2; @@ -1235,6 +1223,7 @@ bitflags::bitflags! { const SAFESTACK = 1 << 10; } } +rustc_data_structures::external_bitflags_debug! { SanitizerSet } impl SanitizerSet { /// Return sanitizer's name @@ -1274,38 +1263,6 @@ impl fmt::Display for SanitizerSet { } } -impl IntoIterator for SanitizerSet { - type Item = SanitizerSet; - type IntoIter = std::vec::IntoIter<SanitizerSet>; - - fn into_iter(self) -> Self::IntoIter { - [ - SanitizerSet::ADDRESS, - SanitizerSet::CFI, - SanitizerSet::KCFI, - SanitizerSet::LEAK, - SanitizerSet::MEMORY, - SanitizerSet::MEMTAG, - SanitizerSet::SHADOWCALLSTACK, - SanitizerSet::THREAD, - SanitizerSet::HWADDRESS, - SanitizerSet::KERNELADDRESS, - SanitizerSet::SAFESTACK, - ] - .iter() - .copied() - .filter(|&s| self.contains(s)) - .collect::<Vec<_>>() - .into_iter() - } -} - -impl<CTX> HashStable<CTX> for SanitizerSet { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.bits().hash_stable(ctx, hasher); - } -} - impl ToJson for SanitizerSet { fn to_json(&self) -> Json { self.into_iter() 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_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index ba80c23196e..5b91682e168 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); + base.vendor = "win7".into(); base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), 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_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/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f63314081d6..58700850a60 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -19,11 +19,10 @@ use rustc_errors::{ 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; @@ -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..efc75ee538e 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 @@ -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) => { @@ -3163,14 +3163,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) )); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 3a08d89cc44..38f0eb82180 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "1.2.1" +bitflags = "2.4.1" derivative = "2.2.0" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index af741a0a3a0..bc57d6daf47 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -3,6 +3,7 @@ bitflags! { /// through the type during type construction, so that we can quickly check /// whether the type has various kinds of types in it without recursing /// over the type itself. + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct TypeFlags: u32 { // Does this have parameters? Used to determine whether substitution is // required. @@ -13,9 +14,9 @@ bitflags! { /// Does this have `ConstKind::Param`? const HAS_CT_PARAM = 1 << 2; - const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_RE_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits; + const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits() + | TypeFlags::HAS_RE_PARAM.bits() + | TypeFlags::HAS_CT_PARAM.bits(); /// Does this have `Infer`? const HAS_TY_INFER = 1 << 3; @@ -26,9 +27,9 @@ bitflags! { /// Does this have inference variables? Used to determine whether /// inference is required. - const HAS_INFER = TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_RE_INFER.bits - | TypeFlags::HAS_CT_INFER.bits; + const HAS_INFER = TypeFlags::HAS_TY_INFER.bits() + | TypeFlags::HAS_RE_INFER.bits() + | TypeFlags::HAS_CT_INFER.bits(); /// Does this have `Placeholder`? const HAS_TY_PLACEHOLDER = 1 << 6; @@ -38,9 +39,9 @@ bitflags! { const HAS_CT_PLACEHOLDER = 1 << 8; /// Does this have placeholders? - const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_RE_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits; + const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits() + | TypeFlags::HAS_RE_PLACEHOLDER.bits() + | TypeFlags::HAS_CT_PLACEHOLDER.bits(); /// `true` if there are "names" of regions and so forth /// that are local to a particular fn/inferctxt @@ -48,12 +49,12 @@ bitflags! { /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits - | TypeFlags::HAS_CT_PARAM.bits - | TypeFlags::HAS_TY_INFER.bits - | TypeFlags::HAS_CT_INFER.bits - | TypeFlags::HAS_TY_PLACEHOLDER.bits - | TypeFlags::HAS_CT_PLACEHOLDER.bits + const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits() + | TypeFlags::HAS_CT_PARAM.bits() + | TypeFlags::HAS_TY_INFER.bits() + | TypeFlags::HAS_CT_INFER.bits() + | TypeFlags::HAS_TY_PLACEHOLDER.bits() + | TypeFlags::HAS_CT_PLACEHOLDER.bits() // We consider 'freshened' types and constants // to depend on a particular fn. // The freshening process throws away information, @@ -61,10 +62,10 @@ bitflags! { // cache. Note that there is no 'fresh lifetime' flag - // freshening replaces all lifetimes with `ReErased`, // which is different from how types/const are freshened. - | TypeFlags::HAS_TY_FRESH.bits - | TypeFlags::HAS_CT_FRESH.bits - | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits - | TypeFlags::HAS_RE_ERASED.bits; + | TypeFlags::HAS_TY_FRESH.bits() + | TypeFlags::HAS_CT_FRESH.bits() + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits() + | TypeFlags::HAS_RE_ERASED.bits(); /// Does this have `Projection`? const HAS_TY_PROJECTION = 1 << 10; @@ -76,10 +77,10 @@ bitflags! { const HAS_CT_PROJECTION = 1 << 13; /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits - | TypeFlags::HAS_TY_OPAQUE.bits - | TypeFlags::HAS_TY_INHERENT.bits - | TypeFlags::HAS_CT_PROJECTION.bits; + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits() + | TypeFlags::HAS_TY_OPAQUE.bits() + | TypeFlags::HAS_TY_INHERENT.bits() + | TypeFlags::HAS_CT_PROJECTION.bits(); /// Is an error type/const reachable? const HAS_ERROR = 1 << 14; @@ -96,9 +97,9 @@ bitflags! { const HAS_CT_BOUND = 1 << 18; /// Does this have any bound variables? /// Used to check if a global bound is safe to evaluate. - const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits - | TypeFlags::HAS_TY_BOUND.bits - | TypeFlags::HAS_CT_BOUND.bits; + const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits() + | TypeFlags::HAS_TY_BOUND.bits() + | TypeFlags::HAS_CT_BOUND.bits(); /// Does this have any `ReErased` regions? const HAS_RE_ERASED = 1 << 19; |
