diff options
| author | bors <bors@rust-lang.org> | 2024-07-02 06:29:31 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-07-02 06:29:31 +0000 |
| commit | 3ca56a34bd9cd7b05aaaa668d6653fdc99033357 (patch) | |
| tree | d3a4cadce7ec832453d49cb1d9d1c6fce3dd6ce5 /compiler | |
| parent | 9d920ed33323028200f56a3451157e0da3d360d8 (diff) | |
| parent | cbea3d7add356898fdfc84e9433baaa514df5552 (diff) | |
Auto merge of #3727 - RalfJung:rustup, r=RalfJung
Rustup To unblock https://github.com/rust-lang/miri/pull/3688
Diffstat (limited to 'compiler')
175 files changed, 3016 insertions, 2108 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 624bca525b9..218fa974022 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -103,7 +103,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ParamMode::Optional, ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, // Method calls can't have bound modifiers None, )); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 74e04eff4f3..d59ac576629 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -56,7 +56,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver); + let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -190,6 +190,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (ty, body_id)) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -221,7 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, decl) = - this.lower_generics(generics, header.constness, id, itctx, |this| { + this.lower_generics(generics, header.constness, false, id, itctx, |this| { this.lower_fn_decl( decl, id, @@ -265,6 +266,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -293,6 +295,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, variants) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -307,6 +310,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, struct_def) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -317,6 +321,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, vdata) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -348,12 +353,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, *constness, id, itctx, |this| { + self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| { let modifiers = TraitBoundModifiers { - constness: match *constness { - Const::Yes(span) => BoundConstness::Maybe(span), - Const::No => BoundConstness::Never, - }, + constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, // we don't use this in bound lowering polarity: BoundPolarity::Positive, @@ -389,6 +391,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { + constness: self.lower_constness(*constness), safety: self.lower_safety(*safety, hir::Safety::Safe), polarity, defaultness, @@ -400,15 +403,10 @@ impl<'hir> LoweringContext<'_, 'hir> { })) } ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => { - // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible - let constness = attrs - .unwrap_or(&[]) - .iter() - .find(|x| x.has_name(sym::const_trait)) - .map_or(Const::No, |x| Const::Yes(x.span)); let (generics, (safety, items, bounds)) = self.lower_generics( generics, - constness, + Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -429,6 +427,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, bounds) = self.lower_generics( generics, Const::No, + false, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -609,30 +608,45 @@ impl<'hir> LoweringContext<'_, 'hir> { // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - let generics = match parent_hir.node().expect_item().kind { + let parent_item = parent_hir.node().expect_item(); + let constness = match parent_item.kind { hir::ItemKind::Impl(impl_) => { self.is_in_trait_impl = impl_.of_trait.is_some(); - &impl_.generics + // N.B. the impl should always lower to methods that have `const host: bool` params if the trait + // is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from + // calling non-const impls are done through associated types. + if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) { + if let Some(local_def) = def_id.as_local() { + match &self.ast_index[local_def] { + AstOwner::Item(ast::Item { attrs, .. }) => attrs + .iter() + .find(|attr| attr.has_name(sym::const_trait)) + .map_or(Const::No, |attr| Const::Yes(attr.span)), + _ => Const::No, + } + } else { + self.tcx + .get_attr(def_id, sym::const_trait) + .map_or(Const::No, |attr| Const::Yes(attr.span)) + } + } else { + Const::No + } } - hir::ItemKind::Trait(_, _, generics, _, _) => generics, + hir::ItemKind::Trait(_, _, _, _, _) => parent_hir + .attrs + .get(parent_item.hir_id().local_id) + .iter() + .find(|attr| attr.has_name(sym::const_trait)) + .map_or(Const::No, |attr| Const::Yes(attr.span)), kind => { span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr()) } }; - if self.tcx.features().effects { - self.host_param_id = generics - .params - .iter() - .find(|param| { - matches!(param.kind, hir::GenericParamKind::Const { is_host_effect: true, .. }) - }) - .map(|param| param.def_id); - } - match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)), } } @@ -648,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, Const::No, i.id, itctx, |this| { + self.lower_generics(generics, Const::No, false, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -765,7 +779,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { + fn lower_trait_item( + &mut self, + i: &AssocItem, + trait_constness: Const, + ) -> &'hir hir::TraitItem<'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -775,6 +793,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -795,6 +814,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } @@ -813,6 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + trait_constness, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -822,6 +843,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( &generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -894,7 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } - fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { + fn lower_impl_item( + &mut self, + i: &AssocItem, + constness_of_trait: Const, + ) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); @@ -905,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -930,6 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, + constness_of_trait, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -940,6 +968,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( &generics, Const::No, + false, i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1352,15 +1381,18 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option<CoroutineKind>, + parent_constness: Const, ) -> (&'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 constness = + if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = + self.lower_generics(generics, constness, kind == FnDeclKind::Impl, 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) }) } @@ -1436,6 +1468,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, constness: Const, + force_append_constness: bool, parent_node_id: NodeId, itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1496,7 +1529,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // if the effects feature is enabled. This needs to be done before we lower where // clauses since where clauses need to bind to the DefId of the host param let host_param_parts = if let Const::Yes(span) = constness - && self.tcx.features().effects + // if this comes from implementing a `const` trait, we must force constness to be appended + // to the impl item, no matter whether effects is enabled. + && (self.tcx.features().effects || force_append_constness) { let span = self.lower_span(span); let param_node_id = self.next_node_id(); @@ -1609,6 +1644,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }), )), )), + // FIXME(effects) we might not need a default. default: Some(self.arena.alloc(hir::AnonConst { def_id: anon_const, hir_id: const_id, @@ -1616,6 +1652,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, })), is_host_effect: true, + synthetic: true, }, colon_span: None, pure_wrt_drop: false, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0a06304fcec..8fba46625ab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -142,14 +142,19 @@ struct LoweringContext<'a, 'hir> { generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, host_param_id: Option<LocalDefId>, + ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { + fn new( + tcx: TyCtxt<'hir>, + resolver: &'a mut ResolverAstLowering, + ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>, + ) -> Self { Self { // Pseudo-globals. tcx, - resolver: resolver, + resolver, arena: tcx.hir_arena, // HirId handling. @@ -185,6 +190,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), generics_def_id_map: Default::default(), host_param_id: None, + ast_index, } } @@ -2135,7 +2141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind(param, source); + let (name, kind) = self.lower_generic_param_kind( + param, + source, + attr::contains_name(¶m.attrs, sym::rustc_runtime), + ); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2155,6 +2165,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, + is_host_effect: bool, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2220,7 +2231,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, is_host_effect: false }, + hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false }, ) } } @@ -2607,78 +2618,6 @@ struct GenericArgsCtor<'hir> { } impl<'hir> GenericArgsCtor<'hir> { - fn push_constness( - &mut self, - lcx: &mut LoweringContext<'_, 'hir>, - constness: ast::BoundConstness, - ) { - if !lcx.tcx.features().effects { - return; - } - - let (span, body) = match constness { - BoundConstness::Never => return, - BoundConstness::Always(span) => { - let span = lcx.lower_span(span); - - let body = hir::ExprKind::Lit( - lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }), - ); - - (span, body) - } - BoundConstness::Maybe(span) => { - let span = lcx.lower_span(span); - - let Some(host_param_id) = lcx.host_param_id else { - lcx.dcx().span_delayed_bug( - span, - "no host param id for call in const yet no errors reported", - ); - return; - }; - - let hir_id = lcx.next_id(); - let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id()); - let body = hir::ExprKind::Path(hir::QPath::Resolved( - None, - lcx.arena.alloc(hir::Path { - span, - res, - segments: arena_vec![ - lcx; - hir::PathSegment::new( - Ident { name: sym::host, span }, - hir_id, - res - ) - ], - }), - )); - - (span, body) - } - }; - let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body))); - - let id = lcx.next_node_id(); - let hir_id = lcx.next_id(); - - let def_id = lcx.create_def( - lcx.current_hir_id_owner.def_id, - id, - kw::Empty, - DefKind::AnonConst, - span, - ); - - lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.args.push(hir::GenericArg::Const(hir::ConstArg { - value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }), - is_desugared_from_effects: true, - })) - } - fn is_empty(&self) -> bool { self.args.is_empty() && self.constraints.is_empty() diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 9d38e1e6784..9a1ca703699 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -107,8 +107,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode, parenthesized_generic_args, itctx, - // if this is the last segment, add constness to the trait path - if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None }, bound_modifier_allowed_features.clone(), ) }, @@ -165,7 +163,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, itctx, None, - None, )); let qpath = hir::QPath::TypeRelative(ty, hir_segment); @@ -208,7 +205,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, - None, ) })), span: self.lower_span(p.span), @@ -222,7 +218,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: ImplTraitContext, - constness: Option<ast::BoundConstness>, // Additional features ungated with a bound modifier like `async`. // This is passed down to the implicit associated type binding in // parenthesized bounds. @@ -289,10 +284,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) }; - if let Some(constness) = constness { - generic_args.push_constness(self, constness); - } - let has_lifetimes = generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba4b6130b60..022f953c6e7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1,10 +1,20 @@ -// Validate AST before lowering it to HIR. -// -// This pass is supposed to catch things that fit into AST data structures, -// but not permitted by the language. It runs after expansion when AST is frozen, -// so it can check for erroneous constructions produced by syntax extensions. -// This pass is supposed to perform only simple checks not requiring name resolution -// or type checking or some other kind of complex analysis. +//! Validate AST before lowering it to HIR. +//! +//! This pass intends to check that the constructed AST is *syntactically valid* to allow the rest +//! of the compiler to assume that the AST is valid. These checks cannot be performed during parsing +//! because attribute macros are allowed to accept certain pieces of invalid syntax such as a +//! function without body outside of a trait definition: +//! +//! ```ignore (illustrative) +//! #[my_attribute] +//! mod foo { +//! fn missing_body(); +//! } +//! ``` +//! +//! These checks are run post-expansion, after AST is frozen, to be able to check for erroneous +//! constructions produced by proc macros. This pass is only intended for simple checks that do not +//! require name resolution or type checking, or other kinds of complex analysis. use itertools::{Either, Itertools}; use rustc_ast::ptr::P; @@ -459,13 +469,18 @@ impl<'a> AstValidator<'a> { fn check_item_safety(&self, span: Span, safety: Safety) { match self.extern_mod_safety { Some(extern_safety) => { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) - && (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks) - { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span: span, - block: self.current_extern_span().shrink_to_lo(), - }); + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) { + if extern_safety == Safety::Default { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: Some(self.current_extern_span().shrink_to_lo()), + }); + } else if !self.features.unsafe_extern_blocks { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: None, + }); + } } } None => { @@ -1088,7 +1103,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } else if let &Safety::Unsafe(span) = safety { - this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); + let mut diag = this + .dcx() + .create_err(errors::UnsafeItem { span, kind: "extern block" }); + rustc_session::parse::add_feature_diagnostics( + &mut diag, + self.session, + sym::unsafe_extern_blocks, + ); + diag.emit(); } if abi.is_none() { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 965d8fac712..bfb90476450 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -222,7 +222,7 @@ pub struct InvalidSafetyOnExtern { #[primary_span] pub item_span: Span, #[suggestion(code = "unsafe ", applicability = "machine-applicable", style = "verbose")] - pub block: Span, + pub block: Option<Span>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index f26f8711dd4..8eb44458137 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -6,8 +6,8 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; -impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { - pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { +impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { + pub fn dcx(&self) -> DiagCtxtHandle<'infcx> { self.infcx.dcx() } @@ -18,7 +18,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { place: &str, borrow_place: &str, value_place: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { self.dcx().create_err(crate::session_diagnostics::MoveBorrow { place, span, @@ -34,7 +34,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { desc: &str, borrow_span: Span, borrow_desc: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), span, @@ -54,7 +54,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { old_loan_span: Span, old_opt_via: &str, old_load_end_span: Option<Span>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_code_err!( self.dcx(), @@ -101,7 +101,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { desc: &str, old_loan_span: Span, old_load_end_span: Option<Span>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -134,7 +134,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { noun_old: &str, old_opt_via: &str, previous_end_span: Option<Span>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -166,7 +166,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { old_opt_via: &str, previous_end_span: Option<Span>, second_borrow_desc: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -198,7 +198,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { kind_old: &str, msg_old: &str, old_load_end_span: Option<Span>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_code_err!( self.dcx(), @@ -239,7 +239,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { span: Span, borrow_span: Span, desc: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), span, @@ -256,12 +256,12 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { span: Span, desc: &str, is_arg: bool, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) } - pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'tcx> { + pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> Diag<'infcx> { struct_span_code_err!(self.dcx(), span, E0594, "cannot assign to {}", desc) } @@ -269,7 +269,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, move_from_span: Span, move_from_desc: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), move_from_span, @@ -287,7 +287,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { move_from_span: Span, ty: Ty<'_>, is_index: Option<bool>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", @@ -308,7 +308,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, move_from_span: Span, container_ty: Ty<'_>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), move_from_span, @@ -325,7 +325,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { verb: &str, optional_adverb_for_moved: &str, moved_path: Option<String>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); struct_span_code_err!( @@ -344,7 +344,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { span: Span, path: &str, reason: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), span, @@ -362,7 +362,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { immutable_place: &str, immutable_section: &str, action: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), mutate_span, @@ -380,7 +380,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, span: Span, yield_span: Span, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind; struct_span_code_err!( self.dcx(), @@ -391,7 +391,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { .with_span_label(yield_span, "possible yield occurs here") } - pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'tcx> { + pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), borrow_span, @@ -400,7 +400,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { ) } - pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'tcx> { + pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> { struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) } @@ -410,7 +410,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { return_kind: &str, reference_desc: &str, path_desc: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), span, @@ -433,7 +433,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { borrowed_path: &str, capture_span: Span, scope: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), closure_span, @@ -445,7 +445,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { .with_span_label(closure_span, format!("may outlive borrowed value {borrowed_path}")) } - pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'tcx> { + pub(crate) fn thread_local_value_does_not_live_long_enough(&self, span: Span) -> Diag<'infcx> { struct_span_code_err!( self.dcx(), span, @@ -454,7 +454,7 @@ impl<'tcx> crate::MirBorrowckCtxt<'_, '_, '_, 'tcx> { ) } - pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'tcx> { + pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> { struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) } } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index f2b5ddcd782..00a30dc2240 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -15,24 +15,24 @@ use std::fmt; use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; /// The results of the dataflow analyses used by the borrow checker. -pub struct BorrowckResults<'mir, 'tcx> { - pub(crate) borrows: Results<'tcx, Borrows<'mir, 'tcx>>, - pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, - pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>, +pub struct BorrowckResults<'a, 'mir, 'tcx> { + pub(crate) borrows: Results<'tcx, Borrows<'a, 'mir, 'tcx>>, + pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'mir, 'tcx>>, + pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'mir, 'tcx>>, } /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Debug)] -pub struct BorrowckFlowState<'mir, 'tcx> { - pub(crate) borrows: <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, - pub(crate) uninits: <MaybeUninitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, - pub(crate) ever_inits: <EverInitializedPlaces<'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, +pub struct BorrowckFlowState<'a, 'mir, 'tcx> { + pub(crate) borrows: <Borrows<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, + pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, + pub(crate) ever_inits: <EverInitializedPlaces<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Domain, } -impl<'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'mir, 'tcx> { +impl<'a, 'mir, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'mir, 'tcx> { // All three analyses are forward, but we have to use just one here. - type Direction = <Borrows<'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction; - type FlowState = BorrowckFlowState<'mir, 'tcx>; + type Direction = <Borrows<'a, 'mir, 'tcx> as AnalysisDomain<'tcx>>::Direction; + type FlowState = BorrowckFlowState<'a, 'mir, 'tcx>; fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { BorrowckFlowState { @@ -106,11 +106,11 @@ rustc_index::newtype_index! { /// `BorrowIndex`, and maps each such index to a `BorrowData` /// describing the borrow. These indexes are used for representing the /// borrows in compact bitvectors. -pub struct Borrows<'mir, 'tcx> { +pub struct Borrows<'a, 'mir, 'tcx> { tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, - borrow_set: &'mir BorrowSet<'tcx>, + borrow_set: &'a BorrowSet<'tcx>, borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, } @@ -389,12 +389,12 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { } } -impl<'mir, 'tcx> Borrows<'mir, 'tcx> { +impl<'a, 'mir, 'tcx> Borrows<'a, 'mir, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, - regioncx: &'mir RegionInferenceContext<'tcx>, - borrow_set: &'mir BorrowSet<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + borrow_set: &'a BorrowSet<'tcx>, ) -> Self { let mut borrows_out_of_scope_at_location = calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set); @@ -494,7 +494,7 @@ impl<'mir, 'tcx> Borrows<'mir, 'tcx> { } } -impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { +impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, '_, 'tcx> { type Domain = BitSet<BorrowIndex>; const NAME: &'static str = "borrows"; @@ -517,7 +517,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { /// region stops containing the CFG points reachable from the issuing location. /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of /// `a.b.c` when `a` is overwritten. -impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { +impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, '_, 'tcx> { type Idx = BorrowIndex; fn domain_size(&self, _: &mir::Body<'tcx>) -> usize { @@ -617,8 +617,8 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } -impl DebugWithContext<Borrows<'_, '_>> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl DebugWithContext<Borrows<'_, '_, '_>> for BorrowIndex { + fn fmt_with(&self, ctxt: &Borrows<'_, '_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", ctxt.location(*self)) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index d46febffba8..8bf3e670ff2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -149,13 +149,13 @@ trait TypeOpInfo<'tcx> { fn base_universe(&self) -> ty::UniverseIndex; - fn nice_error( + fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<Diag<'tcx>>; + ) -> Option<Diag<'infcx>>; #[instrument(level = "debug", skip(self, mbcx))] fn report_error( @@ -231,18 +231,25 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { self.base_universe } - fn nice_error( + fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<Diag<'tcx>> { + ) -> Option<Diag<'infcx>> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); type_op_prove_predicate_with_cause(&ocx, key, cause); - try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region) + let diag = try_extract_error_from_fulfill_cx( + &ocx, + mbcx.mir_def_id(), + placeholder_region, + error_region, + )? + .with_dcx(mbcx.dcx()); + Some(diag) } } @@ -268,13 +275,13 @@ where self.base_universe } - fn nice_error( + fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<Diag<'tcx>> { + ) -> Option<Diag<'infcx>> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); @@ -288,7 +295,14 @@ where let (param_env, value) = key.into_parts(); let _ = ocx.normalize(&cause, param_env, value.value); - try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region) + let diag = try_extract_error_from_fulfill_cx( + &ocx, + mbcx.mir_def_id(), + placeholder_region, + error_region, + )? + .with_dcx(mbcx.dcx()); + Some(diag) } } @@ -308,18 +322,25 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { self.base_universe } - fn nice_error( + fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<Diag<'tcx>> { + ) -> Option<Diag<'infcx>> { let (infcx, key, _) = mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); let ocx = ObligationCtxt::new(&infcx); type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?; - try_extract_error_from_fulfill_cx(&ocx, mbcx.mir_def_id(), placeholder_region, error_region) + let diag = try_extract_error_from_fulfill_cx( + &ocx, + mbcx.mir_def_id(), + placeholder_region, + error_region, + )? + .with_dcx(mbcx.dcx()); + Some(diag) } } @@ -334,13 +355,13 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { self.base_universe.unwrap() } - fn nice_error( + fn nice_error<'infcx>( &self, - mbcx: &mut MirBorrowckCtxt<'_, '_, '_, 'tcx>, + mbcx: &mut MirBorrowckCtxt<'_, '_, 'infcx, 'tcx>, _cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<Diag<'tcx>> { + ) -> Option<Diag<'infcx>> { try_extract_error_from_region_constraints( mbcx.infcx, mbcx.mir_def_id(), @@ -358,12 +379,12 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { } #[instrument(skip(ocx), level = "debug")] -fn try_extract_error_from_fulfill_cx<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, +fn try_extract_error_from_fulfill_cx<'a, 'tcx>( + ocx: &ObligationCtxt<'a, 'tcx>, generic_param_scope: LocalDefId, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, -) -> Option<Diag<'tcx>> { +) -> Option<Diag<'a>> { // We generally shouldn't have errors here because the query was // already run, but there's no point using `span_delayed_bug` // when we're going to emit an error here anyway. @@ -381,15 +402,15 @@ fn try_extract_error_from_fulfill_cx<'tcx>( } #[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))] -fn try_extract_error_from_region_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, +fn try_extract_error_from_region_constraints<'a, 'tcx>( + infcx: &'a InferCtxt<'tcx>, generic_param_scope: LocalDefId, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, region_constraints: &RegionConstraintData<'tcx>, mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin, mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex, -) -> Option<Diag<'tcx>> { +) -> Option<Diag<'a>> { let placeholder_universe = match placeholder_region.kind() { ty::RePlaceholder(p) => p.universe, ty::ReVar(vid) => universe_of_region(vid), diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1cc7fee718e..44ab762f66e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -73,7 +73,7 @@ enum StorageDeadOrDrop<'tcx> { Destructor(Ty<'tcx>), } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pub(crate) fn report_use_of_moved_or_uninitialized( &mut self, location: Location, @@ -341,7 +341,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { fn suggest_ref_or_clone( &self, mpi: MovePathIndex, - err: &mut Diag<'tcx>, + err: &mut Diag<'infcx>, in_pattern: &mut bool, move_spans: UseSpans<'tcx>, ) { @@ -517,7 +517,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { desired_action: InitializationRequiringAction, span: Span, use_spans: UseSpans<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { // We need all statements in the body where the binding was assigned to later find all // the branching code paths where the binding *wasn't* assigned to. let inits = &self.move_data.init_path_map[mpi]; @@ -1288,7 +1288,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { return false; } // Try to find predicates on *generic params* that would allow copying `ty` - let suggestion = + let mut suggestion = if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { format!(": {symbol}.clone()") } else { @@ -1296,6 +1296,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { }; let mut sugg = Vec::with_capacity(2); let mut inner_expr = expr; + let mut is_raw_ptr = false; + let typeck_result = self.infcx.tcx.typeck(self.mir_def_id()); // Remove uses of `&` and `*` when suggesting `.clone()`. while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) = &inner_expr.kind @@ -1306,14 +1308,32 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { return false; } inner_expr = inner; + if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) { + if matches!(inner_type.kind(), ty::RawPtr(..)) { + is_raw_ptr = true; + break; + } + } } - if inner_expr.span.lo() != expr.span.lo() { + // Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch error. (see #126863) + if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr { + // Remove "(*" or "(&" sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new())); } + // Check whether `expr` is surrounded by parentheses or not. let span = if inner_expr.span.hi() != expr.span.hi() { // Account for `(*x)` to suggest `x.clone()`. - expr.span.with_lo(inner_expr.span.hi()) + if is_raw_ptr { + expr.span.shrink_to_hi() + } else { + // Remove the close parenthesis ")" + expr.span.with_lo(inner_expr.span.hi()) + } } else { + if is_raw_ptr { + sugg.push((expr.span.shrink_to_lo(), "(".to_string())); + suggestion = ").clone()".to_string(); + } expr.span.shrink_to_hi() }; sugg.push((span, suggestion)); @@ -1441,7 +1461,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { location: Location, (place, _span): (Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); @@ -1491,7 +1511,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -1782,7 +1802,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { err } - fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) { + fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'infcx>, place: Place<'tcx>) { let tcx = self.infcx.tcx; let hir = tcx.hir(); let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return }; @@ -2841,7 +2861,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { debug!( "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ @@ -3016,7 +3036,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, drop_span: Span, borrow_span: Span, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { debug!( "report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ @@ -3041,7 +3061,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { @@ -3206,7 +3226,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'infcx>> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", @@ -3299,7 +3319,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { constraint_span: Span, captured_var: &str, scope: &str, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -3411,7 +3431,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { upvar_span: Span, upvar_name: Symbol, escape_span: Span, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let tcx = self.infcx.tcx; let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 842ed38f1e2..4567a014fe8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -69,7 +69,7 @@ pub(super) struct DescribePlaceOpt { pub(super) struct IncludingTupleField(pub(super) bool); -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure /// is moved after being invoked. /// @@ -86,7 +86,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, location: Location, place: PlaceRef<'tcx>, - diag: &mut Diag<'_>, + diag: &mut Diag<'infcx>, ) -> bool { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); let mut target = place.local_or_deref_local(); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 12fa4c4f5ee..c817a80a541 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -93,7 +93,7 @@ enum GroupedMoveError<'tcx> { }, } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pub(crate) fn report_move_errors(&mut self) { let grouped_errors = self.group_move_errors(); for error in grouped_errors { @@ -291,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { self.buffer_error(err); } - fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'tcx> { + fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) } else { @@ -428,7 +428,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option<UseSpans<'tcx>>, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let tcx = self.infcx.tcx; // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -639,12 +639,27 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) { match self.infcx.tcx.sess.source_map().span_to_snippet(span) { Ok(snippet) if snippet.starts_with('*') => { - err.span_suggestion_verbose( - span.with_hi(span.lo() + BytePos(1)), - "consider removing the dereference here", - String::new(), - Applicability::MaybeIncorrect, - ); + let sp = span.with_lo(span.lo() + BytePos(1)); + let inner = self.find_expr(sp); + let mut is_raw_ptr = false; + if let Some(inner) = inner { + let typck_result = self.infcx.tcx.typeck(self.mir_def_id()); + if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) { + if matches!(inner_type.kind(), ty::RawPtr(..)) { + is_raw_ptr = true; + } + } + } + // If the `inner` is a raw pointer, do not suggest removing the "*", see #126863 + // FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`. + if !is_raw_ptr { + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(1)), + "consider removing the dereference here", + String::new(), + Applicability::MaybeIncorrect, + ); + } } _ => { err.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 93fac3181ba..19a4df0cd7b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -30,7 +30,7 @@ pub(crate) enum AccessKind { Mutate, } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pub(crate) fn report_mutability_error( &mut self, access_place: Place<'tcx>, @@ -541,7 +541,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { } /// Suggest `map[k] = v` => `map.insert(k, v)` and the like. - fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'tcx>, span: Span) { + fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'infcx>, span: Span) { let Some(adt) = ty.ty_adt_def() else { return }; let did = adt.did(); if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did) @@ -550,13 +550,13 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { /// Walks through the HIR, looking for the corresponding span for this error. /// When it finds it, see if it corresponds to assignment operator whose LHS /// is an index expr. - struct SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> { + struct SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> { assign_span: Span, - err: &'a mut Diag<'tcx>, + err: &'a mut Diag<'infcx>, ty: Ty<'tcx>, suggested: bool, } - impl<'a, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> { + impl<'a, 'cx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'cx, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { hir::intravisit::walk_stmt(self, stmt); let expr = match stmt.kind { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index db78edc45b9..fba18c38146 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -160,7 +160,7 @@ pub struct ErrorConstraintInfo<'tcx> { pub(super) span: Span, } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// Converts a region inference variable into a `ty::Region` that /// we can use for error reporting. If `r` is universally bound, /// then we use the name that we have on record for it. If `r` is @@ -360,7 +360,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); let diag = unexpected_hidden_region_diagnostic( - self.infcx.tcx, + self.infcx, self.mir_def_id(), span, named_ty, @@ -589,7 +589,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { &self, errci: &ErrorConstraintInfo<'tcx>, kind: ReturnConstraint, - ) -> Diag<'tcx> { + ) -> Diag<'infcx> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; @@ -658,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { /// | ^^^^^^^^^^ `x` escapes the function body here /// ``` #[instrument(level = "debug", skip(self))] - fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> { + fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> { let ErrorConstraintInfo { span, category, .. } = errci; let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( @@ -767,7 +767,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { /// | is returning data with lifetime `'b` /// ``` #[allow(rustc::diagnostic_outside_of_impl)] // FIXME - fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> { + fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> { let ErrorConstraintInfo { fr, fr_is_local, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 69efee2fbdc..e6f8ffd428d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -310,8 +310,8 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); diags = promoted_mbcx.diags; - struct MoveVisitor<'a, 'b, 'mir, 'cx, 'tcx> { - ctxt: &'a mut MirBorrowckCtxt<'b, 'mir, 'cx, 'tcx>, + struct MoveVisitor<'a, 'b, 'mir, 'infcx, 'tcx> { + ctxt: &'a mut MirBorrowckCtxt<'b, 'mir, 'infcx, 'tcx>, } impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, '_, 'tcx> { @@ -528,8 +528,8 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { } } -struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'tcx>, +struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> { + infcx: &'infcx BorrowckInferCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &'mir Body<'tcx>, move_data: &'a MoveData<'tcx>, @@ -596,7 +596,7 @@ struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> { /// Results of Polonius analysis. polonius_output: Option<Rc<PoloniusOutput>>, - diags: diags::BorrowckDiags<'tcx>, + diags: diags::BorrowckDiags<'infcx, 'tcx>, move_errors: Vec<MoveError<'tcx>>, } @@ -605,15 +605,15 @@ struct MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> - for MirBorrowckCtxt<'_, 'mir, '_, 'tcx> +impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> + for MirBorrowckCtxt<'a, 'mir, '_, 'tcx> { - type FlowState = Flows<'mir, 'tcx>; + type FlowState = Flows<'a, 'mir, 'tcx>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, stmt: &'mir Statement<'tcx>, location: Location, ) { @@ -683,7 +683,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, term: &'mir Terminator<'tcx>, loc: Location, ) { @@ -794,7 +794,7 @@ impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R> fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, term: &'mir Terminator<'tcx>, loc: Location, ) { @@ -988,7 +988,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { place_span: (Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { let (sd, rw) = kind; @@ -1038,7 +1038,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { place_span: (Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) -> bool { let mut error_reported = false; let borrow_set = Rc::clone(&self.borrow_set); @@ -1179,7 +1179,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { // Write of P[i] or *P requires P init'd. self.check_if_assigned_path_is_moved(location, place_span, flow_state); @@ -1197,7 +1197,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, (rvalue, span): (&'mir Rvalue<'tcx>, Span), - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { @@ -1455,7 +1455,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, (operand, span): (&'mir Operand<'tcx>, Span), - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { match *operand { Operand::Copy(place) => { @@ -1579,7 +1579,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, span: Span, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with @@ -1743,7 +1743,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1848,7 +1848,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1947,7 +1947,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { &mut self, location: Location, (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); @@ -2013,7 +2013,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { location: Location, base: PlaceRef<'tcx>, span: Span, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -2104,7 +2104,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { (place, span): (Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, location: Location, ) -> bool { debug!( @@ -2220,7 +2220,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { fn is_local_ever_initialized( &self, local: Local, - flow_state: &Flows<'mir, 'tcx>, + flow_state: &Flows<'_, 'mir, 'tcx>, ) -> Option<InitIndex> { let mpi = self.move_data.rev_lookup.find_local(local)?; let ii = &self.move_data.init_path_map[mpi]; @@ -2228,7 +2228,7 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> { } /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'mir, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'_, 'mir, 'tcx>) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being @@ -2428,12 +2428,12 @@ mod diags { use super::*; - enum BufferedDiag<'tcx> { - Error(Diag<'tcx>), - NonError(Diag<'tcx, ()>), + enum BufferedDiag<'infcx> { + Error(Diag<'infcx>), + NonError(Diag<'infcx, ()>), } - impl<'tcx> BufferedDiag<'tcx> { + impl<'infcx> BufferedDiag<'infcx> { fn sort_span(&self) -> Span { match self { BufferedDiag::Error(diag) => diag.sort_span, @@ -2442,7 +2442,7 @@ mod diags { } } - pub struct BorrowckDiags<'tcx> { + pub struct BorrowckDiags<'infcx, 'tcx> { /// This field keeps track of move errors that are to be reported for given move indices. /// /// There are situations where many errors can be reported for a single move out (see @@ -2457,15 +2457,15 @@ mod diags { /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary /// when errors in the map are being re-added to the error buffer so that errors with the /// same primary span come out in a consistent order. - buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'tcx>)>, + buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>, - buffered_mut_errors: FxIndexMap<Span, (Diag<'tcx>, usize)>, + buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>, /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics. - buffered_diags: Vec<BufferedDiag<'tcx>>, + buffered_diags: Vec<BufferedDiag<'infcx>>, } - impl<'tcx> BorrowckDiags<'tcx> { + impl<'infcx, 'tcx> BorrowckDiags<'infcx, 'tcx> { pub fn new() -> Self { BorrowckDiags { buffered_move_errors: BTreeMap::new(), @@ -2474,28 +2474,28 @@ mod diags { } } - pub fn buffer_error(&mut self, diag: Diag<'tcx>) { + pub fn buffer_error(&mut self, diag: Diag<'infcx>) { self.buffered_diags.push(BufferedDiag::Error(diag)); } - pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) { + pub fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) { self.buffered_diags.push(BufferedDiag::NonError(diag)); } } - impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { - pub fn buffer_error(&mut self, diag: Diag<'tcx>) { + impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { + pub fn buffer_error(&mut self, diag: Diag<'infcx>) { self.diags.buffer_error(diag); } - pub fn buffer_non_error(&mut self, diag: Diag<'tcx, ()>) { + pub fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) { self.diags.buffer_non_error(diag); } pub fn buffer_move_error( &mut self, move_out_indices: Vec<MoveOutIndex>, - place_and_err: (PlaceRef<'tcx>, Diag<'tcx>), + place_and_err: (PlaceRef<'tcx>, Diag<'infcx>), ) -> bool { if let Some((_, diag)) = self.diags.buffered_move_errors.insert(move_out_indices, place_and_err) @@ -2508,12 +2508,12 @@ mod diags { } } - pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'tcx>, usize)> { + pub fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> { // FIXME(#120456) - is `swap_remove` correct? self.diags.buffered_mut_errors.swap_remove(&span) } - pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'tcx>, count: usize) { + pub fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) { self.diags.buffered_mut_errors.insert(span, (diag, count)); } @@ -2554,7 +2554,7 @@ mod diags { pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, Diag<'tcx>)> { + ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> { self.diags.buffered_move_errors.get(move_out_indices) } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 923cf7e9405..2ffa9ba5b4d 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -81,7 +81,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( promoted: &IndexSlice<Promoted, Body<'tcx>>, location_table: &LocationTable, param_env: ty::ParamEnv<'tcx>, - flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, + flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'_, 'cx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, upvars: &[&ty::CapturedPlace<'tcx>], @@ -262,13 +262,13 @@ pub(super) fn dump_mir_results<'tcx>( #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] -pub(super) fn dump_annotation<'tcx>( - infcx: &BorrowckInferCtxt<'tcx>, +pub(super) fn dump_annotation<'tcx, 'cx>( + infcx: &'cx BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, - diags: &mut crate::diags::BorrowckDiags<'tcx>, + diags: &mut crate::diags::BorrowckDiags<'cx, 'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); @@ -285,7 +285,7 @@ pub(super) fn dump_annotation<'tcx>( let def_span = tcx.def_span(body.source.def_id()); let mut err = if let Some(closure_region_requirements) = closure_region_requirements { - let mut err = tcx.dcx().struct_span_note(def_span, "external requirements"); + let mut err = infcx.dcx().struct_span_note(def_span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -304,7 +304,7 @@ pub(super) fn dump_annotation<'tcx>( err } else { - let mut err = tcx.dcx().struct_span_note(def_span, "no external requirements"); + let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements"); regioncx.annotate(tcx, &mut err); err diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 67e5c8352df..e195ceded1b 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -285,7 +285,7 @@ impl<'tcx> InferCtxt<'tcx> { } if let Err(guar) = - check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) + check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span) { return Ty::new_error(self.tcx, guar); } @@ -294,6 +294,10 @@ impl<'tcx> InferCtxt<'tcx> { .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; + if let Err(e) = definition_ty.error_reported() { + return Ty::new_error(self.tcx, e); + } + // `definition_ty` does not live in of the current inference context, // so lets make sure that we don't accidentally misuse our current `infcx`. match check_opaque_type_well_formed( @@ -387,10 +391,11 @@ fn check_opaque_type_well_formed<'tcx>( /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html fn check_opaque_type_parameter_valid<'tcx>( - tcx: TyCtxt<'tcx>, + infcx: &InferCtxt<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, ) -> Result<(), ErrorGuaranteed> { + let tcx = infcx.tcx; let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); @@ -420,7 +425,7 @@ fn check_opaque_type_parameter_valid<'tcx>( opaque_env.param_is_error(i)?; - return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { + return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam { ty: arg, kind, span, @@ -438,7 +443,7 @@ fn check_opaque_type_parameter_valid<'tcx>( .collect(); #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] - return Err(tcx + return Err(infcx .dcx() .struct_span_err(span, "non-defining opaque type use in defining scope") .with_span_note(spans, format!("{descr} used multiple times")) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index b777e01f7a6..6d6425b5f19 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -34,7 +34,7 @@ pub(super) fn generate<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &Rc<DenseLocationMap>, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, move_data: &MoveData<'tcx>, ) { debug!("liveness::generate"); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 359c4ea0eb1..eb86c8d06f1 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -43,7 +43,7 @@ pub(super) fn trace<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, elements: &Rc<DenseLocationMap>, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec<Local>, boring_locals: Vec<Local>, @@ -101,7 +101,7 @@ pub(super) fn trace<'mir, 'tcx>( } /// Contextual state for the type-liveness coroutine. -struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { +struct LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx> { /// Current type-checker, giving us our inference context etc. typeck: &'me mut TypeChecker<'typeck, 'tcx>, @@ -119,7 +119,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { /// Results of dataflow tracking which variables (and paths) have been /// initialized. - flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'flow, 'tcx>>, + flow_inits: &'me mut ResultsCursor<'flow, 'tcx, MaybeInitializedPlaces<'a, 'flow, 'tcx>>, /// Index indicating where each variable is assigned, used, or /// dropped. @@ -131,8 +131,8 @@ struct DropData<'tcx> { region_constraint_data: Option<&'tcx QueryRegionConstraints<'tcx>>, } -struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { - cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>, +struct LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> { + cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>, /// Set of points that define the current local. defs: BitSet<PointIndex>, @@ -153,8 +153,8 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { stack: Vec<PointIndex>, } -impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { - fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self { +impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tcx> { + fn new(cx: LivenessContext<'a, 'me, 'typeck, 'flow, 'tcx>) -> Self { let num_points = cx.elements.num_points(); LivenessResults { cx, @@ -507,7 +507,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } -impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { +impl<'tcx> LivenessContext<'_, '_, '_, '_, 'tcx> { /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 81bde14a82f..aa25e3adf28 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -129,7 +129,7 @@ pub(crate) fn type_check<'mir, 'tcx>( location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option<AllFacts>, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc<DenseLocationMap>, upvars: &[&ty::CapturedPlace<'tcx>], diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index 25e1f6268e0..e2de6b8b4a9 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -45,10 +45,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { /// MIR visitor for collecting used mutable variables. /// The 'visit lifetime represents the duration of the MIR walk. -struct GatherUsedMutsVisitor<'visit, 'a, 'mir, 'cx, 'tcx> { +struct GatherUsedMutsVisitor<'visit, 'a, 'mir, 'infcx, 'tcx> { temporary_used_locals: FxIndexSet<Local>, never_initialized_mut_locals: &'visit mut FxIndexSet<Local>, - mbcx: &'visit mut MirBorrowckCtxt<'a, 'mir, 'cx, 'tcx>, + mbcx: &'visit mut MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx>, } impl GatherUsedMutsVisitor<'_, '_, '_, '_, '_> { diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml index b7063f35a3e..1ed6f8fc359 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml @@ -55,10 +55,6 @@ jobs: if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin' run: rustup set default-host x86_64-apple-darwin - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 1f5a6513f63..a2ae3d63fb9 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -66,6 +66,9 @@ jobs: env: TARGET_TRIPLE: aarch64-unknown-linux-gnu apt_deps: gcc-aarch64-linux-gnu qemu-user + - os: macos-latest + env: + TARGET_TRIPLE: aarch64-apple-darwin - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu @@ -108,10 +111,6 @@ jobs: sudo apt-get update sudo apt-get install -y ${{ matrix.apt_deps }} - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare @@ -214,6 +213,9 @@ jobs: - os: macos-latest env: TARGET_TRIPLE: x86_64-apple-darwin + - os: macos-latest + env: + TARGET_TRIPLE: aarch64-apple-darwin # cross-compile from Linux to Windows using mingw - os: ubuntu-latest env: @@ -248,10 +250,6 @@ jobs: sudo apt-get update sudo apt-get install -y gcc-mingw-w64-x86-64 - - name: Select XCode version - if: matrix.os == 'macos-latest' - run: sudo xcode-select -s /Applications/Xcode_14.3.1.app - - name: Prepare dependencies run: ./y.sh prepare @@ -282,7 +280,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 if: ${{ github.ref == 'refs/heads/master' }} - needs: [rustfmt, test, bench, dist] + # FIXME add the bench job back to the dependency list once rust-lang/rust#125493 gets merged + needs: [rustfmt, test, dist] permissions: contents: write # for creating the dev tag and release diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 33fe52ddbdd..15c9e9d66fa 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b27922a6879b5b5361d0a084cb0b1941bf109a98540addcb932da13b68bed4" +checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304c455b28bf56372729acb356afbb55d622f2b0f2f7837aa5e57c138acaac4d" +checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa" dependencies = [ "bumpalo", "cranelift-bforest", @@ -70,45 +70,46 @@ dependencies = [ "hashbrown 0.14.3", "log", "regalloc2", + "rustc-hash", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1653c56b99591d07f67c5ca7f9f25888948af3f4b97186bff838d687d666f613" +checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b6a9cf6b6eb820ee3f973a0db313c05dc12d370f37b4fe9630286e1672573f" +checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da" [[package]] name = "cranelift-control" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d06e6bf30075fb6bed9e034ec046475093392eea1aff90eb5c44c4a033d19a" +checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29be04f931b73cdb9694874a295027471817f26f26d2f0ebe5454153176b6e3a" +checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b" [[package]] name = "cranelift-frontend" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07fd7393041d7faa2f37426f5dc7fc04003b70988810e8c063beefeff1cd8f9" +checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5" dependencies = [ "cranelift-codegen", "log", @@ -118,15 +119,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f341d7938caa6dff8149dac05bb2b53fc680323826b83b4cf175ab9f5139a3c9" +checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e" [[package]] name = "cranelift-jit" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42733555e06433f1461570e09dbd756dafc228b4dac75c597cdbdc518de07522" +checksum = "f5c5cfb8bbd3339cd25cca30e7516ff8fe5cb1feeddde6980cc4d5ef34df97bb" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +145,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84950af02bb85f3da764d53a953b43bb29a732e793d4fe24637a61591be9a024" +checksum = "7c9b0d4269b36fd858e6d8f20cd4938941186fb831488c361888cb2d6b33a9a6" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +156,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82af6066e6448d26eeabb7aa26a43f7ff79f8217b06bade4ee6ef230aecc8880" +checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581" dependencies = [ "cranelift-codegen", "libc", @@ -166,9 +167,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.107.0" +version = "0.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00af56107039ed150391df6f753298c7b08f2b6a2e0727d216b5fa599d684d8b" +checksum = "19e33439ec20db058bc7cc3410f9748ab1ad90a35cef713d625c736f43e3820d" dependencies = [ "anyhow", "cranelift-codegen", @@ -278,9 +279,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "object" -version = "0.33.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "crc32fast", "hashbrown 0.14.3", @@ -410,10 +411,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "20.0.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9f93a3289057b26dc75eb84d6e60d7694f7d169c7c09597495de6e016a13ff" +checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91" dependencies = [ + "anyhow", "cfg-if", "libc", "windows-sys", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 2015cdbcc2a..2969a6cf6ec 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,15 +8,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.107.0", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.107.0" } -cranelift-module = { version = "0.107.0" } -cranelift-native = { version = "0.107.0" } -cranelift-jit = { version = "0.107.0", optional = true } -cranelift-object = { version = "0.107.0" } +cranelift-codegen = { version = "0.109.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.109.0" } +cranelift-module = { version = "0.109.0" } +cranelift-native = { version = "0.109.0" } +cranelift-jit = { version = "0.109.0", optional = true } +cranelift-object = { version = "0.109.0" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} -object = { version = "0.33", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" libloading = { version = "0.8.0", optional = true } diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 00ea15cb38c..eb21e027dd0 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |FreeBSD|✅[^no-rustup]|❓|❓|❓| |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| -|macOS|✅|❌[^apple-silicon]|N/A|N/A| +|macOS|✅|✅[^no-rustup]|N/A|N/A| |Windows|✅[^no-rustup]|❌|N/A|N/A| ✅: Fully supported and tested @@ -80,7 +80,6 @@ For more docs on how to build and test see [build_system/usage.txt](build_system Not all targets are available as rustup component for nightly. See notes in the platform support matrix. [^xcoff]: XCOFF object file format is not supported. -[^apple-silicon]: Tracked in [#1248](https://github.com/rust-lang/rustc_codegen_cranelift/issues/1248). [^no-rustup]: Not available as rustup component for nightly. You can build it yourself. ## Usage diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 196ff8fda75..dfbe0f51e7b 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -267,10 +267,6 @@ fn build_clif_sysroot_for_triple( prefix.to_str().unwrap() )); } - rustflags.push("-Zunstable-options".to_owned()); - for (name, values) in EXTRA_CHECK_CFGS { - rustflags.push(check_cfg_arg(name, *values)); - } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); if channel == "release" { @@ -330,34 +326,3 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> { Some(target_libs) } - -// Copied from https://github.com/rust-lang/rust/blob/4fd98a4b1b100f5329c6efae18031791f64372d2/src/bootstrap/src/utils/helpers.rs#L569-L585 -/// Create a `--check-cfg` argument invocation for a given name -/// and it's values. -fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { - // Creating a string of the values by concatenating each value: - // ',values("tvos","watchos")' or '' (nothing) when there are no values. - let next = match values { - Some(values) => { - let mut tmp = values.iter().flat_map(|val| [",", "\"", val, "\""]).collect::<String>(); - - tmp.insert_str(1, "values("); - tmp.push(')'); - tmp - } - None => "".to_string(), - }; - format!("--check-cfg=cfg({name}{next})") -} - -const EXTRA_CHECK_CFGS: &[(&str, Option<&[&str]>)] = &[ - ("bootstrap", None), - ("stdarch_intel_sde", None), - ("no_fp_fmt_parse", None), - ("no_global_oom_handling", None), - ("no_rc", None), - ("no_sync", None), - ("netbsd10", None), - ("backtrace_in_libstd", None), - ("target_arch", Some(&["xtensa"])), -]; diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 278f334796a..790d9cbd9fc 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -329,7 +329,6 @@ pub(crate) fn run_tests( struct TestRunner<'a> { is_native: bool, jit_supported: bool, - use_unstable_features: bool, skip_tests: &'a [&'a str], dirs: Dirs, target_compiler: Compiler, @@ -361,15 +360,7 @@ impl<'a> TestRunner<'a> { && target_compiler.triple.contains("x86_64") && !target_compiler.triple.contains("windows"); - Self { - is_native, - jit_supported, - use_unstable_features, - skip_tests, - dirs, - target_compiler, - stdlib_source, - } + Self { is_native, jit_supported, skip_tests, dirs, target_compiler, stdlib_source } } fn run_testsuite(&self, tests: &[TestCase]) { @@ -393,31 +384,13 @@ impl<'a> TestRunner<'a> { match *cmd { TestCaseCmd::Custom { func } => func(self), TestCaseCmd::BuildLib { source, crate_types } => { - if self.use_unstable_features { - self.run_rustc([source, "--crate-type", crate_types]); - } else { - self.run_rustc([ - source, - "--crate-type", - crate_types, - "--cfg", - "no_unstable_features", - ]); - } + self.run_rustc([source, "--crate-type", crate_types]); } TestCaseCmd::BuildBin { source } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } + self.run_rustc([source]); } TestCaseCmd::BuildBinAndRun { source, args } => { - if self.use_unstable_features { - self.run_rustc([source]); - } else { - self.run_rustc([source, "--cfg", "no_unstable_features"]); - } + self.run_rustc([source]); self.run_out_command( source.split('/').last().unwrap().split('.').next().unwrap(), args, @@ -472,7 +445,6 @@ impl<'a> TestRunner<'a> { cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); cmd.arg("-Zunstable-options"); - cmd.arg("--check-cfg=cfg(no_unstable_features)"); cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); cmd diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index aab20f67248..7d361a9ab2b 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -333,12 +333,7 @@ fn main() { #[cfg(all(not(jit), not(all(windows, target_env = "gnu"))))] test_tls(); - #[cfg(all( - not(jit), - not(no_unstable_features), - target_arch = "x86_64", - any(target_os = "linux", target_os = "macos") - ))] + #[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))] unsafe { global_asm_test(); naked_test(); @@ -367,17 +362,12 @@ fn stack_val_align() { assert_eq!(&a as *const Foo as usize % 8192, 0); } -#[cfg(all( - not(jit), - not(no_unstable_features), - target_arch = "x86_64", - any(target_os = "linux", target_os = "macos") -))] +#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "macos")))] extern "C" { fn global_asm_test(); } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "linux"))] +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))] global_asm! { " .global global_asm_test @@ -387,7 +377,7 @@ global_asm! { " } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64", target_os = "macos"))] +#[cfg(all(not(jit), target_arch = "x86_64", target_os = "macos"))] global_asm! { " .global _global_asm_test @@ -397,7 +387,7 @@ global_asm! { " } -#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64"))] +#[cfg(all(not(jit), target_arch = "x86_64"))] #[naked] extern "C" fn naked_test() { unsafe { diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 7347b2e7789..6cedd84adfe 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -251,6 +251,9 @@ unsafe fn test_simd() { test_mm_add_epi8(); test_mm_add_pd(); test_mm_cvtepi8_epi16(); + #[cfg(not(jit))] + test_mm_cvtps_epi32(); + test_mm_cvttps_epi32(); test_mm_cvtsi128_si64(); test_mm_extract_epi8(); @@ -476,6 +479,41 @@ unsafe fn test_mm256_permutevar8x32_epi32() { assert_eq_m256i(r, e); } +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +#[cfg(not(jit))] +unsafe fn test_mm_cvtps_epi32() { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvtps_epi32(float_vec); + + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [2, -2, i32::MIN, i32::MIN]; + + assert_eq!(ints, expected_ints); +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "avx2")] +unsafe fn test_mm_cvttps_epi32() { + let floats: [f32; 4] = [1.5, -2.5, i32::MAX as f32 + 1.0, f32::NAN]; + + let float_vec = _mm_loadu_ps(floats.as_ptr()); + let int_vec = _mm_cvttps_epi32(float_vec); + + let mut ints: [i32; 4] = [0; 4]; + _mm_storeu_si128(ints.as_mut_ptr() as *mut __m128i, int_vec); + + // this is very different from `floats.map(|f| f as i32)`! + let expected_ints: [i32; 4] = [1, -2, i32::MIN, i32::MIN]; + + assert_eq!(ints, expected_ints); +} + fn test_checked_mul() { let u: Option<u8> = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml index c8c7b45bc9a..9ea53e8f848 100644 --- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml +++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml @@ -4,12 +4,12 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.29.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -134,6 +134,17 @@ dependencies = [ ] [[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -147,9 +158,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -189,9 +200,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "compiler_builtins", "memchr", @@ -286,9 +297,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -396,8 +407,6 @@ dependencies = [ "core", "getopts", "libc", - "panic_abort", - "panic_unwind", "std", ] @@ -430,7 +439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.28.1", "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index a2ba79cbe90..cfa91744a0e 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-13" +channel = "nightly-2024-06-30" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 689cda21643..c1b7e4b0e07 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -36,9 +36,8 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic # exotic linkages -rm tests/ui/issues/issue-33992.rs # unsupported linkages -rm tests/incremental/hashes/function_interfaces.rs # same -rm tests/incremental/hashes/statics.rs # same +rm tests/incremental/hashes/function_interfaces.rs +rm tests/incremental/hashes/statics.rs # variadic arguments rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs @@ -60,13 +59,20 @@ rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported # requires LTO rm -r tests/run-make/cdylib -rm -r tests/run-make/issue-14500 -rm -r tests/run-make/issue-64153 rm -r tests/run-make/codegen-options-parsing rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 rm -r tests/run-make/issue-109934-lto-debuginfo rm -r tests/run-make/no-builtins-lto +rm -r tests/run-make/reachable-extern-fn-available-lto + +# coverage instrumentation +rm tests/ui/consts/precise-drop-with-coverage.rs +rm tests/ui/issues/issue-85461.rs +rm -r tests/ui/instrument-coverage/ + +# missing f16/f128 support +rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs # optimization tests # ================== @@ -74,6 +80,7 @@ rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same rm tests/ui/issues/issue-40883.rs # same rm -r tests/run-make/fmt-write-bloat/ # tests an optimization +rm tests/ui/statics/const_generics.rs # same # backend specific tests # ====================== @@ -85,6 +92,7 @@ rm -r tests/run-make/sepcomp-cci-copies # same rm -r tests/run-make/volatile-intrinsics # same rm -r tests/run-make/llvm-ident # same rm -r tests/run-make/no-builtins-attribute # same +rm -r tests/run-make/pgo-gen-no-imp-symbols # same rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific @@ -93,13 +101,14 @@ rm -r tests/run-make/print-to-output # requires --print relocation-models # requires asm, llvm-ir and/or llvm-bc emit support # ============================================= rm -r tests/run-make/emit-named-files -rm -r tests/run-make/issue-30063 rm -r tests/run-make/multiple-emits rm -r tests/run-make/output-type-permutations rm -r tests/run-make/emit-to-stdout rm -r tests/run-make/compressed-debuginfo rm -r tests/run-make/symbols-include-type-name - +rm -r tests/run-make/notify-all-emit-artifacts +rm -r tests/run-make/reset-codegen-1 +rm -r tests/run-make/inline-always-many-cgu # giving different but possibly correct results # ============================================= @@ -118,6 +127,7 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain # ============ rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort +rm tests/ui/deprecation/deprecated_inline_threshold.rs # missing deprecation warning for -Cinline-threshold # bugs in the test suite # ====================== @@ -148,12 +158,12 @@ index 9607ff02f96..b7d97caf9a2 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -34,8 +34,6 @@ pub fn bare() -> Self { - /// Construct a \`rustdoc\` invocation with \`-L \$(TARGET_RPATH_DIR)\` set. + #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); -- let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); +- let target_rpath_dir = env_var_os("TARGET_RPATH_DIR"); - cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); - Self { cmd, stdin: None } + Self { cmd } } EOF diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 695dbaf2804..0d7eee7afb4 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -5,8 +5,9 @@ mod pass_mode; mod returning; use std::borrow::Cow; +use std::mem; -use cranelift_codegen::ir::SigRef; +use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; @@ -17,7 +18,7 @@ use rustc_middle::ty::TypeVisitableExt; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::abi::call::{Conv, FnAbi}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::spec::abi::Abi; use self::pass_mode::*; @@ -487,6 +488,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let args = args; assert_eq!(fn_abi.args.len(), args.len()); + #[derive(Copy, Clone)] enum CallTarget { Direct(FuncRef), Indirect(SigRef, Value), @@ -532,7 +534,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( }; self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| { - let call_args = return_ptr + let mut call_args = return_ptr .into_iter() .chain(first_arg_override.into_iter()) .chain( @@ -545,47 +547,118 @@ pub(crate) fn codegen_terminator_call<'tcx>( ) .collect::<Vec<Value>>(); - let call_inst = match func_ref { + // FIXME: Find a cleaner way to support varargs. + if fn_abi.c_variadic { + adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); + } + + match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) } + } + }); + + if let Some(dest) = target { + let ret_block = fx.get_block(dest); + fx.bcx.ins().jump(ret_block, &[]); + } else { + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + } + + fn adjust_call_for_c_variadic<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + source_info: mir::SourceInfo, + target: CallTarget, + call_args: &mut Vec<Value>, + ) { + if fn_abi.conv != Conv::C { + fx.tcx.dcx().span_fatal( + source_info.span, + format!("Variadic call for non-C abi {:?}", fn_abi.conv), + ); + } + let sig_ref = match target { + CallTarget::Direct(func_ref) => fx.bcx.func.dfg.ext_funcs[func_ref].signature, + CallTarget::Indirect(sig_ref, _) => sig_ref, }; + // `mem::take()` the `params` so that `fx.bcx` can be used below. + let mut abi_params = mem::take(&mut fx.bcx.func.dfg.signatures[sig_ref].params); + + // Recalculate the parameters in the signature to ensure the signature contains the variadic arguments. + let has_return_arg = matches!(fn_abi.ret.mode, PassMode::Indirect { .. }); + // Drop everything except the return argument (if there is one). + abi_params.truncate(if has_return_arg { 1 } else { 0 }); + // Add the fixed arguments. + abi_params.extend( + fn_abi.args[..fn_abi.fixed_count as usize] + .iter() + .flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()), + ); + let fixed_arg_count = abi_params.len(); + // Add the variadic arguments. + abi_params.extend( + fn_abi.args[fn_abi.fixed_count as usize..] + .iter() + .flat_map(|arg_abi| arg_abi.get_abi_param(fx.tcx).into_iter()), + ); - // FIXME find a cleaner way to support varargs - if fn_sig.c_variadic() { - if !matches!(fn_sig.abi(), Abi::C { .. }) { + if fx.tcx.sess.target.is_like_osx && fx.tcx.sess.target.arch == "aarch64" { + // Add any padding arguments needed for Apple AArch64. + // There's no need to pad the argument list unless variadic arguments are actually being + // passed. + if abi_params.len() > fixed_arg_count { + // 128-bit integers take 2 registers, and everything else takes 1. + // FIXME: Add support for non-integer types + // This relies on the checks below to ensure all arguments are integer types and + // that the ABI is "C". + // The return argument isn't counted as it goes in its own dedicated register. + let integer_registers_used: usize = abi_params + [if has_return_arg { 1 } else { 0 }..fixed_arg_count] + .iter() + .map(|arg| if arg.value_type.bits() == 128 { 2 } else { 1 }) + .sum(); + // The ABI uses 8 registers before it starts pushing arguments to the stack. Pad out + // the registers if needed to ensure the variadic arguments are passed on the stack. + if integer_registers_used < 8 { + abi_params.splice( + fixed_arg_count..fixed_arg_count, + (integer_registers_used..8).map(|_| AbiParam::new(types::I64)), + ); + call_args.splice( + fixed_arg_count..fixed_arg_count, + (integer_registers_used..8).map(|_| fx.bcx.ins().iconst(types::I64, 0)), + ); + } + } + + // `StructArgument` is not currently used by the `aarch64` ABI, and is therefore not + // handled when calculating how many padding arguments to use. Assert that this remains + // the case. + assert!(abi_params.iter().all(|param| matches!( + param.purpose, + // The only purposes used are `Normal` and `StructReturn`. + ArgumentPurpose::Normal | ArgumentPurpose::StructReturn + ))); + } + + // Check all parameters are integers. + for param in abi_params.iter() { + if !param.value_type.is_int() { + // FIXME: Set %al to upperbound on float args once floats are supported. fx.tcx.dcx().span_fatal( source_info.span, - format!("Variadic call for non-C abi {:?}", fn_sig.abi()), + format!("Non int ty {:?} for variadic call", param.value_type), ); } - let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap(); - let abi_params = call_args - .into_iter() - .map(|arg| { - let ty = fx.bcx.func.dfg.value_type(arg); - if !ty.is_int() { - // FIXME set %al to upperbound on float args once floats are supported - fx.tcx.dcx().span_fatal( - source_info.span, - format!("Non int ty {:?} for variadic call", ty), - ); - } - AbiParam::new(ty) - }) - .collect::<Vec<AbiParam>>(); - fx.bcx.func.dfg.signatures[sig_ref].params = abi_params; } - call_inst - }); + assert_eq!(abi_params.len(), call_args.len()); - if let Some(dest) = target { - let ret_block = fx.get_block(dest); - fx.bcx.ins().jump(ret_block, &[]); - } else { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + // Put the `AbiParam`s back in the signature. + fx.bcx.func.dfg.signatures[sig_ref].params = abi_params; } } diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index e8af3e8c255..b4a3825e996 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -11,15 +11,10 @@ use rustc_session::config::OomStrategy; use crate::prelude::*; /// Returns whether an allocator shim was created -pub(crate) fn codegen( - tcx: TyCtxt<'_>, - module: &mut impl Module, - unwind_context: &mut UnwindContext, -) -> bool { +pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; codegen_inner( module, - unwind_context, kind, tcx.alloc_error_handler_kind(()).unwrap(), tcx.sess.opts.unstable_opts.oom, @@ -28,8 +23,7 @@ pub(crate) fn codegen( } fn codegen_inner( - module: &mut impl Module, - unwind_context: &mut UnwindContext, + module: &mut dyn Module, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, oom_strategy: OomStrategy, @@ -67,7 +61,6 @@ fn codegen_inner( }; crate::common::create_wrapper_function( module, - unwind_context, sig, &global_fn_name(method.name), &default_fn_name(method.name), @@ -82,7 +75,6 @@ fn codegen_inner( }; crate::common::create_wrapper_function( module, - unwind_context, sig, "__rust_alloc_error_handler", &alloc_error_handler_name(alloc_error_handler_kind), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index b117dc496c2..c5b4277015a 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -249,9 +249,7 @@ pub(crate) fn compile_fn( } // Define debuginfo for function - let isa = module.isa(); let debug_context = &mut cx.debug_context; - let unwind_context = &mut cx.unwind_context; cx.profiler.generic_activity("generate debug info").run(|| { if let Some(debug_context) = debug_context { codegened_func.func_debug_cx.unwrap().finalize( @@ -260,7 +258,6 @@ pub(crate) fn compile_fn( context, ); } - unwind_context.add_function(codegened_func.func_id, &context, isa); }); } @@ -909,7 +906,7 @@ fn codegen_stmt<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::AscribeUserType(..) => {} - StatementKind::Coverage { .. } => fx.tcx.dcx().fatal("-Zcoverage is unimplemented"), + StatementKind::Coverage { .. } => unreachable!(), StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic { // We ignore `assume` intrinsics, they are only useful for optimizations NonDivergingIntrinsic::Assume(_) => {} diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 21d0cd2d30f..09317139936 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -247,7 +247,6 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool { pub(crate) fn create_wrapper_function( module: &mut dyn Module, - unwind_context: &mut UnwindContext, sig: Signature, wrapper_name: &str, callee_name: &str, @@ -280,7 +279,6 @@ pub(crate) fn create_wrapper_function( bcx.finalize(); } module.define_function(wrapper_func_id, &mut ctx).unwrap(); - unwind_context.add_function(wrapper_func_id, &ctx, module.isa()); } pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { @@ -395,6 +393,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { // FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets // a way to specify stack slot alignment. size: (size + abi_align - 1) / abi_align * abi_align, + align_shift: 4, }); Pointer::stack_slot(stack_slot) } else { @@ -405,6 +404,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { // FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets // a way to specify stack slot alignment. size: (size + align) / abi_align * abi_align, + align_shift: 4, }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align)); diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index dcafac21bc7..763d9a48407 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -26,6 +26,7 @@ use rustc_session::Session; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; use crate::global_asm::GlobalAsmConfig; +use crate::unwind_module::UnwindModule; use crate::{prelude::*, BackendConfig}; struct ModuleCodegenResult { @@ -318,7 +319,11 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule { +fn make_module( + sess: &Session, + backend_config: &BackendConfig, + name: String, +) -> UnwindModule<ObjectModule> { let isa = crate::build_isa(sess, backend_config); let mut builder = @@ -327,16 +332,15 @@ fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections // can easily double the amount of time necessary to perform linking. builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) + UnwindModule::new(ObjectModule::new(builder), true) } fn emit_cgu( output_filenames: &OutputFilenames, prof: &SelfProfilerRef, name: String, - module: ObjectModule, + module: UnwindModule<ObjectModule>, debug: Option<DebugContext>, - unwind_context: UnwindContext, global_asm_object_file: Option<PathBuf>, producer: &str, ) -> Result<ModuleCodegenResult, String> { @@ -346,8 +350,6 @@ fn emit_cgu( debug.emit(&mut product); } - unwind_context.emit(&mut product); - let module_regular = emit_module( output_filenames, prof, @@ -494,7 +496,6 @@ fn module_codegen( let mut cx = crate::CodegenCx::new( tcx, - backend_config.clone(), module.isa(), tcx.sess.opts.debuginfo != DebugInfo::None, cgu_name, @@ -531,13 +532,7 @@ fn module_codegen( } } } - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut module, - &mut cx.unwind_context, - false, - cgu.is_primary(), - ); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, false, cgu.is_primary()); let cgu_name = cgu.name().as_str().to_owned(); @@ -571,7 +566,6 @@ fn module_codegen( cgu_name, module, cx.debug_context, - cx.unwind_context, global_asm_object_file, &producer, ) @@ -665,13 +659,10 @@ pub(crate) fn run_aot( }); let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string()); - let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); - let created_alloc_shim = - crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); + let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); let allocator_module = if created_alloc_shim { - let mut product = allocator_module.finish(); - allocator_unwind_context.emit(&mut product); + let product = allocator_module.finish(); match emit_module( tcx.output_filenames(()), diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 4b149131b61..dfee8e714e6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -14,12 +14,12 @@ use rustc_session::Session; use rustc_span::Symbol; use crate::debuginfo::TypeDebugContext; +use crate::unwind_module::UnwindModule; use crate::{prelude::*, BackendConfig}; use crate::{CodegenCx, CodegenMode}; struct JitState { - backend_config: BackendConfig, - jit_module: JITModule, + jit_module: UnwindModule<JITModule>, } thread_local! { @@ -63,7 +63,7 @@ fn create_jit_module( tcx: TyCtxt<'_>, backend_config: &BackendConfig, hotswap: bool, -) -> (JITModule, CodegenCx) { +) -> (UnwindModule<JITModule>, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); let isa = crate::build_isa(tcx.sess, backend_config); @@ -72,17 +72,11 @@ fn create_jit_module( crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); - let mut jit_module = JITModule::new(jit_builder); + let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); - let mut cx = crate::CodegenCx::new( - tcx, - backend_config.clone(), - jit_module.isa(), - false, - Symbol::intern("dummy_cgu_name"), - ); + let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, Symbol::intern("dummy_cgu_name")); - crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context); + crate::allocator::codegen(tcx, &mut jit_module); (jit_module, cx) } @@ -128,7 +122,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { ); } CodegenMode::JitLazy => { - codegen_shim(tcx, &mut cx, &mut cached_context, &mut jit_module, inst) + codegen_shim(tcx, &mut cached_context, &mut jit_module, inst) } }, MonoItem::Static(def_id) => { @@ -146,18 +140,11 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { tcx.dcx().fatal("Inline asm is not supported in JIT mode"); } - crate::main_shim::maybe_create_entry_wrapper( - tcx, - &mut jit_module, - &mut cx.unwind_context, - true, - true, - ); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, true, true); tcx.dcx().abort_if_errors(); - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; + jit_module.finalize_definitions(); println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" @@ -177,12 +164,12 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { call_conv: jit_module.target_config().default_call_conv, }; let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); - let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); + let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); LAZY_JIT_STATE.with(|lazy_jit_state| { let mut lazy_jit_state = lazy_jit_state.borrow_mut(); assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { backend_config, jit_module }); + *lazy_jit_state = Some(JitState { jit_module }); }); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = @@ -268,7 +255,6 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> let mut lazy_jit_state = lazy_jit_state.borrow_mut(); let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); let jit_module = &mut lazy_jit_state.jit_module; - let backend_config = lazy_jit_state.backend_config.clone(); let name = tcx.symbol_name(instance).name; let sig = crate::abi::get_function_sig( @@ -278,7 +264,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> ); let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); - let current_ptr = jit_module.read_got_entry(func_id); + let current_ptr = jit_module.module.read_got_entry(func_id); // If the function's GOT entry has already been updated to point at something other // than the shim trampoline, don't re-jit but just return the new pointer instead. @@ -288,11 +274,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> return current_ptr; } - jit_module.prepare_for_function_redefine(func_id).unwrap(); + jit_module.module.prepare_for_function_redefine(func_id).unwrap(); let mut cx = crate::CodegenCx::new( tcx, - backend_config, jit_module.isa(), false, Symbol::intern("dummy_cgu_name"), @@ -300,9 +285,8 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); assert!(cx.global_asm.is_empty()); - jit_module.finalize_definitions().unwrap(); - unsafe { cx.unwind_context.register_jit(&jit_module) }; - jit_module.get_finalized_function(func_id) + jit_module.finalize_definitions(); + jit_module.module.get_finalized_function(func_id) }) }) } @@ -310,7 +294,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> fn dep_symbol_lookup_fn( sess: &Session, crate_info: CrateInfo, -) -> Box<dyn Fn(&str) -> Option<*const u8>> { +) -> Box<dyn Fn(&str) -> Option<*const u8> + Send> { use rustc_middle::middle::dependency_format::Linkage; let mut dylib_paths = Vec::new(); @@ -362,9 +346,8 @@ fn dep_symbol_lookup_fn( fn codegen_shim<'tcx>( tcx: TyCtxt<'tcx>, - cx: &mut CodegenCx, cached_context: &mut Context, - module: &mut JITModule, + module: &mut UnwindModule<JITModule>, inst: Instance<'tcx>, ) { let pointer_type = module.target_config().pointer_type(); @@ -413,5 +396,4 @@ fn codegen_shim<'tcx>( trampoline_builder.ins().return_(&ret_vals); module.define_function(func_id, context).unwrap(); - cx.unwind_context.add_function(func_id, context, module.isa()); } diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index c6b26dd873b..c88230c9360 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -113,13 +113,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( ); let sig = get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); - create_wrapper_function( - fx.module, - &mut fx.cx.unwind_context, - sig, - &wrapper_name, - symbol.name, - ); + create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); CInlineAsmOperand::Symbol { symbol: wrapper_name } } else { @@ -283,13 +277,7 @@ pub(crate) fn codegen_naked_asm<'tcx>( ); let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); - create_wrapper_function( - module, - &mut cx.unwind_context, - sig, - &wrapper_name, - symbol.name, - ); + create_wrapper_function(module, sig, &wrapper_name, symbol.name); CInlineAsmOperand::Symbol { symbol: wrapper_name } } else { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index d454f3c1de7..399518e58d8 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -459,11 +459,20 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (a); intrinsic); let a = a.load_scalar(fx); + let value = fx.bcx.ins().x86_cvtt2dq(types::I32X4, a); + let cvalue = CValue::by_val(value, ret.layout()); + ret.write_cvalue(fx, cvalue); + } + "llvm.x86.sse2.cvtps2dq" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_epi32 + intrinsic_args!(fx, args => (a); intrinsic); + let a = a.load_scalar(fx); + // Using inline asm instead of fcvt_to_sint_sat as unrepresentable values are turned // into 0x80000000 for which Cranelift doesn't have a native instruction. codegen_inline_asm_inner( fx, - &[InlineAsmTemplatePiece::String(format!("cvttps2dq xmm0, xmm0"))], + &[InlineAsmTemplatePiece::String(format!("cvtps2dq xmm0, xmm0"))], &[CInlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), _late: true, @@ -1416,6 +1425,36 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.write_cvalue(fx, res); } + "llvm.x86.rdtsc" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_rdtsc&ig_expand=5273 + + let res_place = CPlace::new_stack_slot( + fx, + fx.layout_of(Ty::new_tup(fx.tcx, &[fx.tcx.types.u32, fx.tcx.types.u32])), + ); + let eax_place = res_place.place_field(fx, FieldIdx::new(0)); + let edx_place = res_place.place_field(fx, FieldIdx::new(1)); + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("rdtsc".to_string())], + &[ + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + late: true, + place: Some(eax_place), + }, + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + late: true, + place: Some(edx_place), + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::NOMEM, + ); + let res = res_place.to_cvalue(fx); + ret.write_cvalue_transmute(fx, res); + } + _ => { fx.tcx .dcx() diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 06ca52b3903..192e6c91ea3 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -79,6 +79,7 @@ mod pretty_clif; mod toolchain; mod trap; mod unsize; +mod unwind_module; mod value_and_place; mod vtable; @@ -130,22 +131,13 @@ struct CodegenCx { global_asm: String, inline_asm_index: Cell<usize>, debug_context: Option<DebugContext>, - unwind_context: UnwindContext, cgu_name: Symbol, } impl CodegenCx { - fn new( - tcx: TyCtxt<'_>, - backend_config: BackendConfig, - isa: &dyn TargetIsa, - debug_info: bool, - cgu_name: Symbol, - ) -> Self { + fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, debug_info: bool, cgu_name: Symbol) -> Self { assert_eq!(pointer_ty(tcx), isa.pointer_type()); - let unwind_context = - UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { Some(DebugContext::new(tcx, isa, cgu_name.as_str())) } else { @@ -158,7 +150,6 @@ impl CodegenCx { global_asm: String::new(), inline_asm_index: Cell::new(0), debug_context, - unwind_context, cgu_name, } } @@ -175,7 +166,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } fn init(&self, sess: &Session) { - use rustc_session::config::Lto; + use rustc_session::config::{InstrumentCoverage, Lto}; match sess.lto() { Lto::No | Lto::ThinLocal => {} Lto::Thin | Lto::Fat => { @@ -183,6 +174,11 @@ impl CodegenBackend for CraneliftCodegenBackend { } } + if sess.opts.cg.instrument_coverage() != InstrumentCoverage::No { + sess.dcx() + .fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift"); + } + let mut config = self.config.borrow_mut(); if config.is_none() { let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args) diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index f9a729618a5..33d3f9b8a90 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -11,8 +11,7 @@ use crate::prelude::*; /// users main function. pub(crate) fn maybe_create_entry_wrapper( tcx: TyCtxt<'_>, - module: &mut impl Module, - unwind_context: &mut UnwindContext, + module: &mut dyn Module, is_jit: bool, is_primary_cgu: bool, ) { @@ -36,12 +35,11 @@ pub(crate) fn maybe_create_entry_wrapper( return; } - create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe); + create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe); fn create_entry_fn( tcx: TyCtxt<'_>, - m: &mut impl Module, - unwind_context: &mut UnwindContext, + m: &mut dyn Module, rust_main_def_id: DefId, ignore_lang_start_wrapper: bool, is_main_fn: bool, @@ -170,7 +168,5 @@ pub(crate) fn maybe_create_entry_wrapper( if let Err(err) = m.define_function(cmain_func_id, &mut ctx) { tcx.dcx().fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}")); } - - unwind_context.add_function(cmain_func_id, &ctx, m.isa()); } } diff --git a/compiler/rustc_codegen_cranelift/src/unwind_module.rs b/compiler/rustc_codegen_cranelift/src/unwind_module.rs new file mode 100644 index 00000000000..b950aaa29ce --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/unwind_module.rs @@ -0,0 +1,115 @@ +use cranelift_codegen::control::ControlPlane; +use cranelift_codegen::ir::{Function, Signature}; +use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa}; +use cranelift_codegen::{Context, FinalizedMachReloc}; +use cranelift_module::{ + DataDescription, DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations, + ModuleResult, +}; +use cranelift_object::{ObjectModule, ObjectProduct}; + +use crate::UnwindContext; + +/// A wrapper around a [Module] which adds any defined function to the [UnwindContext]. +pub(crate) struct UnwindModule<T> { + pub(crate) module: T, + unwind_context: UnwindContext, +} + +impl<T: Module> UnwindModule<T> { + pub(crate) fn new(module: T, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(module.isa(), pic_eh_frame); + UnwindModule { module, unwind_context } + } +} + +impl UnwindModule<ObjectModule> { + pub(crate) fn finish(self) -> ObjectProduct { + let mut product = self.module.finish(); + self.unwind_context.emit(&mut product); + product + } +} + +#[cfg(feature = "jit")] +impl UnwindModule<cranelift_jit::JITModule> { + pub(crate) fn finalize_definitions(&mut self) { + self.module.finalize_definitions().unwrap(); + let prev_unwind_context = std::mem::replace( + &mut self.unwind_context, + UnwindContext::new(self.module.isa(), false), + ); + unsafe { prev_unwind_context.register_jit(&self.module) }; + } +} + +impl<T: Module> Module for UnwindModule<T> { + fn isa(&self) -> &dyn TargetIsa { + self.module.isa() + } + + fn declarations(&self) -> &ModuleDeclarations { + self.module.declarations() + } + + fn get_name(&self, name: &str) -> Option<FuncOrDataId> { + self.module.get_name(name) + } + + fn target_config(&self) -> TargetFrontendConfig { + self.module.target_config() + } + + fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &Signature, + ) -> ModuleResult<FuncId> { + self.module.declare_function(name, linkage, signature) + } + + fn declare_anonymous_function(&mut self, signature: &Signature) -> ModuleResult<FuncId> { + self.module.declare_anonymous_function(signature) + } + + fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + tls: bool, + ) -> ModuleResult<DataId> { + self.module.declare_data(name, linkage, writable, tls) + } + + fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> { + self.module.declare_anonymous_data(writable, tls) + } + + fn define_function_with_control_plane( + &mut self, + func: FuncId, + ctx: &mut Context, + ctrl_plane: &mut ControlPlane, + ) -> ModuleResult<()> { + self.module.define_function_with_control_plane(func, ctx, ctrl_plane)?; + self.unwind_context.add_function(func, ctx, self.module.isa()); + Ok(()) + } + + fn define_function_bytes( + &mut self, + _func_id: FuncId, + _func: &Function, + _alignment: u64, + _bytes: &[u8], + _relocs: &[FinalizedMachReloc], + ) -> ModuleResult<()> { + unimplemented!() + } + + fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> { + self.module.define_data(data_id, data) + } +} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 548c23cc794..230fe4f5871 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -28,6 +28,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global // TODO(antoyo): set linkage. } + + pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } } pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { @@ -239,19 +252,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { self.context .new_array_access(None, base_addr, self.const_usize(offset.bytes())) diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 4a1f5188a80..6231b09552c 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -27,7 +27,6 @@ use crate::callee::get_fn; use crate::common::SignType; pub struct CodegenCx<'gcc, 'tcx> { - pub check_overflow: bool, pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, @@ -134,8 +133,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { tcx: TyCtxt<'tcx>, supports_128bit_integers: bool, ) -> Self { - let check_overflow = tcx.sess.overflow_checks(); - let create_type = |ctype, rust_type| { let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap(); let align = layout.align.abi.bytes(); @@ -271,7 +268,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } let mut cx = Self { - check_overflow, codegen_unit, context, current_func: RefCell::new(None), @@ -511,10 +507,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 68471b028be..4caff2e6310 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -89,13 +89,34 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { ty::FloatTy::F128 => self.type_f128(), } } -} -impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn type_i1(&self) -> Type<'gcc> { + pub fn type_i1(&self) -> Type<'gcc> { self.bool_type } + pub fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { + let types = fields.to_vec(); + if let Some(typ) = self.struct_types.borrow().get(fields) { + return *typ; + } + let fields: Vec<_> = fields + .iter() + .enumerate() + .map(|(index, field)| { + self.context.new_field(None, *field, format!("field{}_TODO", index)) + }) + .collect(); + let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); + if packed { + #[cfg(feature = "master")] + typ.set_packed(); + } + self.struct_types.borrow_mut().insert(types, typ); + typ + } +} + +impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } @@ -131,7 +152,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f64(&self) -> Type<'gcc> { self.double_type } - + fn type_f128(&self) -> Type<'gcc> { unimplemented!("f16_f128") } @@ -140,27 +161,6 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.context.new_function_pointer_type(None, return_type, params, false) } - fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { - let types = fields.to_vec(); - if let Some(typ) = self.struct_types.borrow().get(fields) { - return *typ; - } - let fields: Vec<_> = fields - .iter() - .enumerate() - .map(|(index, field)| { - self.context.new_field(None, *field, format!("field{}_TODO", index)) - }) - .collect(); - let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); - if packed { - #[cfg(feature = "master")] - typ.set_packed(); - } - self.struct_types.borrow_mut().insert(types, typ); - typ - } - fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { if self.is_int_type_or_bool(typ) { TypeKind::Integer diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 4ffc92eb633..d42c6ed827a 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -329,10 +329,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { const_alloc_to_llvm(self, alloc, /*static*/ false) } - fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { - self.const_bitcast(val, ty) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { llvm::LLVMConstInBoundsGEP2( diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 7d92888feee..1a8e8efdae5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -3,6 +3,7 @@ use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::coverageinfo; use crate::debuginfo; +use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm; use crate::llvm_util; use crate::type_::Type; @@ -43,7 +44,6 @@ use std::str; /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. pub struct CodegenCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, - pub check_overflow: bool, pub use_dll_storage_attrs: bool, pub tls_model: llvm::ThreadLocalMode, @@ -441,8 +441,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { // start) and then strongly recommending static linkage on Windows! let use_dll_storage_attrs = tcx.sess.target.is_like_windows; - let check_overflow = tcx.sess.overflow_checks(); - let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); @@ -466,7 +464,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { CodegenCx { tcx, - check_overflow, use_dll_storage_attrs, tls_model, llmod, @@ -522,6 +519,15 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { &self.vtables } + fn apply_vcall_visibility_metadata( + &self, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + vtable: &'ll Value, + ) { + apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable); + } + fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value { get_fn(self, instance) } @@ -596,10 +602,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 8de4e0effad..742bfd76590 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1449,12 +1449,18 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } -fn vcall_visibility_metadata<'ll, 'tcx>( +pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, trait_ref: Option<PolyExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { + // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in + // LLVM at the moment. + if !cx.sess().opts.unstable_opts.virtual_function_elimination || cx.sess().lto() != Lto::Fat { + return; + } + enum VCallVisibility { Public = 0, LinkageUnit = 1, @@ -1531,12 +1537,6 @@ pub fn create_vtable_di_node<'ll, 'tcx>( poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { - // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in - // LLVM at the moment. - if cx.sess().opts.unstable_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat { - vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable); - } - if cx.dbg_cx.is_none() { return; } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4b7a2643007..ed0989a0ba4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -274,10 +274,11 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { + fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { + use std::fmt::Write; match req.kind { PrintKind::RelocationModels => { - writeln!(out, "Available relocation models:"); + writeln!(out, "Available relocation models:").unwrap(); for name in &[ "static", "pic", @@ -288,25 +289,25 @@ impl CodegenBackend for LlvmCodegenBackend { "ropi-rwpi", "default", ] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::CodeModels => { - writeln!(out, "Available code models:"); + writeln!(out, "Available code models:").unwrap(); for name in &["tiny", "small", "kernel", "medium", "large"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::TlsModels => { - writeln!(out, "Available TLS models:"); + writeln!(out, "Available TLS models:").unwrap(); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::StackProtectorStrategies => { writeln!( @@ -332,7 +333,8 @@ impl CodegenBackend for LlvmCodegenBackend { none Do not generate stack canaries. "# - ); + ) + .unwrap(); } _other => llvm_util::print(req, out, sess), } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 7e0f264a4ae..0e89e66be49 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,7 +6,6 @@ use crate::errors::{ use crate::llvm; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; -use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; @@ -18,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use std::ffi::{c_char, c_void, CStr, CString}; +use std::fmt::Write; use std::path::Path; use std::ptr; use std::slice; @@ -372,7 +372,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { ret } -fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) { +fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMachine) { let mut llvm_target_features = llvm_target_features(tm); let mut known_llvm_target_features = FxHashSet::<&'static str>::default(); let mut rustc_target_features = sess @@ -412,24 +412,26 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll .max() .unwrap_or(0); - writeln!(out, "Features supported by rustc for this target:"); + writeln!(out, "Features supported by rustc for this target:").unwrap(); for (feature, desc) in &rustc_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } - writeln!(out, "\nCode-generation features supported by LLVM for this target:"); + writeln!(out, "\nCode-generation features supported by LLVM for this target:").unwrap(); for (feature, desc) in &llvm_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } if llvm_target_features.is_empty() { - writeln!(out, " Target features listing is not supported by this LLVM version."); + writeln!(out, " Target features listing is not supported by this LLVM version.") + .unwrap(); } - writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it."); - writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); - writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],"); - writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); + writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.").unwrap(); + writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n") + .unwrap(); + writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],").unwrap(); + writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n").unwrap(); } -pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req.kind { @@ -440,9 +442,9 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { - let out = &mut *(out as *mut &mut dyn PrintBackendInfo); + let out = &mut *(out as *mut &mut String); let bytes = slice::from_raw_parts(string as *const u8, len); - write!(out, "{}", String::from_utf8_lossy(bytes)); + write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); } unsafe { llvm::LLVMRustPrintTargetCPUs( diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index a00f09dc40d..f1141c57ced 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -127,13 +127,24 @@ impl<'ll> CodegenCx<'ll, '_> { pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } -} -impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn type_i1(&self) -> &'ll Type { + pub(crate) fn type_i1(&self) -> &'ll Type { unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } } + pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { + unsafe { + llvm::LLVMStructTypeInContext( + self.llcx, + els.as_ptr(), + els.len() as c_uint, + packed as Bool, + ) + } + } +} + +impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i8(&self) -> &'ll Type { unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } } @@ -178,17 +189,6 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) } } - fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { - unsafe { - llvm::LLVMStructTypeInContext( - self.llcx, - els.as_ptr(), - els.len() as c_uint, - packed as Bool, - ) - } - } - fn type_kind(&self, ty: &'ll Type) -> TypeKind { unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d509e4ce56d..da4fa41e2aa 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::collections::BTreeSet; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -1306,12 +1306,12 @@ fn link_sanitizer_runtime( let filename = format!("rustc{channel}_rt.{name}"); let path = find_sanitizer_runtime(sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); - linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); + linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib_by_name(&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"); + linker.link_arg("/INFERASANLIBS"); } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); @@ -1888,9 +1888,9 @@ fn add_post_link_objects( /// FIXME: Determine where exactly these args need to be inserted. fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.pre_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } - cmd.args(&sess.opts.unstable_opts.pre_link_args); + cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args); } /// Add a link script embedded in the target, if applicable. @@ -1908,8 +1908,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error }); } - cmd.arg("--script"); - cmd.arg(path); + cmd.link_arg("--script").link_arg(path); } _ => {} } @@ -1918,7 +1917,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty /// Add arbitrary "user defined" args defined from command line. /// FIXME: Determine where exactly these args need to be inserted. fn add_user_defined_link_args(cmd: &mut dyn Linker, sess: &Session) { - cmd.args(&sess.opts.cg.link_args); + cmd.verbatim_args(&sess.opts.cg.link_args); } /// Add arbitrary "late link" args defined by the target spec. @@ -1936,15 +1935,15 @@ fn add_late_link_args( }); if any_dynamic_crate { if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } else { if let Some(args) = sess.target.late_link_args_static.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } if let Some(args) = sess.target.late_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -1952,7 +1951,7 @@ fn add_late_link_args( /// FIXME: Determine where exactly these args need to be inserted. fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.post_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -2097,6 +2096,10 @@ fn add_rpath_args( codegen_results: &CodegenResults, out_filename: &Path, ) { + if !sess.target.has_rpath { + return; + } + // FIXME (#2397): At some point we want to rpath our guesses as to // where extern libraries might live, based on the // add_lib_search_paths @@ -2115,11 +2118,10 @@ fn add_rpath_args( let rpath_config = RPathConfig { libs: &*libs, out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.has_rpath, is_like_osx: sess.target.is_like_osx, linker_is_gnu: sess.target.linker_flavor.is_gnu(), }; - cmd.args(&rpath::get_rpath_flags(&rpath_config)); + cmd.cc_args(&rpath::get_rpath_flags(&rpath_config)); } } @@ -2378,7 +2380,7 @@ fn add_order_independent_options( } else { "" }; - cmd.arg(format!("--dynamic-linker={prefix}ld.so.1")); + cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1")); } if sess.target.eh_frame_header { @@ -2393,8 +2395,7 @@ fn add_order_independent_options( } if sess.target.os == "emscripten" { - cmd.arg("-s"); - cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { + cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort { "DISABLE_EXCEPTION_CATCHING=1" } else { "DISABLE_EXCEPTION_CATCHING=0" @@ -2402,22 +2403,21 @@ fn add_order_independent_options( } if flavor == LinkerFlavor::Llbc { - cmd.arg("--target"); - cmd.arg(sess.target.llvm_target.as_ref()); - cmd.arg("--target-cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&[ + "--target", + sess.target.llvm_target.as_ref(), + "--target-cpu", + &codegen_results.crate_info.target_cpu, + ]); } else if flavor == LinkerFlavor::Ptx { - cmd.arg("--fallback-arch"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]); } else if flavor == LinkerFlavor::Bpf { - cmd.arg("--cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--cpu", &codegen_results.crate_info.target_cpu]); if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features] .into_iter() .find(|feat| !feat.is_empty()) { - cmd.arg("--cpu-features"); - cmd.arg(feat); + cmd.link_args(&["--cpu-features", feat]); } } @@ -2618,7 +2618,11 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.linker_arg(OsStr::new(name), verbatim); + if verbatim { + cmd.verbatim_arg(name); + } else { + cmd.link_arg(name); + } } } } @@ -3012,10 +3016,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // This is admittedly a bit strange, as on most targets // `-isysroot` only applies to include header files, but on Apple // targets this also applies to libraries and frameworks. - cmd.args(&["-isysroot", &sdk_root]); + cmd.cc_args(&["-isysroot", &sdk_root]); } LinkerFlavor::Darwin(Cc::No, _) => { - cmd.args(&["-syslibroot", &sdk_root]); + cmd.link_args(&["-syslibroot", &sdk_root]); } _ => unreachable!(), } @@ -3026,8 +3030,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // search path. // The flags are called `-L` and `-F` both in Clang, ld64 and ldd. - cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib")); - cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks")); + let sdk_root = Path::new(&sdk_root); + cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib")); + cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks")); } } @@ -3142,7 +3147,7 @@ fn add_lld_args( for path in sess.get_tools_search_paths(false) { let linker_path = path.join("gcc-ld"); linker_path_exists |= linker_path.exists(); - cmd.arg({ + cmd.cc_arg({ let mut arg = OsString::from("-B"); arg.push(linker_path); arg @@ -3162,7 +3167,7 @@ fn add_lld_args( // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { - cmd.arg("-fuse-ld=lld"); + cmd.cc_arg("-fuse-ld=lld"); } if !flavor.is_gnu() { @@ -3186,7 +3191,7 @@ fn add_lld_args( // targeting a different linker flavor on macOS, and that's also always // the case when targeting WASM. if sess.target.linker_flavor != sess.host.linker_flavor { - cmd.arg(format!("--target={}", sess.target.llvm_target)); + cmd.cc_arg(format!("--target={}", sess.target.llvm_target)); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a82478900b1..0f75ece9729 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -8,7 +8,7 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use std::{env, mem, str}; +use std::{env, iter, mem, str}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -159,6 +159,102 @@ pub fn get_linker<'a>( } } +// Note: Ideally neither these helper function, nor the macro-generated inherent methods below +// would exist, and these functions would live in `trait Linker`. +// Unfortunately, adding these functions to `trait Linker` make it `dyn`-incompatible. +// If the methods are added to the trait with `where Self: Sized` bounds, then even a separate +// implementation of them for `dyn Linker {}` wouldn't work due to a conflict with those +// uncallable methods in the trait. + +/// Just pass the arguments to the linker as is. +/// It is assumed that they are correctly prepared in advance. +fn verbatim_args<L: Linker + ?Sized>( + l: &mut L, + args: impl IntoIterator<Item: AsRef<OsStr>>, +) -> &mut L { + for arg in args { + l.cmd().arg(arg); + } + l +} +/// Arguments for the underlying linker. +/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper. +fn link_args<L: Linker + ?Sized>( + l: &mut L, + args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>, +) -> &mut L { + let args = args.into_iter(); + if !l.is_cc() { + verbatim_args(l, args); + } else if args.len() != 0 { + // FIXME: Support arguments with commas, see `rpaths_to_flags` for the example. + let mut combined_arg = OsString::from("-Wl"); + for arg in args { + combined_arg.push(","); + combined_arg.push(arg); + } + l.cmd().arg(combined_arg); + } + l +} +/// Arguments for the cc wrapper specifically. +/// Check that it's indeed a cc wrapper and pass verbatim. +fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L { + assert!(l.is_cc()); + verbatim_args(l, args) +} +/// Arguments supported by both underlying linker and cc wrapper, pass verbatim. +fn link_or_cc_args<L: Linker + ?Sized>( + l: &mut L, + args: impl IntoIterator<Item: AsRef<OsStr>>, +) -> &mut L { + verbatim_args(l, args) +} + +macro_rules! generate_arg_methods { + ($($ty:ty)*) => { $( + impl $ty { + pub fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + verbatim_args(self, args) + } + pub fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + verbatim_args(self, iter::once(arg)) + } + pub fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self { + link_args(self, args) + } + pub fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + link_args(self, iter::once(arg)) + } + pub fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + cc_args(self, args) + } + pub fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + cc_args(self, iter::once(arg)) + } + pub fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self { + link_or_cc_args(self, args) + } + pub fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { + link_or_cc_args(self, iter::once(arg)) + } + } + )* } +} + +generate_arg_methods! { + GccLinker<'_> + MsvcLinker<'_> + EmLinker<'_> + WasmLd<'_> + L4Bender<'_> + AixLinker<'_> + LlbcLinker<'_> + PtxLinker<'_> + BpfLinker<'_> + dyn Linker + '_ +} + /// Linker abstraction used by `back::link` to build up the command to invoke a /// linker. /// @@ -168,6 +264,9 @@ pub fn get_linker<'a>( /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { fn cmd(&mut self) -> &mut Command; + fn is_cc(&self) -> bool { + false + } fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { @@ -175,10 +274,18 @@ pub trait Linker { } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool); fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool); - fn include_path(&mut self, path: &Path); - fn framework_path(&mut self, path: &Path); - fn output_filename(&mut self, path: &Path); - fn add_object(&mut self, path: &Path); + fn include_path(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]); + } + fn framework_path(&mut self, _path: &Path) { + bug!("framework path set with unsupported linker") + } + fn output_filename(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]); + } + fn add_object(&mut self, path: &Path) { + link_or_cc_args(self, &[path]); + } fn gc_sections(&mut self, keep_metadata: bool); fn no_gc_sections(&mut self); fn full_relro(&mut self); @@ -198,25 +305,9 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} - fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { - self.linker_args(&[arg], verbatim); - } - fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { - args.into_iter().for_each(|a| { - self.cmd().arg(a); - }); - } } impl dyn Linker + '_ { - pub fn arg(&mut self, arg: impl AsRef<OsStr>) { - self.cmd().arg(arg); - } - - pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) { - self.cmd().args(args); - } - pub fn take_cmd(&mut self) -> Command { mem::replace(self.cmd(), Command::new("")) } @@ -233,14 +324,6 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - fn linker_arg(&mut self, arg: impl AsRef<OsStr>) { - Linker::linker_arg(self, arg.as_ref(), false); - } - fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) { - let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); - Linker::linker_args(self, &args_vec, false); - } - fn takes_hints(&self) -> bool { // Really this function only returns true if the underlying linker // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We @@ -262,7 +345,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(true) { - self.linker_arg("-Bstatic"); + self.link_arg("-Bstatic"); self.hinted_static = Some(true); } } @@ -272,7 +355,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(false) { - self.linker_arg("-Bdynamic"); + self.link_arg("-Bdynamic"); self.hinted_static = Some(false); } } @@ -281,7 +364,7 @@ impl<'a> GccLinker<'a> { if let Some(plugin_path) = plugin_path { let mut arg = OsString::from("-plugin="); arg.push(plugin_path); - self.linker_arg(&arg); + self.link_arg(&arg); } let opt_level = match self.sess.opts.optimize { @@ -292,9 +375,9 @@ impl<'a> GccLinker<'a> { }; if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { - self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); + self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; - self.linker_args(&[ + self.link_args(&[ &format!("-plugin-opt={opt_level}"), &format!("-plugin-opt=mcpu={}", self.target_cpu), ]); @@ -304,10 +387,10 @@ impl<'a> GccLinker<'a> { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { if !self.is_ld { - self.cmd.arg("-dynamiclib"); + self.cc_arg("-dynamiclib"); } - self.linker_arg("-dylib"); + self.link_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack // purely to support rustbuild right now, we should get a more @@ -316,10 +399,10 @@ impl<'a> GccLinker<'a> { if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { let mut rpath = OsString::from("@rpath/"); rpath.push(out_filename.file_name().unwrap()); - self.linker_args(&[OsString::from("-install_name"), rpath]); + self.link_arg("-install_name").link_arg(rpath); } } else { - self.cmd.arg("-shared"); + self.link_or_cc_arg("-shared"); if self.sess.target.is_like_windows { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the @@ -336,7 +419,7 @@ impl<'a> GccLinker<'a> { if let Some(implib_name) = implib_name { let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); + self.link_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); } } } @@ -345,76 +428,56 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { - if self.is_ld || verbatim { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - } - fn cmd(&mut self) -> &mut Command { &mut self.cmd } + fn is_cc(&self) -> bool { + !self.is_ld + } + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::DynamicPicExe => { // noop on windows w/ gcc & ld, error w/ lld if !self.sess.target.is_like_windows { // `-pie` works for both gcc wrapper and ld. - self.cmd.arg("-pie"); + self.link_or_cc_arg("-pie"); } } LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::StaticPicExe => { if !self.is_ld { // Note that combination `-static -pie` doesn't work as expected // for the gcc wrapper, `-static` in that case suppresses `-pie`. - self.cmd.arg("-static-pie"); + self.cc_arg("-static-pie"); } else { // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing // a static pie, but currently passed because gcc and clang pass them. // The former suppresses the `INTERP` ELF header specifying dynamic linker, // which is otherwise implicitly injected by ld (but not lld). // The latter doesn't change anything, only ensures that everything is pic. - self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); + self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); } } LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), LinkOutputKind::StaticDylib => { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.build_dylib(out_filename); } LinkOutputKind::WasiReactorExe => { - self.linker_args(&["--entry", "_initialize"]); + self.link_args(&["--entry", "_initialize"]); } } // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, @@ -430,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> { | LinkOutputKind::StaticDylib ) { - self.cmd.arg("--static-crt"); + self.cc_arg("--static-crt"); } } @@ -450,18 +513,18 @@ impl<'a> Linker for GccLinker<'a> { // but we have no way to detect that here. self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--no-as-needed"); + self.link_arg("--no-as-needed"); } else { self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); } } self.hint_dynamic(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.link_or_cc_arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); if !as_needed { if self.sess.target.is_like_osx { // See above FIXME comment } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); + self.link_arg("--as-needed"); } } } @@ -471,63 +534,51 @@ impl<'a> Linker for GccLinker<'a> { if !as_needed { // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework // flag but we have no way to detect that here. - // self.cmd.arg("-needed_framework").arg(name); + // self.link_or_cc_arg("-needed_framework").link_or_cc_arg(name); self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } - self.cmd.arg("-framework").arg(name); + self.link_or_cc_args(&["-framework", name]); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { - self.cmd.arg(format!("-l{colon}{name}")); + self.link_or_cc_arg(format!("-l{colon}{name}")); } else if self.sess.target.is_like_osx { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. - self.linker_arg("-force_load"); - self.linker_arg(find_native_static_library(name, verbatim, self.sess)); + self.link_arg("-force_load"); + self.link_arg(find_native_static_library(name, verbatim, self.sess)); } else { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{colon}{name}")); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{colon}{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else if self.sess.target.is_like_osx { - self.linker_arg("-force_load"); - self.linker_arg(path); + self.link_arg("-force_load").link_arg(path); } else { - self.linker_arg("--whole-archive"); - self.linker_arg(path); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } fn framework_path(&mut self, path: &Path) { - self.cmd.arg("-F").arg(path); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_or_cc_arg("-F").link_or_cc_arg(path); } fn full_relro(&mut self) { - self.linker_args(&["-z", "relro", "-z", "now"]); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.linker_args(&["-z", "relro"]); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.linker_args(&["-z", "norelro"]); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { @@ -546,7 +597,7 @@ impl<'a> Linker for GccLinker<'a> { // for partial linking when using multiple codegen units (-r). So we // insert it here. if self.sess.target.is_like_osx { - self.linker_arg("-dead_strip"); + self.link_arg("-dead_strip"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -554,13 +605,13 @@ impl<'a> Linker for GccLinker<'a> { // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata { - self.linker_arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { if self.is_gnu || self.sess.target.is_like_wasm { - self.linker_arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } } @@ -574,7 +625,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.linker_arg("-O1"); + self.link_arg("-O1"); } } @@ -594,8 +645,7 @@ impl<'a> Linker for GccLinker<'a> { // // Though it may be worth to try to revert those changes upstream, since // the overhead of the initialization should be minor. - self.cmd.arg("-u"); - self.cmd.arg("__llvm_profile_runtime"); + self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]); } fn control_flow_guard(&mut self) {} @@ -616,33 +666,33 @@ impl<'a> Linker for GccLinker<'a> { // The --strip-debug case is handled by running an external // `strip` utility as a separate step after linking. if !self.sess.target.is_like_solaris { - self.linker_arg("--strip-debug"); + self.link_arg("--strip-debug"); } } Strip::Symbols => { - self.linker_arg("--strip-all"); + self.link_arg("--strip-all"); } } match self.sess.opts.unstable_opts.debuginfo_compression { config::DebugInfoCompression::None => {} config::DebugInfoCompression::Zlib => { - self.linker_arg("--compress-debug-sections=zlib"); + self.link_arg("--compress-debug-sections=zlib"); } config::DebugInfoCompression::Zstd => { - self.linker_arg("--compress-debug-sections=zstd"); + self.link_arg("--compress-debug-sections=zstd"); } } } fn no_crt_objects(&mut self) { if !self.is_ld { - self.cmd.arg("-nostartfiles"); + self.cc_arg("-nostartfiles"); } } fn no_default_libraries(&mut self) { if !self.is_ld { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } } @@ -718,24 +768,22 @@ impl<'a> Linker for GccLinker<'a> { } if self.sess.target.is_like_osx { - self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); + self.link_arg("-exported_symbols_list").link_arg(path); } else if self.sess.target.is_like_solaris { - self.linker_args(&[OsString::from("-M"), path.into()]); + self.link_arg("-M").link_arg(path); } else { if is_windows { - self.linker_arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("--version-script="); arg.push(path); - self.linker_arg(arg); - self.linker_arg("--no-undefined-version"); + self.link_arg(arg).link_arg("--no-undefined-version"); } } } fn subsystem(&mut self, subsystem: &str) { - self.linker_arg("--subsystem"); - self.linker_arg(&subsystem); + self.link_args(&["--subsystem", subsystem]); } fn reset_per_library_state(&mut self) { @@ -760,23 +808,23 @@ impl<'a> Linker for GccLinker<'a> { // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, // so we just always add it. fn add_eh_frame_header(&mut self) { - self.linker_arg("--eh-frame-hdr"); + self.link_arg("--eh-frame-hdr"); } fn add_no_exec(&mut self) { if self.sess.target.is_like_windows { - self.linker_arg("--nxcompat"); + self.link_arg("--nxcompat"); } else if self.is_gnu { - self.linker_args(&["-z", "noexecstack"]); + self.link_args(&["-z", "noexecstack"]); } } fn add_as_needed(&mut self) { if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); + self.link_arg("--as-needed"); } else if self.sess.target.is_like_solaris { // -z ignore is the Solaris equivalent to the GNU ld --as-needed option - self.linker_args(&["-z", "ignore"]); + self.link_args(&["-z", "ignore"]); } } } @@ -798,10 +846,10 @@ impl<'a> Linker for MsvcLinker<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("/DLL"); + self.link_arg("/DLL"); let mut arg: OsString = "/IMPLIB:".into(); arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); + self.link_arg(arg); } LinkOutputKind::WasiReactorExe => { panic!("can't link as reactor on non-wasi target"); @@ -810,44 +858,40 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; - self.cmd.arg(format!("{prefix}{name}{suffix}")); + self.link_arg(format!("{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("/WHOLEARCHIVE:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn gc_sections(&mut self, _keep_metadata: bool) { // MSVC's ICF (Identical COMDAT Folding) link optimization is // slow for Rust and thus we disable it by default when not in // optimization build. if self.sess.opts.optimize != config::OptLevel::No { - self.cmd.arg("/OPT:REF,ICF"); + self.link_arg("/OPT:REF,ICF"); } else { // It is necessary to specify NOICF here, because /OPT:REF // implies ICF by default. - self.cmd.arg("/OPT:REF,NOICF"); + self.link_arg("/OPT:REF,NOICF"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("/OPT:NOREF,NOICF"); + self.link_arg("/OPT:NOREF,NOICF"); } fn full_relro(&mut self) { @@ -867,23 +911,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn no_default_libraries(&mut self) { - self.cmd.arg("/NODEFAULTLIB"); + self.link_arg("/NODEFAULTLIB"); } fn include_path(&mut self, path: &Path) { let mut arg = OsString::from("/LIBPATH:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn output_filename(&mut self, path: &Path) { let mut arg = OsString::from("/OUT:"); arg.push(path); - self.cmd.arg(&arg); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on windows") + self.link_arg(&arg); } fn optimize(&mut self) { @@ -895,19 +935,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn control_flow_guard(&mut self) { - self.cmd.arg("/guard:cf"); + self.link_arg("/guard:cf"); } fn ehcont_guard(&mut self) { if self.sess.target.pointer_width == 64 { - self.cmd.arg("/guard:ehcont"); + self.link_arg("/guard:ehcont"); } } fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { // This will cause the Microsoft linker to generate a PDB file // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); + self.link_arg("/DEBUG"); // Default to emitting only the file name of the PDB file into // the binary instead of the full path. Emitting the full path @@ -916,7 +956,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // This default behavior can be overridden by explicitly passing // `-Clink-arg=/PDBALTPATH:...` to rustc. - self.cmd.arg("/PDBALTPATH:%_PDB%"); + self.link_arg("/PDBALTPATH:%_PDB%"); // This will cause the Microsoft linker to embed .natvis info into the PDB file let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); @@ -928,7 +968,7 @@ impl<'a> Linker for MsvcLinker<'a> { if path.extension() == Some("natvis".as_ref()) { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } Err(error) => { @@ -942,7 +982,7 @@ impl<'a> Linker for MsvcLinker<'a> { for path in natvis_debugger_visualizers { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } @@ -986,13 +1026,13 @@ impl<'a> Linker for MsvcLinker<'a> { } let mut arg = OsString::from("/DEF:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn subsystem(&mut self, subsystem: &str) { // Note that previous passes of the compiler validated this subsystem, // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}")); + self.link_arg(&format!("/SUBSYSTEM:{subsystem}")); // Windows has two subsystems we're interested in right now, the console // and windows subsystems. These both implicitly have different entry @@ -1009,7 +1049,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // For more information see RFC #1665 if subsystem == "windows" { - self.cmd.arg("/ENTRY:mainCRTStartup"); + self.link_arg("/ENTRY:mainCRTStartup"); } } @@ -1018,7 +1058,7 @@ impl<'a> Linker for MsvcLinker<'a> { } fn add_no_exec(&mut self) { - self.cmd.arg("/NXCOMPAT"); + self.link_arg("/NXCOMPAT"); } } @@ -1032,31 +1072,23 @@ impl<'a> Linker for EmLinker<'a> { &mut self.cmd } + fn is_cc(&self) -> bool { + true + } + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_or_cc_arg(path); } fn full_relro(&mut self) { @@ -1071,10 +1103,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on Emscripten") - } - fn gc_sections(&mut self, _keep_metadata: bool) { // noop } @@ -1085,7 +1113,7 @@ impl<'a> Linker for EmLinker<'a> { fn optimize(&mut self) { // Emscripten performs own optimizations - self.cmd.arg(match self.sess.opts.optimize { + self.cc_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1106,7 +1134,7 @@ impl<'a> Linker for EmLinker<'a> { fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g - self.cmd.arg(match self.sess.opts.debuginfo { + self.cc_arg(match self.sess.opts.debuginfo { DebugInfo::None => "-g0", DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => { "--profiling-funcs" @@ -1118,13 +1146,13 @@ impl<'a> Linker for EmLinker<'a> { fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { debug!("EXPORTED SYMBOLS:"); - self.cmd.arg("-s"); + self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( @@ -1135,7 +1163,7 @@ impl<'a> Linker for EmLinker<'a> { arg.push(encoded); - self.cmd.arg(arg); + self.cc_arg(arg); } fn subsystem(&mut self, _subsystem: &str) { @@ -1153,7 +1181,7 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { + fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { // If the atomics feature is enabled for wasm then we need a whole bunch // of flags: // @@ -1172,18 +1200,19 @@ impl<'a> WasmLd<'a> { // On wasm32-unknown-unknown, we also export symbols for glue code to use: // * `--export=*tls*` - when `#[thread_local]` symbols are used these // symbols are how the TLS segments are initialized and configured. + let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { - cmd.arg("--shared-memory"); - cmd.arg("--max-memory=1073741824"); - cmd.arg("--import-memory"); + wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); if sess.target.os == "unknown" { - cmd.arg("--export=__wasm_init_tls"); - cmd.arg("--export=__tls_size"); - cmd.arg("--export=__tls_align"); - cmd.arg("--export=__tls_base"); + wasm_ld.link_args(&[ + "--export=__wasm_init_tls", + "--export=__tls_size", + "--export=__tls_align", + "--export=__tls_base", + ]); } } - WasmLd { cmd, sess } + wasm_ld } } @@ -1199,51 +1228,36 @@ impl<'a> Linker for WasmLd<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("--no-entry"); + self.link_arg("--no-entry"); } LinkOutputKind::WasiReactorExe => { - self.cmd.arg("--entry"); - self.cmd.arg("_initialize"); + self.link_args(&["--entry", "_initialize"]); } } } fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } else { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_args(&["-l", name]) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1251,17 +1265,17 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and // only differentiates -O0 and -O1. It does not apply to LTO. - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1279,10 +1293,10 @@ impl<'a> Linker for WasmLd<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd.arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd.arg("--strip-all"); + self.link_arg("--strip-all"); } } } @@ -1297,7 +1311,7 @@ impl<'a> Linker for WasmLd<'a> { fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { for sym in symbols { - self.cmd.arg("--export").arg(&sym); + self.link_args(&["--export", sym]); } // LLD will hide these otherwise-internal symbols since it only exports @@ -1305,8 +1319,7 @@ impl<'a> Linker for WasmLd<'a> { // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. if self.sess.target.os == "unknown" { - self.cmd.arg("--export=__heap_base"); - self.cmd.arg("--export=__data_end"); + self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } @@ -1337,7 +1350,7 @@ impl<'a> WasmLd<'a> { // wasm-ld only handles integer LTO opt levels. Use O2 config::OptLevel::Size | config::OptLevel::SizeMin => "O2", }; - self.cmd.arg(&format!("--lto-{opt_level}")); + self.link_arg(&format!("--lto-{opt_level}")); } } @@ -1362,56 +1375,43 @@ impl<'a> Linker for L4Bender<'a> { fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-PC{name}")); + self.link_arg(format!("-PC{name}")); } else { - self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on L4Re"); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); - self.cmd.arg("-z").arg("now"); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.cmd.arg("-z").arg("norelro"); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { if !keep_metadata { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { @@ -1420,7 +1420,7 @@ impl<'a> Linker for L4Bender<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.cmd.arg("-O1"); + self.link_arg("-O1"); } } @@ -1430,16 +1430,16 @@ impl<'a> Linker for L4Bender<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd().arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd().arg("--strip-all"); + self.link_arg("--strip-all"); } } } fn no_default_libraries(&mut self) { - self.cmd.arg("-nostdlib"); + self.cc_arg("-nostdlib"); } fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { @@ -1449,7 +1449,7 @@ impl<'a> Linker for L4Bender<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem {subsystem}")); + self.link_arg(&format!("--subsystem {subsystem}")); } fn reset_per_library_state(&mut self) { @@ -1467,12 +1467,12 @@ impl<'a> Linker for L4Bender<'a> { impl<'a> L4Bender<'a> { pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { - L4Bender { cmd: cmd, sess: sess, hinted_static: false } + L4Bender { cmd, sess: sess, hinted_static: false } } fn hint_static(&mut self) { if !self.hinted_static { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.hinted_static = true; } } @@ -1487,29 +1487,28 @@ pub struct AixLinker<'a> { impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: None } + AixLinker { cmd, sess: sess, hinted_static: None } } fn hint_static(&mut self) { if self.hinted_static != Some(true) { - self.cmd.arg("-bstatic"); + self.link_arg("-bstatic"); self.hinted_static = Some(true); } } fn hint_dynamic(&mut self) { if self.hinted_static != Some(false) { - self.cmd.arg("-bdynamic"); + self.link_arg("-bdynamic"); self.hinted_static = Some(false); } } fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("-bM:SRE"); - self.cmd.arg("-bnoentry"); + self.link_args(&["-bM:SRE", "-bnoentry"]); // FIXME: Use CreateExportList utility to create export list // and remove -bexpfull. - self.cmd.arg("-bexpfull"); + self.link_arg("-bexpfull"); } } @@ -1534,47 +1533,31 @@ impl<'a> Linker for AixLinker<'a> { fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); - self.cmd.arg(arg); + self.link_or_cc_arg(arg); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on AIX"); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1582,17 +1565,17 @@ impl<'a> Linker for AixLinker<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("-bgc"); + self.link_arg("-bgc"); } fn no_gc_sections(&mut self) { - self.cmd.arg("-bnogc"); + self.link_arg("-bnogc"); } fn optimize(&mut self) {} fn pgo_gen(&mut self) { - self.cmd.arg("-bdbg:namedsects:ss"); + self.link_arg("-bdbg:namedsects:ss"); } fn control_flow_guard(&mut self) {} @@ -1618,7 +1601,7 @@ impl<'a> Linker for AixLinker<'a> { if let Err(e) = res { self.sess.dcx().fatal(format!("failed to write export file: {e}")); } - self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); + self.link_arg(format!("-bE:{}", path.to_str().unwrap())); } fn subsystem(&mut self, _subsystem: &str) {} @@ -1747,39 +1730,27 @@ impl<'a> Linker for PtxLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg("--rlib").arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_arg("--rlib").link_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); + self.link_arg("--debug"); } fn add_object(&mut self, path: &Path) { - self.cmd.arg("--bitcode").arg(path); + self.link_arg("--bitcode").link_arg(path); } fn optimize(&mut self) { match self.sess.lto() { Lto::Thin | Lto::Fat | Lto::ThinLocal => { - self.cmd.arg("-Olto"); + self.link_arg("-Olto"); } Lto::No => {} } } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1829,19 +1800,11 @@ impl<'a> Linker for LlbcLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { @@ -1855,14 +1818,6 @@ impl<'a> Linker for LlbcLinker<'a> { }; } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1887,7 +1842,7 @@ impl<'a> Linker for LlbcLinker<'a> { match _crate_type { CrateType::Cdylib => { for sym in symbols { - self.cmd.arg("--export-symbol").arg(sym); + self.link_args(&["--export-symbol", sym]); } } _ => (), @@ -1920,23 +1875,15 @@ impl<'a> Linker for BpfLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1946,14 +1893,6 @@ impl<'a> Linker for BpfLinker<'a> { }); } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1985,7 +1924,7 @@ impl<'a> Linker for BpfLinker<'a> { if let Err(error) = res { self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error }); } else { - self.cmd.arg("--export-symbols").arg(&path); + self.link_arg("--export-symbols").link_arg(&path); } } diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index f499bbcf853..82070d4453b 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -9,16 +9,10 @@ pub struct RPathConfig<'a> { pub libs: &'a [&'a Path], pub out_filename: PathBuf, pub is_like_osx: bool, - pub has_rpath: bool, pub linker_is_gnu: bool, } pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - debug!("preparing the RPATH!"); let rpaths = get_rpaths(config); diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 0de90a1036e..c620e92db1f 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -37,7 +37,6 @@ fn test_rpath_relative() { if cfg!(target_os = "macos") { let config = &mut RPathConfig { libs: &[], - has_rpath: true, is_like_osx: true, linker_is_gnu: false, out_filename: PathBuf::from("bin/rustc"), @@ -48,7 +47,6 @@ fn test_rpath_relative() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("bin/rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; @@ -62,7 +60,6 @@ fn test_rpath_relative_issue_119571() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index ddc6797388e..febc8ee2be2 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -133,6 +133,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); + cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); cx.create_vtable_debuginfo(ty, trait_ref, vtable); cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 57138d3b9db..b1c22faf1ae 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -658,7 +658,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // with #[rustc_inherit_overflow_checks] and inlined from // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { + if !bx.sess().overflow_checks() && msg.is_optional_overflow_check() { const_cond = Some(expected); } @@ -751,7 +751,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, - intrinsic: Option<ty::IntrinsicDef>, + intrinsic: ty::IntrinsicDef, instance: Option<Instance<'tcx>>, source_info: mir::SourceInfo, target: Option<mir::BasicBlock>, @@ -761,8 +761,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name)); - if let Some(requirement) = panic_intrinsic { + if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { let ty = instance.unwrap().args.type_at(0); let do_panic = !bx @@ -869,12 +868,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let sig = callee.layout.ty.fn_sig(bx.tcx()); let abi = sig.abi(); - // Handle intrinsics old codegen wants Expr's for, ourselves. - let intrinsic = match def { - Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), - _ => None, - }; - let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { let op_ty = op_arg.node.ty(self.mir, bx.tcx()); @@ -886,50 +879,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) { - return if let Some(target) = target { - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - let mut llargs = Vec::with_capacity(arg_count); - let ret_dest = self.make_return_dest( + let instance = match def { + Some(ty::InstanceKind::Intrinsic(def_id)) => { + let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); + if let Some(merging_succ) = self.codegen_panic_intrinsic( + &helper, bx, - destination, - &fn_abi.ret, - &mut llargs, intrinsic, - Some(target), - ); - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); + instance, + source_info, + target, + unwind, + mergeable_succ, + ) { + return merging_succ; } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - MergingSucc::False - }; - } - let instance = match intrinsic { - None => instance, - Some(intrinsic) => { let mut llargs = Vec::with_capacity(1); let ret_dest = self.make_return_dest( bx, @@ -971,6 +939,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); + if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { + let location = self + .get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); + + assert_eq!(llargs, []); + if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { + location.val.store(bx, tmp); + } + self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); + return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); + } + let instance = *instance.as_ref().unwrap(); match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { Ok(()) => { @@ -997,6 +977,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + _ => instance, }; let mut llargs = Vec::with_capacity(arg_count); diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e8b9490d401..3770bd11cf9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -22,8 +22,6 @@ use rustc_session::{ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; -use std::fmt; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -62,7 +60,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> { vec![] } @@ -150,19 +148,3 @@ pub trait ExtraBackendMethods: std::thread::Builder::new().name(name).spawn(f) } } - -pub trait PrintBackendInfo { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); -} - -impl PrintBackendInfo for String { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { - fmt::Write::write_fmt(self, args).unwrap(); - } -} - -impl dyn PrintBackendInfo + '_ { - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { - self.infallible_write_fmt(args); - } -} diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 8cb17a5b37a..3da732602c5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -37,6 +37,5 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 04e2b8796c4..0ace28ed3ba 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -9,7 +9,13 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn vtables( &self, ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>; - fn check_overflow(&self) -> bool; + fn apply_vcall_visibility_metadata( + &self, + _ty: Ty<'tcx>, + _poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + _vtable: Self::Value, + ) { + } fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; fn eh_personality(&self) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 728c2bc8c49..8cb58bd4c70 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,9 +30,7 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{ - Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, -}; +pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 403f6a73277..b1bad6cfa6f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -12,7 +12,6 @@ use rustc_target::abi::{AddressSpace, Float, Integer}; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { - fn type_i1(&self) -> Self::Type; fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -27,7 +26,6 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; - fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr(&self) -> Self::Type; fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; @@ -115,8 +113,8 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { /// The backend type used for a rust type when it's in an SSA register. /// /// For nearly all types this is the same as the [`Self::backend_type`], however - /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] - /// in registers but as [`BaseTypeMethods::type_i8`] in memory. + /// `bool` (and other `0`-or-`1` values) are kept as `i1` in registers but as + /// [`BaseTypeMethods::type_i8`] in memory. /// /// Converting values between the two different backend types is done using /// [`from_immediate`](super::BuilderMethods::from_immediate) and diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 8c66888d100..7acd08e0cce 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -42,10 +42,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { hir::Constness::Const } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx - .generics_of(def_id) - .host_effect_index - .map_or(hir::Constness::NotConst, |_| hir::Constness::Const), + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index a13630ce084..83b61ab1749 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; @@ -187,10 +187,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty) }; let val = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => self.cast_from_float(src.to_scalar().to_f16()?, cast_to.ty), FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty), FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; Ok(ImmTy::from_scalar(val, cast_to)) } @@ -296,18 +296,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Float(fty) if signed => { let v = v as i128; match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_i128(v).value), } } // unsigned int -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => Scalar::from_f128(Quad::from_u128(v).value), }, // u8 -> char @@ -321,7 +321,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Low-level cast helper function. Converts an apfloat `f` into int or float types. fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where - F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, + F: Float + + Into<Scalar<M::Provenance>> + + FloatConvert<Half> + + FloatConvert<Single> + + FloatConvert<Double> + + FloatConvert<Quad>, { use rustc_type_ir::TyKind::*; @@ -358,10 +363,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // float -> float Float(fty) => match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)), FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value)) + } }, // That's it. _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index f525510030b..c4b2e067bbe 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -50,7 +50,7 @@ libc = "0.2" memmap2 = "0.2.1" # tidy-alphabetical-end -[target.'cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))'.dependencies] +[target.'cfg(not(target_has_atomic = "64"))'.dependencies] portable-atomic = "1.5.1" [features] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 32fad0de1aa..83fdaff515b 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -147,14 +147,13 @@ cfg_match! { [crate::owned_slice::OwnedSlice] ); - // MIPS, PowerPC and SPARC platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc", target_arch = "sparc")))] + // Use portable AtomicU64 for targets without native 64-bit atomics + #[cfg(target_has_atomic = "64")] already_sync!( [std::sync::atomic::AtomicU64] ); - #[cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))] + #[cfg(not(target_has_atomic = "64"))] already_sync!( [portable_atomic::AtomicU64] ); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 5ae79ca988f..79ceb28abb5 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -270,12 +270,11 @@ cfg_match! { pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32}; - // MIPS, PowerPC and SPARC platforms with 32-bit pointers do not - // have AtomicU64 type. - #[cfg(not(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc")))] + // Use portable AtomicU64 for targets without native 64-bit atomics + #[cfg(target_has_atomic = "64")] pub use std::sync::atomic::AtomicU64; - #[cfg(any(target_arch = "mips", target_arch = "powerpc", target_arch = "sparc"))] + #[cfg(not(target_has_atomic = "64"))] pub use portable_atomic::AtomicU64; pub use std::sync::Arc as Lrc; diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index e580910af77..d500f6d88a0 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -510,7 +510,7 @@ pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { // would be bad. impl<G> !Clone for Diag<'_, G> {} -rustc_data_structures::static_assert_size!(Diag<'_, ()>, 2 * std::mem::size_of::<usize>()); +rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * std::mem::size_of::<usize>()); impl<G: EmissionGuarantee> Deref for Diag<'_, G> { type Target = DiagInner; @@ -582,6 +582,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { Self::new_diagnostic(dcx, DiagInner::new(level, message)) } + /// Allow moving diagnostics between different error tainting contexts + pub fn with_dcx(mut self, dcx: DiagCtxtHandle<'_>) -> Diag<'_, G> { + Diag { dcx, diag: self.diag.take(), _marker: PhantomData } + } + /// Creates a new `Diag` with an already constructed diagnostic. #[track_caller] pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 91112a57277..2086d4030f9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -63,6 +63,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::{Loc, Span, DUMMY_SP}; use std::backtrace::{Backtrace, BacktraceStatus}; use std::borrow::Cow; +use std::cell::Cell; use std::error::Report; use std::fmt; use std::hash::Hash; @@ -98,9 +99,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); +rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24); #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); +rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { @@ -417,6 +418,9 @@ pub struct DiagCtxt { #[derive(Copy, Clone)] pub struct DiagCtxtHandle<'a> { dcx: &'a DiagCtxt, + /// Some contexts create `DiagCtxtHandle` with this field set, and thus all + /// errors emitted with it will automatically taint when emitting errors. + tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>, } impl<'a> std::ops::Deref for DiagCtxtHandle<'a> { @@ -752,7 +756,17 @@ impl DiagCtxt { } pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> { - DiagCtxtHandle { dcx: self } + DiagCtxtHandle { dcx: self, tainted_with_errors: None } + } + + /// Link this to a taintable context so that emitting errors will automatically set + /// the `Option<ErrorGuaranteed>` instead of having to do that manually at every error + /// emission site. + pub fn taintable_handle<'a>( + &'a self, + tainted_with_errors: &'a Cell<Option<ErrorGuaranteed>>, + ) -> DiagCtxtHandle<'a> { + DiagCtxtHandle { dcx: self, tainted_with_errors: Some(tainted_with_errors) } } } @@ -795,7 +809,9 @@ impl<'a> DiagCtxtHandle<'a> { // can be used to create a backtrace at the stashing site insted of whenever the // diagnostic context is dropped and thus delayed bugs are emitted. Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))), - DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag), + DelayedBug => { + return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors); + } ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow | Expect(_) => None, }; @@ -947,16 +963,19 @@ impl<'a> DiagCtxtHandle<'a> { (0, _) => { // Use `ForceWarning` rather than `Warning` to guarantee emission, e.g. with a // configuration like `--cap-lints allow --force-warn bare_trait_objects`. - inner.emit_diagnostic(DiagInner::new( - ForceWarning(None), - DiagMessage::Str(warnings), - )); + inner.emit_diagnostic( + DiagInner::new(ForceWarning(None), DiagMessage::Str(warnings)), + None, + ); } (_, 0) => { - inner.emit_diagnostic(DiagInner::new(Error, errors)); + inner.emit_diagnostic(DiagInner::new(Error, errors), self.tainted_with_errors); } (_, _) => { - inner.emit_diagnostic(DiagInner::new(Error, format!("{errors}; {warnings}"))); + inner.emit_diagnostic( + DiagInner::new(Error, format!("{errors}; {warnings}")), + self.tainted_with_errors, + ); } } @@ -987,14 +1006,14 @@ impl<'a> DiagCtxtHandle<'a> { "For more information about an error, try `rustc --explain {}`.", &error_codes[0] ); - inner.emit_diagnostic(DiagInner::new(FailureNote, msg1)); - inner.emit_diagnostic(DiagInner::new(FailureNote, msg2)); + inner.emit_diagnostic(DiagInner::new(FailureNote, msg1), None); + inner.emit_diagnostic(DiagInner::new(FailureNote, msg2), None); } else { let msg = format!( "For more information about this error, try `rustc --explain {}`.", &error_codes[0] ); - inner.emit_diagnostic(DiagInner::new(FailureNote, msg)); + inner.emit_diagnostic(DiagInner::new(FailureNote, msg), None); } } } @@ -1020,7 +1039,7 @@ impl<'a> DiagCtxtHandle<'a> { } pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> { - self.inner.borrow_mut().emit_diagnostic(diagnostic) + self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { @@ -1080,7 +1099,7 @@ impl<'a> DiagCtxtHandle<'a> { // Here the diagnostic is given back to `emit_diagnostic` where it was first // intercepted. Now it should be processed as usual, since the unstable expectation // id is now stable. - inner.emit_diagnostic(diag); + inner.emit_diagnostic(diag, self.tainted_with_errors); } } @@ -1430,13 +1449,17 @@ impl DiagCtxtInner { continue; } } - guar = guar.or(self.emit_diagnostic(diag)); + guar = guar.or(self.emit_diagnostic(diag, None)); } guar } // Return value is only `Some` if the level is `Error` or `DelayedBug`. - fn emit_diagnostic(&mut self, mut diagnostic: DiagInner) -> Option<ErrorGuaranteed> { + fn emit_diagnostic( + &mut self, + mut diagnostic: DiagInner, + taint: Option<&Cell<Option<ErrorGuaranteed>>>, + ) -> Option<ErrorGuaranteed> { match diagnostic.level { Expect(expect_id) | ForceWarning(Some(expect_id)) => { // The `LintExpectationId` can be stable or unstable depending on when it was @@ -1609,6 +1632,9 @@ impl DiagCtxtInner { if is_lint { self.lint_err_guars.push(guar); } else { + if let Some(taint) = taint { + taint.set(Some(guar)); + } self.err_guars.push(guar); } self.panic_if_treat_err_as_bug(); @@ -1718,8 +1744,8 @@ impl DiagCtxtInner { // `-Ztreat-err-as-bug`, which we don't want. let note1 = "no errors encountered even though delayed bugs were created"; let note2 = "those delayed bugs will now be shown as internal compiler errors"; - self.emit_diagnostic(DiagInner::new(Note, note1)); - self.emit_diagnostic(DiagInner::new(Note, note2)); + self.emit_diagnostic(DiagInner::new(Note, note1), None); + self.emit_diagnostic(DiagInner::new(Note, note2), None); for bug in bugs { if let Some(out) = &mut out { @@ -1752,7 +1778,7 @@ impl DiagCtxtInner { } bug.level = Bug; - self.emit_diagnostic(bug); + self.emit_diagnostic(bug, None); } // Panic with `DelayedBugPanic` to avoid "unexpected panic" messages. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f884f996927..910402d5499 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -833,6 +833,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_panic_str, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), + rustc_attr!( + rustc_runtime, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::No, INTERNAL_UNSTABLE + ), // ========================================================================== // Internal attributes, Layout related: @@ -1114,6 +1118,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( + TEST, rustc_dump_def_parents, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 22a6c06bba3..6cccdec94c0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -526,6 +526,7 @@ pub enum GenericParamKind<'hir> { /// Optional default value for the const generic param default: Option<&'hir AnonConst>, is_host_effect: bool, + synthetic: bool, }, } @@ -3364,6 +3365,7 @@ pub enum ItemKind<'hir> { /// Refer to [`ImplItem`] for an associated item within an impl block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Impl<'hir> { + pub constness: Constness, pub safety: Safety, pub polarity: ImplPolarity, pub defaultness: Defaultness, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 065ecc5d7b7..9bb3245ae05 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -543,6 +543,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id())); } ItemKind::Impl(Impl { + constness: _, safety: _, defaultness: _, polarity: _, @@ -915,7 +916,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default, is_host_effect: _ } => { + GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => { try_visit!(visitor.visit_ty(ty)); if let Some(ref default) = default { try_visit!(visitor.visit_const_param_default(param.hir_id, default)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 69461957f80..3c44acb1657 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -393,6 +393,14 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + + EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None; + EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None; + EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None; + EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None; + EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None; + EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1); + EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1); } pub enum GenericRequirement { diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 7ed32fb9d9f..064d9c077b0 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -120,6 +120,10 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here +hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally + .note = the next trait solver must be enabled globally for the effects feature to work correctly + .help = use `-Znext-solver` to enable + hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 7f0d72b3a8d..c7ee89e73c2 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,9 +1,13 @@ //! Bounds are restrictions applied to some types after they've been lowered from the HIR to the //! [`rustc_middle::ty`] form. +use rustc_data_structures::fx::FxIndexMap; +use rustc_hir::def::DefKind; use rustc_hir::LangItem; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; -use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_span::{sym, Span}; /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: @@ -24,6 +28,7 @@ use rustc_span::Span; #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { clauses: Vec<(ty::Clause<'tcx>, Span)>, + effects_min_tys: FxIndexMap<Ty<'tcx>, Span>, } impl<'tcx> Bounds<'tcx> { @@ -40,12 +45,14 @@ impl<'tcx> Bounds<'tcx> { pub fn push_trait_bound( &mut self, tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + defining_def_id: DefId, + bound_trait_ref: ty::PolyTraitRef<'tcx>, span: Span, polarity: ty::PredicatePolarity, + constness: ty::BoundConstness, ) { let clause = ( - trait_ref + bound_trait_ref .map_bound(|trait_ref| { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }) @@ -53,11 +60,98 @@ impl<'tcx> Bounds<'tcx> { span, ); // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. - if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { + if tcx.is_lang_item(bound_trait_ref.def_id(), LangItem::Sized) { self.clauses.insert(0, clause); } else { self.clauses.push(clause); } + + if !tcx.features().effects { + return; + } + // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the + // associated type of `<T as Tr>` and make sure that the effect is compatible. + let compat_val = match (tcx.def_kind(defining_def_id), constness) { + // FIXME(effects): revisit the correctness of this + (_, ty::BoundConstness::Const) => tcx.consts.false_, + // body owners that can have trait bounds + (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => { + tcx.expected_host_effect_param_for_body(defining_def_id) + } + + (_, ty::BoundConstness::NotConst) => { + if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) { + return; + } + tcx.consts.true_ + } + + ( + DefKind::Trait | DefKind::Impl { of_trait: true }, + ty::BoundConstness::ConstIfConst, + ) => { + // this is either a where clause on an impl/trait header or on a trait. + // push `<T as Tr>::Effects` into the set for the `Min` bound. + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); + return; + }; + + let ty = bound_trait_ref + .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args)); + + // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the + // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in + // the `Min` associated type properly (which doesn't allow using `for<>`) + // This should work for any bound variables as long as they don't have any + // bounds e.g. `for<T: Trait>`. + // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>` + let ty = tcx.replace_bound_vars_uncached( + ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_static, + types: &mut |_| tcx.types.unit, + consts: &mut |_| unimplemented!("`~const` does not support const binders"), + }, + ); + + self.effects_min_tys.insert(ty, span); + return; + } + // for + // ``` + // trait Foo { type Bar: ~const Trait } + // ``` + // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`. + // + // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor + // that uses a `Bar` that implements `Trait` with `Maybe` effects. + (DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => { + // FIXME(effects): implement this + return; + } + // probably illegal in this position. + (_, ty::BoundConstness::ConstIfConst) => { + tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered"); + return; + } + }; + // create a new projection type `<T as Tr>::Effects` + let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { + tcx.dcx().span_delayed_bug( + span, + "`~const` trait bound has no effect assoc yet no errors encountered?", + ); + return; + }; + let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args); + // make `<T as Tr>::Effects: Compat<runtime>` + let new_trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), + [ty::GenericArg::from(self_ty), compat_val.into()], + ); + self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span)); } pub fn push_projection_bound( @@ -79,7 +173,15 @@ impl<'tcx> Bounds<'tcx> { self.clauses.insert(0, (trait_ref.upcast(tcx), span)); } - pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { + pub fn clauses( + &self, + // FIXME(effects): remove tcx + _tcx: TyCtxt<'tcx>, + ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ { self.clauses.iter().cloned() } + + pub fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { + self.effects_min_tys.keys().copied() + } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e13ea1a1935..f93777eda52 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -879,7 +879,8 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - if !tcx.is_impl_trait_in_trait(impl_item) { + // FIXME(effects) the associated type from effects could be specialized + if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7fa5c96bc9a..b5b68471b9d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1985,10 +1985,10 @@ pub(super) fn check_type_bounds<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the - // span for an impl's associated type. Instead, for these, use the def_span for the synthesized - // associated type. - let impl_ty_span = if impl_ty.is_impl_trait_in_trait() { + // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, + // which we currently use to get the span for an impl's associated type. Instead, for these, + // use the def_span for the synthesized associated type. + let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring { tcx.def_span(impl_ty_def_id) } else { match tcx.hir_node_by_def_id(impl_ty_def_id) { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index a188c1b12ae..2230528a5ae 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -913,7 +913,12 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => { + hir::GenericParamKind::Const { + ty: hir_ty, + default: _, + is_host_effect: _, + synthetic: _, + } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().adt_const_params { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e7892f17660..41fbef48940 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -70,10 +70,10 @@ pub fn provide(providers: &mut Providers) { predicates_of: predicates_of::predicates_of, predicates_defined_on, explicit_predicates_of: predicates_of::explicit_predicates_of, - super_predicates_of: predicates_of::super_predicates_of, - implied_predicates_of: predicates_of::implied_predicates_of, - super_predicates_that_define_assoc_item: - predicates_of::super_predicates_that_define_assoc_item, + explicit_super_predicates_of: predicates_of::explicit_super_predicates_of, + explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of, + explicit_supertraits_containing_assoc_item: + predicates_of::explicit_supertraits_containing_assoc_item, trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds, type_param_predicates: predicates_of::type_param_predicates, trait_def, @@ -691,14 +691,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Trait(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().trait_def(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); tcx.ensure().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { tcx.ensure().generics_of(def_id); - tcx.at(it.span).implied_predicates_of(def_id); - tcx.at(it.span).super_predicates_of(def_id); + tcx.at(it.span).explicit_implied_predicates_of(def_id); + tcx.at(it.span).explicit_super_predicates_of(def_id); tcx.ensure().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { @@ -1459,8 +1459,25 @@ fn infer_return_ty_for_fn_sig<'tcx>( Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. + // This is a heuristic approach. If the scope has region paramters, + // we should change fn_sig's lifetime from `ReErased` to `ReError`, + // otherwise to `ReStatic`. + let has_region_params = generics.params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }); let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r { - ty::ReErased => tcx.lifetimes.re_static, + ty::ReErased => { + if has_region_params { + ty::Region::new_error_with_message( + tcx, + DUMMY_SP, + "erased region is not allowed here in return type", + ) + } else { + tcx.lifetimes.re_static + } + } _ => r, }); @@ -1638,44 +1655,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); - impl_ - .of_trait - .as_ref() - .map(|hir_trait_ref| { - let self_ty = tcx.type_of(def_id).instantiate_identity(); + impl_.of_trait.as_ref().map(|ast_trait_ref| { + let selfty = tcx.type_of(def_id).instantiate_identity(); - let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( - tcx, - tcx.is_const_trait_impl_raw(def_id.to_def_id()), - hir_trait_ref, - ) { - // we have a const impl, but for a trait without `#[const_trait]`, so - // without the host param. If we continue with the HIR trait ref, we get - // ICEs for generic arg count mismatch. We do a little HIR editing to - // make HIR ty lowering happy. - let mut path_segments = hir_trait_ref.path.segments.to_vec(); - let last_segment = path_segments.len() - 1; - let mut args = *path_segments[last_segment].args(); - let last_arg = args.args.len() - 1; - assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects)); - args.args = &args.args[..args.args.len() - 1]; - path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args)); - let path = hir::Path { - span: hir_trait_ref.path.span, - res: hir_trait_ref.path.res, - segments: tcx.hir_arena.alloc_slice(&path_segments), - }; - let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id }); - icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty) - } else { - icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty) - }; - ty::ImplTraitHeader { - trait_ref: ty::EarlyBinder::bind(trait_ref), - safety: impl_.safety, - polarity: polarity_of_impl(tcx, def_id, impl_, item.span) - } - }) + check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref); + + let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty); + + ty::ImplTraitHeader { + trait_ref: ty::EarlyBinder::bind(trait_ref), + safety: impl_.safety, + polarity: polarity_of_impl(tcx, def_id, impl_, item.span), + } + }) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 85e1c600d6d..c73d3a5390d 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,5 +1,7 @@ use rustc_hir::def::DefKind; -use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::intravisit; +use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::TyCtxt; use rustc_span::sym; @@ -41,3 +43,49 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { } } } + +pub(crate) fn def_parents(tcx: TyCtxt<'_>) { + for did in tcx.hir().body_owners() { + if tcx.has_attr(did, sym::rustc_dump_def_parents) { + struct AnonConstFinder<'tcx> { + tcx: TyCtxt<'tcx>, + anon_consts: Vec<LocalDefId>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) { + self.anon_consts.push(c.def_id); + intravisit::walk_anon_const(self, c) + } + } + + // Look for any anon consts inside of this body owner as there is no way to apply + // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible + // to see what its def parent is. + let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] }; + intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value); + + for did in [did].into_iter().chain(anon_ct_finder.anon_consts) { + let span = tcx.def_span(did); + + let mut diag = tcx.dcx().struct_span_err( + span, + format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()), + ); + + let mut current_did = did.to_def_id(); + while let Some(parent_did) = tcx.opt_parent(current_did) { + current_did = parent_did; + diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}")); + } + diag.emit(); + } + } + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 303fa23dbc1..9b02c1a61fa 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -354,7 +354,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { ty: _, default, is_host_effect } => { + GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() // `host` effect params are allowed to have defaults. @@ -388,6 +388,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), is_host_effect, + synthetic, }, }) } @@ -541,7 +542,8 @@ struct AnonConstInParamTyDetector { impl<'v> Visitor<'v> for AnonConstInParamTyDetector { fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind + { let prev = self.in_param_ty; self.in_param_ty = true; self.visit_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d084d3aefeb..c03e074c80b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFold use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_type_ir::Upcast; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -46,7 +47,7 @@ fn associated_type_bounds<'tcx>( } }); - let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); + let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), @@ -75,7 +76,7 @@ fn opaque_type_bounds<'tcx>( icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span); debug!(?bounds); - tcx.arena.alloc_from_iter(bounds.clauses()) + tcx.arena.alloc_from_iter(bounds.clauses(tcx)) }) } @@ -124,6 +125,32 @@ pub(super) fn explicit_item_bounds_with_filter( None => {} } + if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) { + let mut predicates = Vec::new(); + + let parent = tcx.local_parent(def_id); + + let preds = tcx.explicit_predicates_of(parent); + + if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { + // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` + let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); + // FIXME(effects) span + let span = tcx.def_span(def_id); + let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); + let proj = Ty::new_projection(tcx, assoc, [tup]); + let self_proj = Ty::new_projection( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span)); + let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates)); + } + let bounds = match tcx.hir_node_by_def_id(def_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 3421c8da4e9..b89d034fc2e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -57,6 +57,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic #[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + use rustc_middle::ty::Ty; match tcx.opt_rpitit_info(def_id.to_def_id()) { Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => { @@ -84,6 +85,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(tcx.parent(def_id.to_def_id())), predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: ty::List::empty(), }; } @@ -105,6 +107,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen return ty::GenericPredicates { parent: Some(impl_def_id), predicates: tcx.arena.alloc_from_iter(impl_predicates), + effects_min_tys: ty::List::empty(), }; } @@ -124,6 +127,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); + let mut effects_min_tys = Vec::new(); let hir_generics = node.generics().unwrap_or(NO_GENERICS); if let Node::Item(item) = node { @@ -150,11 +154,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - predicates.extend( - icx.lowerer() - .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) - .clauses(), + let bounds = icx.lowerer().lower_mono_bounds( + tcx.types.self_param, + self_bounds, + PredicateFilter::All, ); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } // In default impls, we can assume that the self type implements @@ -187,7 +193,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen param.span, ); trace!(?bounds); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); trace!(?predicates); } hir::GenericParamKind::Const { .. } => { @@ -238,7 +244,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bound_vars, OnlySelfBounds(false), ); - predicates.extend(bounds.clauses()); + predicates.extend(bounds.clauses(tcx)); + effects_min_tys.extend(bounds.effects_min_tys()); } hir::WherePredicate::RegionPredicate(region_pred) => { @@ -297,7 +304,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else { + let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node + else { bug!("unexpected {opaque_ty_node:?}") }; debug!(?lifetimes); @@ -306,9 +314,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen debug!(?predicates); } + // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called + // in const contexts. + if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node + && let Some(host_effect_index) = generics.host_effect_index + { + let parent = generics.parent.unwrap(); + let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else { + bug!("associated_type_for_effects returned None when there is host effect in generics"); + }; + let effects = + Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent)); + let param = generics.param_at(host_effect_index, tcx); + let span = tcx.def_span(param.def_id); + let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param)); + let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span)); + let trait_ref = + ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]); + predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); + } + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), + effects_min_tys: tcx.mk_type_list(&effects_min_tys), } } @@ -459,6 +488,7 @@ pub(super) fn explicit_predicates_of<'tcx>( ty::GenericPredicates { parent: predicates_and_bounds.parent, predicates: tcx.arena.alloc_slice(&predicates), + effects_min_tys: predicates_and_bounds.effects_min_tys, } } } else { @@ -510,6 +540,7 @@ pub(super) fn explicit_predicates_of<'tcx>( return GenericPredicates { parent: parent_preds.parent, predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, + effects_min_tys: parent_preds.effects_min_tys, }; } gather_explicit_predicates_of(tcx, def_id) @@ -519,21 +550,21 @@ pub(super) fn explicit_predicates_of<'tcx>( /// Ensures that the super-predicates of the trait with a `DefId` /// of `trait_def_id` are lowered and stored. This also ensures that /// the transitive super-predicates are lowered. -pub(super) fn super_predicates_of( +pub(super) fn explicit_super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly) } -pub(super) fn super_predicates_that_define_assoc_item( +pub(super) fn explicit_supertraits_containing_assoc_item( tcx: TyCtxt<'_>, (trait_def_id, assoc_name): (DefId, Ident), ) -> ty::GenericPredicates<'_> { implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name)) } -pub(super) fn implied_predicates_of( +pub(super) fn explicit_implied_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, ) -> ty::GenericPredicates<'_> { @@ -560,7 +591,7 @@ pub(super) fn implied_predicates_with_filter( // if `assoc_name` is None, then the query should've been redirected to an // external provider assert!(matches!(filter, PredicateFilter::SelfThatDefines(_))); - return tcx.super_predicates_of(trait_def_id); + return tcx.explicit_super_predicates_of(trait_def_id); }; let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else { @@ -587,7 +618,7 @@ pub(super) fn implied_predicates_with_filter( // Combine the two lists to form the complete set of superbounds: let implied_bounds = - &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); + &*tcx.arena.alloc_from_iter(superbounds.clauses(tcx).chain(where_bounds_that_match)); debug!(?implied_bounds); // Now require that immediate supertraits are lowered, which will, in @@ -601,7 +632,7 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).super_predicates_of(bound.def_id()); + tcx.at(span).explicit_super_predicates_of(bound.def_id()); } } } @@ -611,14 +642,18 @@ pub(super) fn implied_predicates_with_filter( if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() && bound.polarity == ty::PredicatePolarity::Positive { - tcx.at(span).implied_predicates_of(bound.def_id()); + tcx.at(span).explicit_implied_predicates_of(bound.def_id()); } } } _ => {} } - ty::GenericPredicates { parent: None, predicates: implied_bounds } + ty::GenericPredicates { + parent: None, + predicates: implied_bounds, + effects_min_tys: ty::List::empty(), + } } /// Returns the predicates defined on `item_def_id` of the form @@ -744,7 +779,7 @@ impl<'tcx> ItemCtxt<'tcx> { ); } - bounds.clauses().collect() + bounds.clauses(self.tcx).collect() } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index abc3bb838db..cad7870a0a1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.visit_ty(ty); } } - GenericParamKind::Const { ty, default, is_host_effect: _ } => { + GenericParamKind::Const { ty, default, .. } => { self.visit_ty(ty); if let Some(default) = default { self.visit_body(self.tcx.hir().body(default.body)); @@ -1760,7 +1760,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(assoc_item) = trait_defines_associated_item_named(def_id) { break Some((bound_vars.into_iter().collect(), assoc_item)); } - let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name)); + let predicates = tcx.explicit_supertraits_containing_assoc_item((def_id, assoc_name)); let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 44025c3cd61..3ffb51fa992 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1699,3 +1699,9 @@ pub struct InvalidReceiverTy<'tcx> { pub span: Span, pub receiver_ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_effects_without_next_solver)] +#[note] +#[help] +pub struct EffectsWithoutNextSolver; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 3f888c4e272..e92c377f0ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -256,6 +256,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( | GenericParamDefKind::Lifetime, _, ) => { + // FIXME(effects): this should be removed // SPECIAL CASE FOR DESUGARED EFFECT PARAMS // This comes from the following example: // @@ -445,7 +446,7 @@ pub(crate) fn check_generic_arg_count( .own_params .iter() .filter(|param| { - matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) + matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. }) }) .count(); let named_const_param_count = param_counts.consts - synth_const_param_count; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 24ea328889c..2a68d3915bb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -698,7 +698,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); debug!(?poly_trait_ref); - bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); + bounds.push_trait_bound( + tcx, + self.item_def_id().to_def_id(), + poly_trait_ref, + span, + polarity, + constness, + ); let mut dup_constraints = FxIndexMap::default(); for constraint in trait_segment.args().constraints { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 34924f09d09..df69c1938dd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -59,7 +59,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { + for (pred, span) in bounds.clauses(tcx) { let bound_pred = pred.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { @@ -133,7 +133,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| !item.is_impl_trait_in_trait()) + .filter(|item| { + !item.is_impl_trait_in_trait() && !item.is_effects_desugaring + }) .map(|item| item.def_id), ); } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 0428abcdf24..44f1830a3b1 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -151,6 +151,12 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); + // FIXME(effects): remove once effects is implemented in old trait solver + // or if the next solver is stabilized. + if tcx.features().effects && !tcx.next_trait_solver_globally() { + tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); + } + tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { let _ = tcx.ensure().check_mod_type_wf(module); @@ -169,6 +175,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); collect::dump::opaque_hidden_types(tcx); collect::dump::predicates_and_item_bounds(tcx); + collect::dump::def_parents(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 25b0cbdc026..5105d60ae18 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -585,6 +585,7 @@ impl<'a> State<'a> { self.print_struct(struct_def, generics, item.ident.name, item.span, true); } hir::ItemKind::Impl(&hir::Impl { + constness, safety, polarity, defaultness, @@ -599,6 +600,10 @@ impl<'a> State<'a> { self.print_safety(safety); self.word_nbsp("impl"); + if let hir::Constness::Const = constness { + self.word_nbsp("const"); + } + if !generics.params.is_empty() { self.print_generic_params(generics.params); self.space(); @@ -2144,7 +2149,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default, is_host_effect: _ } => { + GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 92f2d3254bb..cb1a412d17e 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -319,7 +319,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { errors::CannotCastToBoolHelp::Unsupported(self.span) }; - fcx.tcx.dcx().emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help }); + fcx.dcx().emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help }); } CastError::CastToChar => { let mut err = type_error_struct!( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 0551b9bc1f0..f72e8a4afde 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1797,16 +1797,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }); } - fn report_return_mismatched_types<'a>( + fn report_return_mismatched_types<'infcx>( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ty_err: TypeError<'tcx>, - fcx: &FnCtxt<'a, 'tcx>, + fcx: &'infcx FnCtxt<'_, 'tcx>, block_or_return_id: hir::HirId, expression: Option<&'tcx hir::Expr<'tcx>>, - ) -> Diag<'a> { + ) -> Diag<'infcx> { let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..)); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f9720c9c307..ad9c1e28211 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -172,21 +172,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn demand_suptype_diag( - &self, + &'a self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'a>> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } #[instrument(skip(self), level = "debug")] pub fn demand_suptype_with_origin( - &self, + &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'a>> { self.at(cause, self.param_env) .sup(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) @@ -200,20 +200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn demand_eqtype_diag( - &self, + &'a self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'a>> { self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } pub fn demand_eqtype_with_origin( - &self, + &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'a>> { self.at(cause, self.param_env) .eq(DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) @@ -247,13 +247,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// will be permitted if the diverges flag is currently "always". #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] pub fn demand_coerce_diag( - &self, + &'a self, mut expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, - ) -> Result<Ty<'tcx>, Diag<'tcx>> { + ) -> Result<Ty<'tcx>, Diag<'a>> { let expected = self.resolve_vars_with_obligations(expected); let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f4e1e461953..2fbc8a3f146 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -638,7 +638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Set expectation to error in that case and set tainted // by error (#114529) let coerce_to = opt_coerce_to.unwrap_or_else(|| { - let guar = tcx.dcx().span_delayed_bug( + let guar = self.dcx().span_delayed_bug( expr.span, "illegal break with value found but no error reported", ); @@ -1716,7 +1716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { error_happened = true; let guar = if let Some(prev_span) = seen_fields.get(&ident) { - tcx.dcx().emit_err(FieldMultiplySpecifiedInInitializer { + self.dcx().emit_err(FieldMultiplySpecifiedInInitializer { span: field.ident.span, prev_span: *prev_span, ident, @@ -1757,7 +1757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if adt_kind == AdtKind::Union { if hir_fields.len() != 1 { struct_span_code_err!( - tcx.dcx(), + self.dcx(), span, E0784, "union expressions should have exactly one field", diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 0ba4bd090f5..9a353bfe49d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -170,7 +170,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { } fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error { - self.tcx.dcx().span_delayed_bug(span, msg.to_string()) + self.dcx().span_delayed_bug(span, msg.to_string()) } fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 061afd03062..5450243417f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1182,7 +1182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { name: self.tcx.item_name(def.did()).to_ident_string(), }); if ty.raw.has_param() { - let guar = self.tcx.dcx().emit_err(errors::SelfCtorFromOuterItem { + let guar = self.dcx().emit_err(errors::SelfCtorFromOuterItem { span: path_span, impl_span: tcx.def_span(impl_def_id), sugg, @@ -1207,7 +1207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check the visibility of the ctor. let vis = tcx.visibility(ctor_def_id); if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { - tcx.dcx() + self.dcx() .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); @@ -1216,7 +1216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (new_res, Some(user_args.args)) } _ => { - let mut err = tcx.dcx().struct_span_err( + let mut err = self.dcx().struct_span_err( span, "the `Self` constructor can only be used with tuple or unit structs", ); @@ -1304,7 +1304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.ty_infer(Some(param), inf.span).into() } ( - &GenericParamDefKind::Const { has_default, is_host_effect }, + &GenericParamDefKind::Const { has_default, is_host_effect, .. }, GenericArg::Infer(inf), ) => { if has_default && is_host_effect { @@ -1346,7 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.var_for_def(self.span, param) } } - GenericParamDefKind::Const { has_default, is_host_effect } => { + GenericParamDefKind::Const { has_default, is_host_effect, .. } => { if has_default { // N.B. this is a bit of a hack. `infer_args` is passed depending on // whether the user has provided generic args. E.g. for `Vec::new` diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 1138642c56d..c6d72700b3f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Otherwise, there's a mismatch, so clear out what we're expecting, and set // our input types to err_args so we don't blow up the error messages let guar = struct_span_code_err!( - tcx.dcx(), + self.dcx(), call_span, E0059, "cannot use call notation; the first type parameter \ @@ -453,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|vars| self.resolve_vars_if_possible(vars)), ); - self.set_tainted_by_errors(self.report_arg_errors( + self.report_arg_errors( compatibility_diagonal, formal_and_expected_inputs, provided_args, @@ -462,7 +462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id, call_span, call_expr, - )); + ); } } @@ -788,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {call_name} are incorrect"), ); } else { - err = tcx.dcx().struct_span_err( + err = self.dcx().struct_span_err( full_call_span, format!( "{call_name} takes {}{} but {} {} supplied", @@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(error_span, "expected errors from argument matrix"); } else { let mut err = - tcx.dcx().create_err(errors::ArgMismatchIndeterminate { span: error_span }); + self.dcx().create_err(errors::ArgMismatchIndeterminate { span: error_span }); suggest_confusable(&mut err); return err.emit(); } @@ -951,16 +951,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return err.emit(); } + // Special case, we found an extra argument is provided, which is very common in practice. + // but there is a obviously better removing suggestion compared to the current one, + // try to find the argument with Error type, if we removed it all the types will become good, + // then we will replace the current suggestion. + if let [Error::Extra(provided_idx)] = &errors[..] { + let remove_idx_is_perfect = |idx: usize| -> bool { + let removed_arg_tys = provided_arg_tys + .iter() + .enumerate() + .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) + .collect::<IndexVec<ProvidedIdx, _>>(); + std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( + |((expected_ty, _), (provided_ty, _))| { + !provided_ty.references_error() + && self.can_coerce(*provided_ty, *expected_ty) + }, + ) + }; + + if !remove_idx_is_perfect(provided_idx.as_usize()) { + if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) { + errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; + } + } + } + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { struct_span_code_err!( - tcx.dcx(), + self.dcx(), full_call_span, E0308, "arguments to this {} are incorrect", call_name, ) } else { - tcx.dcx() + self.dcx() .struct_span_err( full_call_span, format!( @@ -1424,7 +1450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, provided_ty: Ty<'tcx>, arg: &hir::Expr<'tcx>, - err: &mut Diag<'tcx>, + err: &mut Diag<'_>, ) { if let ty::RawPtr(_, hir::Mutability::Mut) = expected_ty.kind() && let ty::RawPtr(_, hir::Mutability::Not) = provided_ty.kind() @@ -2042,7 +2068,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if block_num > 1 && found_semi { err.span_suggestion_verbose( - span.shrink_to_lo(), + // use the span of the *whole* expr + self.tcx.hir().span(binding_hir_id).shrink_to_lo(), "you might have meant to return this to infer its type parameters", "return ", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index c0d60477967..da68da029b4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -144,8 +144,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { - self.infcx.dcx() + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> { + self.root_ctxt.infcx.dcx() } pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { @@ -274,6 +274,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { } }), ), + effects_min_tys: ty::List::empty(), } } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 5eafc60a04e..0389c06c312 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Note: this path is currently not reached in any test, so any // example that triggers this would be worth minimizing and // converting into a test. - tcx.dcx().span_bug(span, "argument to transmute has inference variables"); + self.dcx().span_bug(span, "argument to transmute has inference variables"); } // Transmutes that are only changing lifetimes are always ok. if from == to { @@ -76,7 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { - struct_span_code_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type") + struct_span_code_err!(self.dcx(), span, E0591, "can't transmute zero-sized type") .with_note(format!("source type: {from}")) .with_note(format!("target type: {to}")) .with_help("cast with `as` to a pointer instead") @@ -116,7 +116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), span, E0512, "cannot transmute between types of different sizes, \ diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e1223307b53..ff8899ae036 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, NormalizeExt}; @@ -356,6 +356,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { let (obligation, args) = self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); + // FIXME(effects) find a better way to do this + // Operators don't have generic methods, but making them `#[const_trait]` gives them + // `const host: bool`. + let args = if self.tcx.has_attr(trait_def_id, sym::const_trait) { + self.tcx.mk_args_from_iter( + args.iter() + .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]), + ) + } else { + args + }; self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) } @@ -393,6 +404,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); let mut obligations = vec![]; + // FIXME(effects): revisit when binops get `#[const_trait]` + // Instantiate late-bound regions and instantiate the trait // parameters into the method type to get the actual method type. // diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9747a91ccbf..63b30d79aba 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1279,6 +1279,7 @@ impl<'tcx> Pick<'tcx> { trait_item_def_id: _, fn_has_self_parameter: _, opt_rpitit_info: _, + is_effects_desugaring: _, }, kind: _, import_ids: _, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a385bc70e35..e310730bf9e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -705,7 +705,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source { self.suggest_missing_writer(rcvr_ty, rcvr_expr) } else { - let mut err = tcx.dcx().create_err(NoAssociatedItem { + let mut err = self.dcx().create_err(NoAssociatedItem { span, item_kind, item_name, @@ -1194,7 +1194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - tcx.dcx().span_delayed_bug( + self.dcx().span_delayed_bug( *item_span, "auto trait is invoked with no method error, but no error reported?", ); @@ -2361,7 +2361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - return Err(tcx.dcx().emit_err(errors::MissingParenthesesInRange { + return Err(self.dcx().emit_err(errors::MissingParenthesesInRange { span, ty_str: ty_str.to_string(), method_name: item_name.as_str().to_string(), @@ -2420,7 +2420,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let SelfSource::MethodCall(expr) = source { let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), span, E0689, "can't call {} `{}` on ambiguous numeric type `{}`", diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index aaf3d3ec34d..f932a27e9a2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -89,7 +89,7 @@ struct PatInfo<'tcx, 'a> { current_depth: u32, } -impl<'tcx> FnCtxt<'_, 'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { let code = ObligationCauseCode::Pattern { span: ti.span, @@ -100,12 +100,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } fn demand_eqtype_pat_diag( - &self, + &'a self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, - ) -> Result<(), Diag<'tcx>> { + ) -> Result<(), Diag<'a>> { self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual) .map_err(|mut diag| { if let Some(expr) = ti.origin_expr { @@ -698,7 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl { let mut err = struct_span_code_err!( - self.tcx.dcx(), + self.dcx(), ident.span, E0596, "cannot borrow as mutable inside an `&` pattern" @@ -1010,7 +1010,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = path_resolution; match res { Res::Err => { - let e = tcx.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); + let e = + self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); return Ty::new_error(tcx, e); } @@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { - let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); + let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); on_error(e); return Ty::new_error(tcx, e); @@ -1207,7 +1208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match res { Res::Err => { - tcx.dcx().span_bug(pat.span, "`Res::Err` but no error emitted"); + self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted"); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { let e = report_unexpected_res(res); @@ -1549,10 +1550,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Report an error if an incorrect number of fields was specified. if adt.is_union() { if fields.len() != 1 { - tcx.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span }); + self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span }); } if has_rest_pat { - tcx.dcx().emit_err(errors::UnionPatDotDot { span: pat.span }); + self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span }); } } else if !unmentioned_fields.is_empty() { let accessible_unmentioned_fields: Vec<_> = unmentioned_fields @@ -1690,7 +1691,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, variant: &ty::VariantDef, args: ty::GenericArgsRef<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let tcx = self.tcx; let (field_names, t, plural) = if let [field] = inexistent_fields { (format!("a field named `{}`", field.ident), "this", "") @@ -1710,7 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>(); let mut err = struct_span_code_err!( - tcx.dcx(), + self.dcx(), spans, E0026, "{} `{}` does not have {}", @@ -1881,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], - ) -> Diag<'tcx> { + ) -> Diag<'a> { let mut err = self .dcx() .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); @@ -1973,7 +1974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &[(&ty::FieldDef, Ident)], have_inaccessible_fields: bool, fields: &'tcx [hir::PatField<'tcx>], - ) -> Diag<'tcx> { + ) -> Diag<'a> { let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; let field_names = if let [(_, field)] = unmentioned_fields { format!("field `{field}`{inaccessible}") diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 227691d0994..a8fd3ca8c59 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -139,7 +139,7 @@ pub struct TypeErrCtxt<'a, 'tcx> { } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { + pub fn dcx(&self) -> DiagCtxtHandle<'a> { self.infcx.dcx() } @@ -305,16 +305,17 @@ fn label_msg_span( } } -#[instrument(level = "trace", skip(tcx))] -pub fn unexpected_hidden_region_diagnostic<'tcx>( - tcx: TyCtxt<'tcx>, +#[instrument(level = "trace", skip(infcx))] +pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( + infcx: &'a InferCtxt<'tcx>, generic_param_scope: LocalDefId, span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, opaque_ty_key: ty::OpaqueTypeKey<'tcx>, -) -> Diag<'tcx> { - let mut err = tcx.dcx().create_err(errors::OpaqueCapturesLifetime { +) -> Diag<'a> { + let tcx = infcx.tcx; + let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime { span, opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args), opaque_ty_span: tcx.def_span(opaque_ty_key.def_id), @@ -436,7 +437,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_region_errors( &self, generic_param_scope: LocalDefId, @@ -2206,7 +2207,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trace: TypeTrace<'tcx>, terr: TypeError<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span(); @@ -2215,7 +2216,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span, self.type_error_additional_suggestions(&trace, terr), ); - let mut diag = self.tcx.dcx().create_err(failure_code); + let mut diag = self.dcx().create_err(failure_code); self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false); diag } @@ -2357,14 +2358,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { origin: Option<SubregionOrigin<'tcx>>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { if let Some(SubregionOrigin::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id, }) = origin { - return self.report_extra_impl_obligation( + return self.infcx.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, @@ -2790,7 +2791,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> { } impl<'tcx> InferCtxt<'tcx> { - fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'tcx> { + fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BrNamed(_, name) => name.to_string(), @@ -2829,7 +2830,7 @@ impl<'tcx> InferCtxt<'tcx> { }; struct_span_code_err!( - self.tcx.dcx(), + self.dcx(), var_origin.span(), E0495, "cannot infer an appropriate lifetime{} due to conflicting requirements", diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index d7349abc44c..084aebc296f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, - ) -> Diag<'tcx> { + ) -> Diag<'_> { let source_kind = "other"; let source_name = ""; let failure_span = None; @@ -436,7 +436,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, @@ -445,7 +445,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, should_label_span: bool, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); @@ -453,7 +453,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If we don't have any typeck results we're outside // of a body, so we won't be able to get better info // here. - return self.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); }; let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); @@ -465,7 +465,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); }; let (source_kind, name, path) = kind.ty_localized_msg(self); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8fd19563c30..d1fc9c9f140 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { @@ -79,7 +79,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let mut err = match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); @@ -245,7 +245,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.report_extra_impl_obligation( + let mut err = self.infcx.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, @@ -378,7 +378,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a3cf588da1c..ff593d7ffb7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -684,8 +684,8 @@ impl<'tcx> InferOk<'tcx, ()> { } impl<'tcx> InferCtxt<'tcx> { - pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { - self.tcx.dcx() + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.tcx.dcx().taintable_handle(&self.tainted_by_errors) } pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { @@ -1089,19 +1089,7 @@ impl<'tcx> InferCtxt<'tcx> { /// inference variables, regionck errors). #[must_use = "this method does not have any side effects"] pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { - if let Some(guar) = self.tainted_by_errors.get() { - Some(guar) - } else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation { - // Errors reported since this infcx was made. Lint errors are - // excluded to avoid some being swallowed in the presence of - // non-lint errors. (It's arguable whether or not this exclusion is - // important.) - let guar = self.dcx().has_errors().unwrap(); - self.set_tainted_by_errors(guar); - Some(guar) - } else { - None - } + self.tainted_by_errors.get() } /// Set the "tainted by errors" flag to true. We call this when we @@ -1328,8 +1316,7 @@ impl<'tcx> InferCtxt<'tcx> { bug!("`{value:?}` is not fully resolved"); } if value.has_infer_regions() { - let guar = - self.tcx.dcx().delayed_bug(format!("`{value:?}` is not fully resolved")); + let guar = self.dcx().delayed_bug(format!("`{value:?}` is not fully resolved")); Ok(self.tcx.fold_regions(value, |re, _| { if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re } })) @@ -1607,7 +1594,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // [Note-Type-error-reporting] // An invariant is that anytime the expected or actual type is Error (the special // error type, meaning that an error occurred when typechecking this expression), @@ -1623,9 +1610,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { sp: Span, mk_diag: M, actual_ty: Ty<'tcx>, - ) -> Diag<'tcx> + ) -> Diag<'a> where - M: FnOnce(String) -> Diag<'tcx>, + M: FnOnce(String) -> Diag<'a>, { let actual_ty = self.resolve_vars_if_possible(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); @@ -1646,7 +1633,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } @@ -1656,7 +1643,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected: ty::Const<'tcx>, actual: ty::Const<'tcx>, err: TypeError<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index b8dd501a721..7c764cccc47 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -156,7 +156,7 @@ impl<'tcx> InferCtxt<'tcx> { if self.can_define_opaque_ty(b_def_id) && self.tcx.is_type_alias_impl_trait(b_def_id) { - self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag { + self.dcx().emit_err(OpaqueHiddenTypeDiag { span, hidden_type: self.tcx.def_span(b_def_id), opaque_type: self.tcx.def_span(def_id), diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 890e25368bc..7730fe29e09 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -12,15 +12,15 @@ use std::fmt; use std::iter; impl<'tcx> InferCtxt<'tcx> { - pub fn report_extra_impl_obligation( - &self, + pub fn report_extra_impl_obligation<'a>( + &'a self, error_span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId, requirement: &dyn fmt::Display, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let mut err = struct_span_code_err!( - self.tcx.dcx(), + self.dcx(), error_span, E0276, "impl has stricter requirements than trait" diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index ab4148faaab..24cf9f03fcd 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -275,10 +275,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { } // Get predicates implied by the trait, or only super predicates if we only care about self predicates. let predicates = match self.mode { - Filter::All => tcx.implied_predicates_of(data.def_id()), - Filter::OnlySelf => tcx.super_predicates_of(data.def_id()), + Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), + Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), Filter::OnlySelfThatDefines(ident) => { - tcx.super_predicates_that_define_assoc_item((data.def_id(), ident)) + tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) } }; @@ -420,7 +420,7 @@ pub fn transitive_bounds<'tcx>( /// A specialized variant of `elaborate` that only elaborates trait references that may /// define the given associated item with the name `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that +/// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). pub fn transitive_bounds_that_define_assoc_item<'tcx>( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 02322c9b282..9bd67a1154b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -2,14 +2,22 @@ use crate::interface::{initialize_checked_jobserver, parse_cfg}; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; +use rustc_session::config::{build_configuration, build_session_options, rustc_optgroups}; use rustc_session::config::{ - build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, - CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, - ErrorOutputType, ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, - Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, - LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, - PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, - SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, + DebugInfo, DumpMonoStatsFormat, ErrorOutputType, +}; +use rustc_session::config::{ + ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, + InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, +}; +use rustc_session::config::{ + LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, + OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, +}; +use rustc_session::config::{ + Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 46cf87d1e3c..3e952558d29 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -56,8 +56,6 @@ lint_builtin_asm_labels = avoid using named labels in inline assembly .help = only local labels of the form `<number>:` should be used in inline asm .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 -lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} - lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 98318cd14d9..79c8046f9b7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -24,9 +24,9 @@ use crate::fluent_generated as fluent; use crate::{ errors::BuiltinEllipsisInclusiveRangePatterns, lints::{ - BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle, - BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, - BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, + BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, + BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, + BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, @@ -56,7 +56,6 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::Upcast; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; @@ -135,80 +134,6 @@ impl EarlyLintPass for WhileTrue { } declare_lint! { - /// The `box_pointers` lints use of the Box type. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(box_pointers)] - /// struct Foo { - /// x: Box<i32>, - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is mostly historical, and not particularly useful. `Box<T>` - /// used to be built into the language, and the only way to do heap - /// allocation. Today's Rust can call into other allocators, etc. - BOX_POINTERS, - Allow, - "use of owned (Box type) heap memory" -} - -declare_lint_pass!(BoxPointers => [BOX_POINTERS]); - -impl BoxPointers { - fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { - for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() - && leaf_ty.is_box() - { - cx.emit_span_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); - } - } - } -} - -impl<'tcx> LateLintPass<'tcx> for BoxPointers { - fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - match it.kind { - hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) => self.check_heap_type( - cx, - it.span, - cx.tcx.type_of(it.owner_id).instantiate_identity(), - ), - _ => (), - } - - // If it's a struct, we also have to check the fields' types - match it.kind { - hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - for field in struct_def.fields() { - self.check_heap_type( - cx, - field.span, - cx.tcx.type_of(field.def_id).instantiate_identity(), - ); - } - } - _ => (), - } - } - - fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { - let ty = cx.typeck_results().node_type(e.hir_id); - self.check_heap_type(cx, e.span, ty); - } -} - -declare_lint! { /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }` /// instead of `Struct { x }` in a pattern. /// @@ -1640,7 +1565,6 @@ declare_lint_pass!( /// which are used by other parts of the compiler. SoftLints => [ WHILE_TRUE, - BOX_POINTERS, NON_SHORTHAND_FIELD_PATTERNS, UNSAFE_CODE, MISSING_DOCS, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7dae2de7bfb..17f9d4421ae 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -187,7 +187,6 @@ late_lint_methods!( ImproperCTypesDefinitions: ImproperCTypesDefinitions, InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, - BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, InvalidReferenceCasting: InvalidReferenceCasting, @@ -551,6 +550,10 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see RFC #3535 \ <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information", ); + store.register_removed( + "box_pointers", + "it does not detect other kinds of allocations, and existed only for historical reasons", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 14084405d0e..7c5640f5959 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -67,12 +67,6 @@ pub struct BuiltinWhileTrue { } #[derive(LintDiagnostic)] -#[diag(lint_builtin_box_pointers)] -pub struct BuiltinBoxPointers<'a> { - pub ty: Ty<'a>, -} - -#[derive(LintDiagnostic)] #[diag(lint_builtin_non_shorthand_field_patterns)] pub struct BuiltinNonShorthandFieldPatterns { pub ident: Ident, diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index aa1d94228ea..445dcd41e5d 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { { let direct_super_traits_iter = cx .tcx - .super_predicates_of(def_id) + .explicit_super_predicates_of(def_id) .predicates .into_iter() .filter_map(|(pred, _)| pred.as_trait_clause()); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 300dac442d5..17429ed061f 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -50,7 +50,7 @@ declare_lint! { /// All nested bodies (functions, enum discriminant, array length, consts) (expect for /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. pub NON_LOCAL_DEFINITIONS, - Warn, + Allow, "checks for non-local definitions", report_in_external_macro } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 472e93d202d..2ade6964ca8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -74,6 +74,7 @@ declare_lint_pass! { NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, ORDER_DEPENDENT_TRAIT_OBJECTS, + OUT_OF_SCOPE_MACRO_CALLS, OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, PRIVATE_BOUNDS, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index ea7037740f1..83b41e0540e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1348,7 +1348,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { + let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() + || self.root.tables.is_effects_desugaring.get(self, id) + { kw::Empty } else { self.item_name(id) @@ -1371,6 +1373,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { container, fn_has_self_parameter: has_self, opt_rpitit_info, + is_effects_desugaring: self.root.tables.is_effects_desugaring.get(self, id), } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c9450142cd3..6b240f0f0b3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -211,8 +211,8 @@ provide! { tcx, def_id, other, cdata, explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } - super_predicates_of => { table } - implied_predicates_of => { table } + explicit_super_predicates_of => { table } + explicit_implied_predicates_of => { table } type_of => { table } type_alias_is_lazy => { cdata.root.tables.type_alias_is_lazy.get(cdata, def_id.index) } variances_of => { table } @@ -279,6 +279,9 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } + associated_type_for_effects => { + table + } associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array } visibility => { cdata.get_visibility(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4bd2ec09a6e..209316ca20f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1431,8 +1431,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::Trait = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); let module_children = self.tcx.module_children_local(local_id); record_array!(self.tables.module_children_non_reexports[def_id] <- @@ -1440,8 +1440,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::TraitAlias = def_kind { record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); - record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); - record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id)); + record!(self.tables.explicit_super_predicates_of[def_id] <- self.tcx.explicit_super_predicates_of(def_id)); + record!(self.tables.explicit_implied_predicates_of[def_id] <- self.tcx.explicit_implied_predicates_of(def_id)); } if let DefKind::Trait | DefKind::Impl { .. } = def_kind { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); @@ -1454,6 +1454,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for &def_id in associated_item_def_ids { self.encode_info_for_assoc_item(def_id); } + if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) { + record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id); + } } if def_kind == DefKind::Closure && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) @@ -1634,6 +1637,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ); } } + if item.is_effects_desugaring { + self.tables.is_effects_desugaring.set(def_id.index, true); + } } fn encode_mir(&mut self) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 87900c23d8d..2a44b3423ae 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -391,7 +391,9 @@ define_tables! { inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, + associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, + is_effects_desugaring: Table<DefIndex, bool>, unused_generic_params: Table<DefIndex, UnusedGenericParams>, // Reexported names are not associated with individual `DefId`s, // e.g. a glob import can introduce a lot of names, all with the same `DefId`. @@ -416,10 +418,10 @@ define_tables! { lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>, explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, generics_of: Table<DefIndex, LazyValue<ty::Generics>>, - super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + explicit_super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, // As an optimization, we only store this for trait aliases, - // since it's identical to super_predicates_of for traits. - implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, + // since it's identical to explicit_super_predicates_of for traits. + explicit_implied_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>, variances_of: Table<DefIndex, LazyArray<ty::Variance>>, fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 230a44bcf24..d40a7833589 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -368,6 +368,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// The set of item bounds (see [`TyCtxt::explicit_item_bounds`]) that @@ -378,6 +379,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -646,6 +648,9 @@ rustc_queries! { } /// Returns the predicates written explicitly by the user. + /// + /// You should probably use `predicates_of` unless you're looking for + /// predicates with explicit spans for diagnostics purposes. query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -662,29 +667,32 @@ rustc_queries! { feedable } - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// Maps from the `DefId` of a trait to the list of super-predicates of the trait, + /// *before* elaboration (so it doesn't contain transitive super-predicates). This + /// is a subset of the full list of predicates. We store these in a separate map + /// because we must evaluate them even during type conversion, often before the full + /// predicates are available (note that super-predicates must not be cyclic). + query explicit_super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + /// The predicates of the trait that are implied during elaboration. This is a + /// superset of the super-predicates of the trait, but a subset of the predicates + /// of the trait. For regular traits, this includes all super-predicates and their + /// associated type bounds. For trait aliases, currently, this includes all of the + /// predicates of the trait alias. + query explicit_implied_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the implied predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query - /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the - /// subset of super-predicates that reference traits that define the given associated type. - /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + /// The Ident is the name of an associated type.The query returns only the subset + /// of supertraits that define the given associated type. This is used to avoid + /// cycles in resolving type-dependent associated item paths like `T::Item`. + query explicit_supertraits_containing_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super traits of `{}` with associated type name `{}`", tcx.def_path_str(key.0), key.1 @@ -847,6 +855,12 @@ rustc_queries! { separate_provide_extern } + query associated_type_for_effects(def_id: DefId) -> Option<DefId> { + desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding /// associated item. query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index adbb6cf2ddc..7437be7a74c 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -35,7 +35,7 @@ struct Elaborator<'tcx> { impl<'tcx> Elaborator<'tcx> { fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { let super_predicates = - self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( + self.tcx.explicit_super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { let clause = pred.instantiate_supertrait(self.tcx, trait_ref); self.visited.insert(clause).then_some(clause) diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 1cdde3f057c..820f5e950a9 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -34,6 +34,8 @@ pub struct AssocItem { /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>, + + pub is_effects_desugaring: bool, } impl AssocItem { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4bac9396e59..9225ae6300f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -342,12 +342,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: DefId, ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { ty::EarlyBinder::bind( - self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + self.explicit_super_predicates_of(def_id) + .instantiate_identity(self) + .predicates + .into_iter(), ) } @@ -598,6 +601,11 @@ fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { TraitSolverLangItem::Destruct => LangItem::Destruct, TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, + TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection, + TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput, + TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, + TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, TraitSolverLangItem::Future => LangItem::Future, @@ -2440,7 +2448,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).any(|trait_did| { + self.supertrait_def_ids(trait_def_id).any(|trait_did| { self.associated_items(trait_did) .filter_by_name_unhygienic(assoc_name.name) .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did)) @@ -2463,9 +2471,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { + /// to identify which traits may define a given associated type to help avoid cycle errors, + /// and to make size estimates for vtable layout computation. + pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; @@ -2473,7 +2481,7 @@ impl<'tcx> TyCtxt<'tcx> { iter::from_fn(move || -> Option<DefId> { let trait_did = stack.pop()?; - let generic_predicates = self.super_predicates_of(trait_did); + let generic_predicates = self.explicit_super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { @@ -3095,9 +3103,9 @@ impl<'tcx> TyCtxt<'tcx> { matches!( node, hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), .. - }) if generics.params.iter().any(|p| matches!(p.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })) + }) if matches!(constness, hir::Constness::Const) ) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 6467689a8aa..844023df1e3 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -14,7 +14,7 @@ use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool, is_host_effect: bool }, + Const { has_default: bool, is_host_effect: bool, synthetic: bool }, } impl GenericParamDefKind { @@ -371,6 +371,7 @@ impl<'tcx> Generics { pub struct GenericPredicates<'tcx> { pub parent: Option<DefId>, pub predicates: &'tcx [(Clause<'tcx>, Span)], + pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>, } impl<'tcx> GenericPredicates<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9c2bfc12a18..7d57d88f40f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1608,7 +1608,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// If the def-id is an associated type that was desugared from a + /// If the `def_id` is an associated type that was desugared from a /// return-position `impl Trait` from a trait, then provide the source info /// about where that RPITIT came from. pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> { @@ -1619,6 +1619,16 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Whether the `def_id` is an associated type that was desugared from a + /// `#[const_trait]` or `impl_const`. + pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool { + if let DefKind::AssocTy = self.def_kind(def_id) { + self.associated_item(def_id).is_effects_desugaring + } else { + false + } + } + pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> { variant.fields.iter_enumerated().find_map(|(i, field)| { self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i) diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index dc3c84f9e43..466c3b93f8e 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -3,8 +3,6 @@ use std::fmt; use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::DefId; use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, HashStable)] @@ -42,45 +40,12 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] = &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; - - pub fn supertrait_def_ids(self, trait_def_id: DefId) -> SupertraitDefIds<'tcx> { - SupertraitDefIds { - tcx: self, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } - } } pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<DefId>, - visited: FxHashSet<DefId>, -} - -impl Iterator for SupertraitDefIds<'_> { - type Item = DefId; - - fn next(&mut self) -> Option<DefId> { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.as_trait_clause()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - // Note that we don't have access to a self type here, this has to be purely based on the trait (and // supertrait) definitions. That means we can't call into the same vtable_entries code since that // returns a specific instantiation (e.g., with Vacant slots when bounds aren't satisfied). The goal diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index c1d645aa42c..5ccbd7c59cf 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,3 +1,4 @@ +use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use rustc_middle::middle::region::Scope; @@ -189,38 +190,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[*initializer].span; let scope = (*init_scope, source_info); - let failure = unpack!( - block = this.in_scope(scope, *lint_level, |this| { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - None, - Some((Some(&destination), initializer_span)), - ); - this.visit_primary_bindings( - pattern, - UserTypeProjections::none(), - &mut |this, _, _, node, span, _, _| { - this.storage_live_binding( - block, - node, - span, - OutsideGuard, - true, - ); - }, - ); - this.ast_let_else( - block, - *initializer, - initializer_span, - *else_block, - &last_remainder_scope, - pattern, - ) - }) - ); + let failure_and_block = this.in_scope(scope, *lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + None, + Some((Some(&destination), initializer_span)), + ); + this.visit_primary_bindings( + pattern, + UserTypeProjections::none(), + &mut |this, _, _, node, span, _, _| { + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); + }, + ); + let else_block_span = this.thir[*else_block].span; + let (matching, failure) = + this.in_if_then_scope(last_remainder_scope, else_block_span, |this| { + this.lower_let_expr( + block, + *initializer, + pattern, + None, + initializer_span, + DeclareLetBindings::No, + EmitStorageLive::No, + ) + }); + matching.and(failure) + }); + let failure = unpack!(block = failure_and_block); this.cfg.goto(failure, source_info, failure_entry); if let Some(source_scope) = visibility_scope { @@ -292,7 +298,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, UserTypeProjections::none(), &mut |this, _, _, node, span, _, _| { - this.storage_live_binding(block, node, span, OutsideGuard, true); + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); this.schedule_drop_for_binding(node, span, OutsideGuard); }, ) diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 76bdc26a501..942c69b5c0a 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,6 +1,7 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; +use crate::build::matches::DeclareLetBindings; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary}; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; @@ -86,7 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cond, Some(condition_scope), // Temp scope source_info, - true, // Declare `let` bindings normally + DeclareLetBindings::Yes, // Declare `let` bindings normally )); // Lower the `then` arm into its block. @@ -163,7 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, // This flag controls how inner `let` expressions are lowered, // but either way there shouldn't be any of those in here. - true, + DeclareLetBindings::LetNotPermitted, ) }); 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 932406fd1aa..efed52231e3 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -21,12 +21,14 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; +use util::visit_bindings; // helper functions, broken out by category: mod simplify; mod test; mod util; +use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::mem; @@ -38,9 +40,50 @@ struct ThenElseArgs { /// `self.local_scope()` is used. temp_scope_override: Option<region::Scope>, variable_source_info: SourceInfo, + /// Determines how bindings should be handled when lowering `let` expressions. + /// /// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`]. - /// When false (for match guards), `let` bindings won't be declared. - declare_let_bindings: bool, + declare_let_bindings: DeclareLetBindings, +} + +/// Should lowering a `let` expression also declare its bindings? +/// +/// Used by [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`]. +#[derive(Clone, Copy)] +pub(crate) enum DeclareLetBindings { + /// Yes, declare `let` bindings as normal for `if` conditions. + Yes, + /// No, don't declare `let` bindings, because the caller declares them + /// separately due to special requirements. + /// + /// Used for match guards and let-else. + No, + /// Let expressions are not permitted in this context, so it is a bug to + /// try to lower one (e.g inside lazy-boolean-or or boolean-not). + LetNotPermitted, +} + +/// Used by [`Builder::bind_matched_candidate_for_arm_body`] to determine +/// whether or not to call [`Builder::storage_live_binding`] to emit +/// [`StatementKind::StorageLive`]. +#[derive(Clone, Copy)] +pub(crate) enum EmitStorageLive { + /// Yes, emit `StorageLive` as normal. + Yes, + /// No, don't emit `StorageLive`. The caller has taken responsibility for + /// emitting `StorageLive` as appropriate. + No, +} + +/// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`] +/// to decide whether to schedule drops. +#[derive(Clone, Copy, Debug)] +pub(crate) enum ScheduleDrops { + /// Yes, the relevant functions should also schedule drops as appropriate. + Yes, + /// No, don't schedule drops. The caller has taken responsibility for any + /// appropriate drops. + No, } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -56,7 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_id: ExprId, temp_scope_override: Option<region::Scope>, variable_source_info: SourceInfo, - declare_let_bindings: bool, + declare_let_bindings: DeclareLetBindings, ) -> BlockAnd<()> { self.then_else_break_inner( block, @@ -90,13 +133,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.then_else_break_inner( block, lhs, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, ) }); let rhs_success_block = unpack!(this.then_else_break_inner( failure_block, rhs, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, )); // Make the LHS and RHS success arms converge to a common block. @@ -126,7 +175,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.then_else_break_inner( block, arg, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, ) }); this.break_for_else(success_block, args.variable_source_info); @@ -146,6 +198,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, + EmitStorageLive::Yes, ), _ => { let mut block = block; @@ -314,13 +367,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_start_span = span.shrink_to_lo().to(scrutinee_span); - let fake_borrow_temps = self.lower_match_tree( + // The set of places that we are creating fake borrows of. If there are no match guards then + // we don't need any fake borrows, so don't track them. + let fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { + util::collect_fake_borrows(self, &candidates, scrutinee_span, scrutinee_place.base()) + } else { + Vec::new() + }; + + self.lower_match_tree( block, scrutinee_span, &scrutinee_place, match_start_span, - match_has_guard, &mut candidates, + false, ); self.lower_match_arms( @@ -375,89 +436,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } - /// Create the decision tree for the match expression, starting from `block`. - /// - /// Modifies `candidates` to store the bindings and type ascriptions for - /// that candidate. - /// - /// Returns the places that need fake borrows because we bind or test them. - fn lower_match_tree<'pat>( - &mut self, - block: BasicBlock, - scrutinee_span: Span, - scrutinee_place_builder: &PlaceBuilder<'tcx>, - match_start_span: Span, - match_has_guard: bool, - candidates: &mut [&mut Candidate<'pat, 'tcx>], - ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { - // The set of places that we are creating fake borrows of. If there are no match guards then - // we don't need any fake borrows, so don't track them. - let fake_borrows: Vec<(Place<'tcx>, Local, FakeBorrowKind)> = if match_has_guard { - util::collect_fake_borrows( - self, - candidates, - scrutinee_span, - scrutinee_place_builder.base(), - ) - } else { - Vec::new() - }; - - // See the doc comment on `match_candidates` for why we have an - // otherwise block. Match checking will ensure this is actually - // unreachable. - let otherwise_block = self.cfg.start_new_block(); - - // This will generate code to test scrutinee_place and - // branch to the appropriate arm block - self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); - - let source_info = self.source_info(scrutinee_span); - - // Matching on a `scrutinee_place` with an uninhabited type doesn't - // generate any memory reads by itself, and so if the place "expression" - // contains unsafe operations like raw pointer dereferences or union - // field projections, we wouldn't know to require an `unsafe` block - // around a `match` equivalent to `std::intrinsics::unreachable()`. - // See issue #47412 for this hole being discovered in the wild. - // - // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `scrutinee_place`, specifically by applying `ReadForMatch`. - // - // NOTE: ReadForMatch also checks that the scrutinee is initialized. - // This is currently needed to not allow matching on an uninitialized, - // uninhabited value. If we get never patterns, those will check that - // the place is initialized, and so this read would only be used to - // check safety. - let cause_matched_place = FakeReadCause::ForMatchedPlace(None); - - if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { - self.cfg.push_fake_read( - otherwise_block, - source_info, - cause_matched_place, - scrutinee_place, - ); - } - - self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); - - // Link each leaf candidate to the `pre_binding_block` of the next one. - let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; - - for candidate in candidates { - candidate.visit_leaves(|leaf_candidate| { - if let Some(ref mut prev) = previous_candidate { - assert!(leaf_candidate.false_edge_start_block.is_some()); - prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; - } - previous_candidate = Some(leaf_candidate); - }); - } - - fake_borrows - } - /// Lower the bindings, guards and arm bodies of a `match` expression. /// /// The decision tree should have already been created @@ -513,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &fake_borrow_temps, scrutinee_span, Some((arm, match_scope)), - false, + EmitStorageLive::Yes, ); this.fixed_temps_scope = old_dedup_scope; @@ -558,7 +536,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) -> BasicBlock { if candidate.subcandidates.is_empty() { // Avoid generating another `BasicBlock` when we only have one @@ -569,8 +547,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps, scrutinee_span, arm_match_scope, - true, - storages_alive, + ScheduleDrops::Yes, + emit_storage_live, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -588,7 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // To handle this we instead unschedule it's drop after each time // we lower the guard. let target_block = self.cfg.start_new_block(); - let mut schedule_drops = true; + let mut schedule_drops = ScheduleDrops::Yes; let arm = arm_match_scope.unzip().0; // We keep a stack of all of the bindings and type ascriptions // from the parent candidates that we visit, that also need to @@ -607,10 +585,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, arm_match_scope, schedule_drops, - storages_alive, + emit_storage_live, ); if arm.is_none() { - schedule_drops = false; + schedule_drops = ScheduleDrops::No; } self.cfg.goto(binding_end, outer_source_info, target_block); }, @@ -636,8 +614,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { - let place = - self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); + let place = self.storage_live_binding( + block, + var, + irrefutable_pat.span, + OutsideGuard, + ScheduleDrops::Yes, + ); unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. @@ -670,8 +653,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ascription: thir::Ascription { ref annotation, variance: _ }, } => { - let place = - self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); + let place = self.storage_live_binding( + block, + var, + irrefutable_pat.span, + OutsideGuard, + ScheduleDrops::Yes, + ); unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. @@ -728,62 +716,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { set_match_place: bool, ) -> BlockAnd<()> { let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self); - let fake_borrow_temps = self.lower_match_tree( - block, - irrefutable_pat.span, - &initializer, - irrefutable_pat.span, - false, - &mut [&mut candidate], - ); // For matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for // let PATTERN = ... might not even exist until we do the assignment. // so we set it here instead. if set_match_place { - let mut next = Some(&candidate); - while let Some(candidate_ref) = next.take() { - for binding in &candidate_ref.extra_data.bindings { + // `try_to_place` may fail if it is unable to resolve the given `PlaceBuilder` inside a + // closure. In this case, we don't want to include a scrutinee place. + // `scrutinee_place_builder` will fail for destructured assignments. This is because a + // closure only captures the precise places that it will read and as a result a closure + // may not capture the entire tuple/struct and rather have individual places that will + // be read in the final MIR. + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // let (v1, v2) = foo; + // }; + // ``` + if let Some(place) = initializer.try_to_place(self) { + visit_bindings(&[&mut candidate], |binding: &Binding<'_>| { let local = self.var_local_id(binding.var_id, OutsideGuard); - // `try_to_place` may fail if it is unable to resolve the given - // `PlaceBuilder` inside a closure. In this case, we don't want to include - // a scrutinee place. `scrutinee_place_builder` will fail for destructured - // assignments. This is because a closure only captures the precise places - // that it will read and as a result a closure may not capture the entire - // tuple/struct and rather have individual places that will be read in the - // final MIR. - // Example: - // ``` - // let foo = (0, 1); - // let c = || { - // let (v1, v2) = foo; - // }; - // ``` - if let Some(place) = initializer.try_to_place(self) { - let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref mut match_place, _)), - .. - })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() - else { - bug!("Let binding to non-user variable.") - }; + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref mut match_place, _)), + .. + })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() + { *match_place = Some(place); - } - } - // All of the subcandidates should bind the same locals, so we - // only visit the first one. - next = candidate_ref.subcandidates.get(0) + } else { + bug!("Let binding to non-user variable.") + }; + }); } } + self.lower_match_tree( + block, + irrefutable_pat.span, + &initializer, + irrefutable_pat.span, + &mut [&mut candidate], + false, + ); self.bind_pattern( self.source_info(irrefutable_pat.span), candidate, - fake_borrow_temps.as_slice(), + &[], irrefutable_pat.span, None, - false, + EmitStorageLive::Yes, ) .unit() } @@ -859,13 +841,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Emits a [`StatementKind::StorageLive`] for the given var, and also + /// schedules a drop if requested (and possible). pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, var: LocalVarId, span: Span, for_guard: ForGuard, - schedule_drop: bool, + schedule_drop: ScheduleDrops, ) -> Place<'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); @@ -873,7 +857,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) - && schedule_drop + && matches!(schedule_drop, ScheduleDrops::Yes) { self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } @@ -1306,6 +1290,79 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); // Main matching algorithm impl<'a, 'tcx> Builder<'a, 'tcx> { + /// The entrypoint of the matching algorithm. Create the decision tree for the match expression, + /// starting from `block`. + /// + /// Modifies `candidates` to store the bindings and type ascriptions for + /// that candidate. + /// + /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) + /// or not (for `let` and `match`). In the refutable case we return the block to which we branch + /// on failure. + fn lower_match_tree<'pat>( + &mut self, + block: BasicBlock, + scrutinee_span: Span, + scrutinee_place_builder: &PlaceBuilder<'tcx>, + match_start_span: Span, + candidates: &mut [&mut Candidate<'pat, 'tcx>], + refutable: bool, + ) -> BasicBlock { + // See the doc comment on `match_candidates` for why we have an otherwise block. + let otherwise_block = self.cfg.start_new_block(); + + // This will generate code to test scrutinee_place and branch to the appropriate arm block + self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates); + + // Link each leaf candidate to the `false_edge_start_block` of the next one. + let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| { + if let Some(ref mut prev) = previous_candidate { + assert!(leaf_candidate.false_edge_start_block.is_some()); + prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; + } + previous_candidate = Some(leaf_candidate); + }); + } + + if refutable { + // In refutable cases there's always at least one candidate, and we want a false edge to + // the failure block. + previous_candidate.as_mut().unwrap().next_candidate_start_block = Some(otherwise_block) + } else { + // Match checking ensures `otherwise_block` is actually unreachable in irrefutable + // cases. + let source_info = self.source_info(scrutinee_span); + + // Matching on a scrutinee place of an uninhabited type doesn't generate any memory + // reads by itself, and so if the place is uninitialized we wouldn't know. In order to + // disallow the following: + // ```rust + // let x: !; + // match x {} + // ``` + // we add a dummy read on the place. + // + // NOTE: If we require never patterns for empty matches, those will check that the place + // is initialized, and so this read would no longer be needed. + let cause_matched_place = FakeReadCause::ForMatchedPlace(None); + + if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { + self.cfg.push_fake_read( + otherwise_block, + source_info, + cause_matched_place, + scrutinee_place, + ); + } + + self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); + } + + otherwise_block + } + /// The main match algorithm. It begins with a set of candidates /// `candidates` and has the job of generating code to determine /// which of these candidates, if any, is the correct one. The @@ -1997,53 +2054,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Pat binding - used for `let` and function parameters as well. impl<'a, 'tcx> Builder<'a, 'tcx> { - /// If the bindings have already been declared, set `declare_bindings` to - /// `false` to avoid duplicated bindings declaration. Used for if-let guards. + /// Lowers a `let` expression that appears in a suitable context + /// (e.g. an `if` condition or match guard). + /// + /// Also used for lowering let-else statements, since they have similar + /// needs despite not actually using `let` expressions. + /// + /// Use [`DeclareLetBindings`] to control whether the `let` bindings are + /// declared or not. pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, expr_id: ExprId, pat: &Pat<'tcx>, source_scope: Option<SourceScope>, - span: Span, - declare_bindings: bool, + scope_span: Span, + declare_let_bindings: DeclareLetBindings, + emit_storage_live: EmitStorageLive, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; - let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); - let wildcard = Pat::wildcard_from_ty(pat.ty); - let mut guard_candidate = Candidate::new(expr_place_builder.clone(), pat, false, self); - let mut otherwise_candidate = - Candidate::new(expr_place_builder.clone(), &wildcard, false, self); - let fake_borrow_temps = self.lower_match_tree( + let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); + let mut candidate = Candidate::new(scrutinee.clone(), pat, false, self); + let otherwise_block = self.lower_match_tree( block, + expr_span, + &scrutinee, pat.span, - &expr_place_builder, - pat.span, - false, - &mut [&mut guard_candidate, &mut otherwise_candidate], + &mut [&mut candidate], + true, ); - let expr_place = expr_place_builder.try_to_place(self); - let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); - let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); - self.break_for_else(otherwise_post_guard_block, self.source_info(expr_span)); - if declare_bindings { - self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place); + self.break_for_else(otherwise_block, self.source_info(expr_span)); + + match declare_let_bindings { + DeclareLetBindings::Yes => { + let expr_place = scrutinee.try_to_place(self); + let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); + self.declare_bindings( + source_scope, + pat.span.to(scope_span), + pat, + None, + opt_expr_place, + ); + } + DeclareLetBindings::No => {} // Caller is responsible for bindings. + DeclareLetBindings::LetNotPermitted => { + self.tcx.dcx().span_bug(expr_span, "let expression not expected in this context") + } } - let post_guard_block = self.bind_pattern( + let success = self.bind_pattern( self.source_info(pat.span), - guard_candidate, - fake_borrow_temps.as_slice(), + candidate, + &[], expr_span, None, - false, + emit_storage_live, ); // If branch coverage is enabled, record this branch. - self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block); + self.visit_coverage_conditional_let(pat, success, otherwise_block); - post_guard_block.unit() + success.unit() } /// Initializes each of the bindings from the candidate by @@ -2061,8 +2134,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - schedule_drops: bool, - storages_alive: bool, + schedule_drops: ScheduleDrops, + emit_storage_live: EmitStorageLive, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -2091,14 +2164,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return self.cfg.start_new_block(); } - self.ascribe_types( - block, - parent_data - .iter() - .flat_map(|d| &d.ascriptions) - .cloned() - .chain(candidate.extra_data.ascriptions), - ); + let ascriptions = parent_data + .iter() + .flat_map(|d| &d.ascriptions) + .cloned() + .chain(candidate.extra_data.ascriptions); + let bindings = + parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); + + self.ascribe_types(block, ascriptions); // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. @@ -2185,12 +2259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && let Some(guard) = arm.guard { let tcx = self.tcx; - let bindings = - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); - let guard_frame = - GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() }; + let guard_frame = GuardFrame { + locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(), + }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -2211,7 +2284,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, None, // Use `self.local_scope()` as the temp scope this.source_info(arm.span), - false, // For guards, `let` bindings are declared separately + DeclareLetBindings::No, // For guards, `let` bindings are declared separately ) }); @@ -2263,11 +2336,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = parent_data - .iter() - .flat_map(|d| &d.bindings) - .chain(&candidate.extra_data.bindings) - .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); + let by_value_bindings = + bindings.filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -2275,12 +2345,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause = FakeReadCause::ForGuardBinding; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } - assert!(schedule_drops, "patterns with guards must schedule drops"); + assert_matches!( + schedule_drops, + ScheduleDrops::Yes, + "patterns with guards must schedule drops" + ); self.bind_matched_candidate_for_arm_body( post_guard_block, - true, + ScheduleDrops::Yes, by_value_bindings, - storages_alive, + emit_storage_live, ); post_guard_block @@ -2291,8 +2365,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.bind_matched_candidate_for_arm_body( block, schedule_drops, - parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings), - storages_alive, + bindings, + emit_storage_live, ); block } @@ -2328,7 +2402,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_guard<'b>( &mut self, block: BasicBlock, - schedule_drops: bool, + schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, ) where 'tcx: 'b, @@ -2381,9 +2455,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_arm_body<'b>( &mut self, block: BasicBlock, - schedule_drops: bool, + schedule_drops: ScheduleDrops, bindings: impl IntoIterator<Item = &'b Binding<'tcx>>, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) where 'tcx: 'b, { @@ -2393,21 +2467,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = if storages_alive { + let local = match emit_storage_live { // Here storages are already alive, probably because this is a binding // from let-else. // We just need to schedule drop for the value. - self.var_local_id(binding.var_id, OutsideGuard).into() - } else { - self.storage_live_binding( + EmitStorageLive::No => self.var_local_id(binding.var_id, OutsideGuard).into(), + EmitStorageLive::Yes => self.storage_live_binding( block, binding.var_id, binding.span, OutsideGuard, schedule_drops, - ) + ), }; - if schedule_drops { + if matches!(schedule_drops, ScheduleDrops::Yes) { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } let rvalue = match binding.binding_mode.0 { @@ -2493,55 +2566,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(?locals); self.var_indices.insert(var_id, locals); } - - pub(crate) fn ast_let_else( - &mut self, - mut block: BasicBlock, - init_id: ExprId, - initializer_span: Span, - else_block: BlockId, - let_else_scope: ®ion::Scope, - pattern: &Pat<'tcx>, - ) -> BlockAnd<BasicBlock> { - let else_block_span = self.thir[else_block].span; - let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { - let scrutinee = unpack!(block = this.lower_scrutinee(block, init_id, initializer_span)); - let pat = Pat { ty: pattern.ty, span: else_block_span, kind: PatKind::Wild }; - let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this); - let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this); - let fake_borrow_temps = this.lower_match_tree( - block, - initializer_span, - &scrutinee, - pattern.span, - false, - &mut [&mut candidate, &mut wildcard], - ); - // This block is for the matching case - let matching = this.bind_pattern( - this.source_info(pattern.span), - candidate, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - // This block is for the failure case - let failure = this.bind_pattern( - this.source_info(else_block_span), - wildcard, - fake_borrow_temps.as_slice(), - initializer_span, - None, - true, - ); - - // If branch coverage is enabled, record this branch. - this.visit_coverage_conditional_let(pattern, matching, failure); - - this.break_for_else(failure, this.source_info(initializer_span)); - matching.unit() - }); - matching.and(failure) - } } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 630d0b9438d..3bec154e1df 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; @@ -269,18 +271,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } } -pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { - cx: &'a mut Builder<'b, 'tcx>, - /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from - /// bindings inside deref patterns. - scrutinee_base: PlaceBase, - /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest - /// borrow (i.e. Deep > Shallow). - /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are - /// dereferences are also borrowed with the same of stronger borrow kind. - fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. @@ -344,6 +334,18 @@ pub(super) fn collect_fake_borrows<'tcx>( .collect() } +pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> { + cx: &'a mut Builder<'b, 'tcx>, + /// Base of the scrutinee place. Used to distinguish bindings inside the scrutinee place from + /// bindings inside deref patterns. + scrutinee_base: PlaceBase, + /// Store for each place the kind of borrow to take. In case of conflicts, we take the strongest + /// borrow (i.e. Deep > Shallow). + /// Invariant: for any place in `fake_borrows`, all the prefixes of this place that are + /// dereferences are also borrowed with the same of stronger borrow kind. + fake_borrows: FxIndexMap<Place<'tcx>, FakeBorrowKind>, +} + impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // Fake borrow this place and its dereference prefixes. fn fake_borrow(&mut self, place: Place<'tcx>, kind: FakeBorrowKind) { @@ -457,6 +459,57 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } +/// Visit all the bindings of these candidates. Because or-alternatives bind the same variables, we +/// only explore the first one of each or-pattern. +pub(super) fn visit_bindings<'tcx>( + candidates: &[&mut Candidate<'_, 'tcx>], + f: impl FnMut(&Binding<'tcx>), +) { + let mut visitor = BindingsVisitor { f, phantom: PhantomData }; + for candidate in candidates.iter() { + visitor.visit_candidate(candidate); + } +} + +pub(super) struct BindingsVisitor<'tcx, F> { + f: F, + phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx, F> BindingsVisitor<'tcx, F> +where + F: FnMut(&Binding<'tcx>), +{ + fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { + for binding in &candidate.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &candidate.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { + for binding in &flat_pat.extra_data.bindings { + (self.f)(binding) + } + for match_pair in &flat_pat.match_pairs { + self.visit_match_pair(match_pair); + } + } + + fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + if let TestCase::Or { pats, .. } = &match_pair.test_case { + // All the or-alternatives should bind the same locals, so we only visit the first one. + self.visit_flat_pat(&pats[0]) + } else { + for subpair in &match_pair.subpairs { + self.visit_match_pair(subpair); + } + } + } +} + #[must_use] pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { match ref_mutability { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index f0b79dab0c9..ffcf630b653 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -50,15 +50,19 @@ use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable}; /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeUninitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeInitializedPlaces<'a, 'tcx> { +pub struct MaybeInitializedPlaces<'a, 'mir, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, skip_unreachable_unwind: bool, } -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { +impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + body: &'mir Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, + ) -> Self { MaybeInitializedPlaces { tcx, body, mdpe, skip_unreachable_unwind: false } } @@ -84,7 +88,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { } } -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { +impl<'a, 'mir, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'mir, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } @@ -125,17 +129,21 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeInitializedPlaces` yields the set of /// places that would require a dynamic drop-flag at that statement. -pub struct MaybeUninitializedPlaces<'a, 'tcx> { +pub struct MaybeUninitializedPlaces<'a, 'mir, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, mark_inactive_variants_as_uninit: bool, skip_unreachable_unwind: BitSet<mir::BasicBlock>, } -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { +impl<'a, 'mir, 'tcx> MaybeUninitializedPlaces<'a, 'mir, 'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + body: &'mir Body<'tcx>, + mdpe: &'a MoveDataParamEnv<'tcx>, + ) -> Self { MaybeUninitializedPlaces { tcx, body, @@ -164,7 +172,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { } } -impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, '_, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } @@ -250,24 +258,24 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// c = S; // {a, b, c, d } /// } /// ``` -pub struct EverInitializedPlaces<'a, 'tcx> { - body: &'a Body<'tcx>, +pub struct EverInitializedPlaces<'a, 'mir, 'tcx> { + body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, } -impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { +impl<'a, 'mir, 'tcx> EverInitializedPlaces<'a, 'mir, 'tcx> { + pub fn new(body: &'mir Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { EverInitializedPlaces { body, mdpe } } } -impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, '_, 'tcx> { fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data } } -impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { +impl<'a, 'mir, 'tcx> MaybeInitializedPlaces<'a, 'mir, 'tcx> { fn update_bits( trans: &mut impl GenKill<MovePathIndex>, path: MovePathIndex, @@ -280,7 +288,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { } } -impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> MaybeUninitializedPlaces<'a, '_, 'tcx> { fn update_bits( trans: &mut impl GenKill<MovePathIndex>, path: MovePathIndex, @@ -306,7 +314,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = MaybeReachable<ChunkedBitSet<MovePathIndex>>; @@ -328,7 +336,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, '_, 'tcx> { type Idx = MovePathIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { @@ -441,7 +449,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet<MovePathIndex>; @@ -465,7 +473,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, '_, 'tcx> { type Idx = MovePathIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { @@ -642,7 +650,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { /// There can be many more `InitIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet<InitIndex>; @@ -661,7 +669,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> { type Idx = InitIndex; fn domain_size(&self, _: &Body<'tcx>) -> usize { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 5e2d88f94ca..bfbfff7e259 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -846,9 +846,10 @@ impl Map { if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind() && let ty::Slice(..) = ref_ty.kind() + // The user may have written a predicate like `[T]: Sized` in their where clauses, + // which makes slices scalars. + && self.places[place].value_index.is_none() { - assert!(self.places[place].value_index.is_none(), "slices are not scalars"); - // Prepend new child to the linked list. let len = self.places.push(PlaceInfo::new(Some(TrackElem::DerefLen))); self.places[len].next_sibling = self.places[place].first_child; diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 7e401b5482f..3333bebff3a 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -31,6 +31,37 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 } } + /// Add function-level costs not well-represented by the block-level costs. + /// + /// Needed because the `CostChecker` is used sometimes for just blocks, + /// and even the full `Inline` doesn't call `visit_body`, so there's nowhere + /// to put this logic in the visitor. + pub fn add_function_level_costs(&mut self) { + fn is_call_like(bbd: &BasicBlockData<'_>) -> bool { + use TerminatorKind::*; + match bbd.terminator().kind { + Call { .. } | Drop { .. } | Assert { .. } | InlineAsm { .. } => true, + + Goto { .. } + | SwitchInt { .. } + | UnwindResume + | UnwindTerminate(_) + | Return + | Unreachable => false, + + Yield { .. } | CoroutineDrop | FalseEdge { .. } | FalseUnwind { .. } => { + unreachable!() + } + } + } + + // If the only has one Call (or similar), inlining isn't increasing the total + // number of calls, so give extra encouragement to inlining that. + if self.callee_body.basic_blocks.iter().filter(|bbd| is_call_like(bbd)).count() == 1 { + self.bonus += CALL_PENALTY; + } + } + pub fn cost(&self) -> usize { usize::saturating_sub(self.penalty, self.bonus) } diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 759bb7c1f9d..235992ac547 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -9,9 +9,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; -use crate::coverage::spans::{ - extract_refined_covspans, unexpand_into_body_span_with_visible_macro, -}; +use crate::coverage::spans::extract_refined_covspans; +use crate::coverage::unexpand::unexpand_into_body_span; use crate::coverage::ExtractedHirInfo; /// Associates an ordinary executable code span with its corresponding BCB. @@ -202,8 +201,7 @@ pub(super) fn extract_branch_pairs( if !raw_span.ctxt().outer_expn_data().is_root() { return None; } - let (span, _) = - unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?; + let span = unexpand_into_body_span(raw_span, hir_info.body_span)?; let bcb_from_marker = |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); @@ -238,7 +236,7 @@ pub(super) fn extract_mcdc_mappings( if !raw_span.ctxt().outer_expn_data().is_root() { return None; } - let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?; + let span = unexpand_into_body_span(raw_span, body_span)?; let true_bcb = bcb_from_marker(true_marker)?; let false_bcb = bcb_from_marker(false_marker)?; @@ -261,7 +259,7 @@ pub(super) fn extract_mcdc_mappings( mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { - let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; + let span = unexpand_into_body_span(decision.span, body_span)?; let end_bcbs = decision .end_markers diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 4a64d21f3d1..d55bde311c1 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -6,6 +6,7 @@ mod mappings; mod spans; #[cfg(test)] mod tests; +mod unexpand; use rustc_middle::mir::coverage::{ CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 84a70d1f02d..7612c01c52e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -14,11 +14,6 @@ use crate::coverage::ExtractedHirInfo; mod from_mir; -// FIXME(#124545) It's awkward that we have to re-export this, because it's an -// internal detail of `from_mir` that is also needed when handling branch and -// MC/DC spans. Ideally we would find a more natural home for it. -pub(super) use from_mir::unexpand_into_body_span_with_visible_macro; - pub(super) fn extract_refined_covspans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, 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 09deb7534bf..2ca166929ee 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -4,12 +4,13 @@ use rustc_middle::mir::{ self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; +use rustc_span::{Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; use crate::coverage::spans::Covspan; +use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; use crate::coverage::ExtractedHirInfo; pub(crate) struct ExtractedCovspans { @@ -215,59 +216,6 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> { } } -/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range -/// within the function's body source. This span is guaranteed to be contained -/// within, or equal to, the `body_span`. If the extrapolated span is not -/// contained within the `body_span`, `None` is returned. -/// -/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, -/// etc.). -pub(crate) fn unexpand_into_body_span_with_visible_macro( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option<Symbol>)> { - let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - - let visible_macro = prev - .map(|prev| match prev.ctxt().outer_expn_data().kind { - ExpnKind::Macro(MacroKind::Bang, name) => Some(name), - _ => None, - }) - .flatten(); - - Some((span, visible_macro)) -} - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. -/// The ancestor that was traversed just before the matching span (if any) is -/// also returned. -/// -/// For example, a return value of `Some((ancestor, Some(prev))` means that: -/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` -/// - `ancestor == prev.parent_callsite()` -/// -/// [`SyntaxContext`]: rustc_span::SyntaxContext -fn unexpand_into_body_span_with_prev( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option<Span>)> { - let mut prev = None; - let mut curr = original_span; - - while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { - prev = Some(curr); - curr = curr.parent_callsite()?; - } - - debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); - if let Some(prev) = prev { - debug_assert_eq!(Some(curr), prev.parent_callsite()); - } - - Some((curr, prev)) -} - #[derive(Debug)] pub(crate) struct Hole { pub(crate) span: Span, diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs new file mode 100644 index 00000000000..8cde291b907 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -0,0 +1,60 @@ +use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [syntax context] as `body_span`. +pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> Option<Span> { + // Because we don't need to return any extra ancestor information, + // we can just delegate directly to `find_ancestor_inside_same_ctxt`. + original_span.find_ancestor_inside_same_ctxt(body_span) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [syntax context] as `body_span`. +/// +/// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), +/// the returned symbol will be the name of that macro (e.g. `foo`). +pub(crate) fn unexpand_into_body_span_with_visible_macro( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option<Symbol>)> { + let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; + + let visible_macro = prev + .map(|prev| match prev.ctxt().outer_expn_data().kind { + ExpnKind::Macro(MacroKind::Bang, name) => Some(name), + _ => None, + }) + .flatten(); + + Some((span, visible_macro)) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [syntax context] as `body_span`. +/// The ancestor that was traversed just before the matching span (if any) is +/// also returned. +/// +/// For example, a return value of `Some((ancestor, Some(prev)))` means that: +/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` +/// - `prev.parent_callsite() == ancestor` +/// +/// [syntax context]: rustc_span::SyntaxContext +fn unexpand_into_body_span_with_prev( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option<Span>)> { + let mut prev = None; + let mut curr = original_span; + + while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { + prev = Some(curr); + curr = curr.parent_callsite()?; + } + + debug_assert_eq!(Some(curr), original_span.find_ancestor_inside_same_ctxt(body_span)); + if let Some(prev) = prev { + debug_assert_eq!(Some(curr), prev.parent_callsite()); + } + + Some((curr, prev)) +} diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0fd85eb345d..8b965f4d18e 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -181,11 +181,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { state.insert_value_idx(value_target, val, self.map()); } if let Some(overflow_target) = overflow_target { - let overflow = match overflow { - FlatSet::Top => FlatSet::Top, - FlatSet::Elem(overflow) => FlatSet::Elem(overflow), - FlatSet::Bottom => FlatSet::Bottom, - }; // We have flooded `target` earlier. state.insert_value_idx(overflow_target, overflow, self.map()); } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 665b2260294..fbbb8c5e472 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -97,7 +97,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { #[instrument(level = "trace", skip(body, flow_inits), ret)] fn compute_dead_unwinds<'mir, 'tcx>( body: &'mir Body<'tcx>, - flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'_, 'mir, 'tcx>>, ) -> BitSet<BasicBlock> { // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. @@ -118,12 +118,12 @@ fn compute_dead_unwinds<'mir, 'tcx>( dead_unwinds } -struct InitializationData<'mir, 'tcx> { - inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, - uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, +struct InitializationData<'a, 'mir, 'tcx> { + inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'a, 'mir, 'tcx>>, + uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'a, 'mir, 'tcx>>, } -impl InitializationData<'_, '_> { +impl InitializationData<'_, '_, '_> { fn seek_before(&mut self, loc: Location) { self.inits.seek_before_primary_effect(loc); self.uninits.seek_before_primary_effect(loc); @@ -134,17 +134,17 @@ impl InitializationData<'_, '_> { } } -struct Elaborator<'a, 'b, 'tcx> { - ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, +struct Elaborator<'a, 'b, 'mir, 'tcx> { + ctxt: &'a mut ElaborateDropsCtxt<'b, 'mir, 'tcx>, } -impl fmt::Debug for Elaborator<'_, '_, '_> { +impl fmt::Debug for Elaborator<'_, '_, '_, '_> { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { Ok(()) } } -impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, 'tcx> { +impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, '_, 'tcx> { type Path = MovePathIndex; fn patch(&mut self) -> &mut MirPatch<'tcx> { @@ -238,16 +238,16 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, 'tcx> { } } -struct ElaborateDropsCtxt<'a, 'tcx> { +struct ElaborateDropsCtxt<'a, 'mir, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &'mir Body<'tcx>, env: &'a MoveDataParamEnv<'tcx>, - init_data: InitializationData<'a, 'tcx>, + init_data: InitializationData<'a, 'mir, 'tcx>, drop_flags: IndexVec<MovePathIndex, Option<Local>>, patch: MirPatch<'tcx>, } -impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { +impl<'b, 'mir, 'tcx> ElaborateDropsCtxt<'b, 'mir, 'tcx> { fn move_data(&self) -> &'b MoveData<'tcx> { &self.env.move_data } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 936a7e2d9de..3dbdeb615cf 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1074,11 +1074,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { lhs = *lhs_value; rhs = *rhs_value; - if let Some(op) = self.try_as_operand(lhs, location) { - *lhs_operand = op; - } - if let Some(op) = self.try_as_operand(rhs, location) { - *rhs_operand = op; + if let Some(lhs_op) = self.try_as_operand(lhs, location) + && let Some(rhs_op) = self.try_as_operand(rhs, location) + { + *lhs_operand = lhs_op; + *rhs_operand = rhs_op; } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 0a5fc697d03..6fa31c1174d 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt, TypeFlags}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -85,13 +85,18 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { } let param_env = tcx.param_env_reveal_all_normalized(def_id); + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); let mut this = Inliner { tcx, param_env, - codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), + codegen_fn_attrs, history: Vec::new(), changed: false, + caller_is_inline_forwarder: matches!( + codegen_fn_attrs.inline, + InlineAttr::Hint | InlineAttr::Always + ) && body_is_forwarder(body), }; let blocks = START_BLOCK..body.basic_blocks.next_index(); this.process_blocks(body, blocks); @@ -111,6 +116,9 @@ struct Inliner<'tcx> { history: Vec<DefId>, /// Indicates that the caller body has been modified. changed: bool, + /// Indicates that the caller is #[inline] and just calls another function, + /// and thus we can inline less into it as it'll be inlined itself. + caller_is_inline_forwarder: bool, } impl<'tcx> Inliner<'tcx> { @@ -306,6 +314,16 @@ impl<'tcx> Inliner<'tcx> { InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { return Err("instance without MIR (intrinsic / virtual)"); } + + // FIXME(#127030): `ConstParamHasTy` has bad interactions with + // the drop shim builder, which does not evaluate predicates in + // the correct param-env for types being dropped. Stall resolving + // the MIR for this instance until all of its const params are + // substituted. + InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { + return Err("still needs substitution"); + } + // This cannot result in an immediate cycle since the callee MIR is a shim, which does // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue @@ -475,7 +493,9 @@ impl<'tcx> Inliner<'tcx> { ) -> Result<(), &'static str> { let tcx = self.tcx; - let mut threshold = if cross_crate_inlinable { + let mut threshold = if self.caller_is_inline_forwarder { + self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30) + } else if cross_crate_inlinable { self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) } else { self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) @@ -494,6 +514,8 @@ impl<'tcx> Inliner<'tcx> { let mut checker = CostChecker::new(self.tcx, self.param_env, Some(callsite.callee), callee_body); + checker.add_function_level_costs(); + // Traverse the MIR manually so we can account for the effects of inlining on the CFG. let mut work_list = vec![START_BLOCK]; let mut visited = BitSet::new_empty(callee_body.basic_blocks.len()); @@ -1081,3 +1103,37 @@ fn try_instance_mir<'tcx>( } Ok(tcx.instance_mir(instance)) } + +fn body_is_forwarder(body: &Body<'_>) -> bool { + let TerminatorKind::Call { target, .. } = body.basic_blocks[START_BLOCK].terminator().kind + else { + return false; + }; + if let Some(target) = target { + let TerminatorKind::Return = body.basic_blocks[target].terminator().kind else { + return false; + }; + } + + let max_blocks = if !body.is_polymorphic { + 2 + } else if target.is_none() { + 3 + } else { + 4 + }; + if body.basic_blocks.len() > max_blocks { + return false; + } + + body.basic_blocks.iter_enumerated().all(|(bb, bb_data)| { + bb == START_BLOCK + || matches!( + bb_data.terminator().kind, + TerminatorKind::Return + | TerminatorKind::Drop { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + ) + }) +} diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 23cc0c46e73..27e506a920b 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -91,43 +91,8 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { opportunities: Vec::new(), }; - for (bb, bbdata) in body.basic_blocks.iter_enumerated() { - debug!(?bb, term = ?bbdata.terminator()); - if bbdata.is_cleanup || loop_headers.contains(bb) { - continue; - } - let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { continue }; - let Some(discr) = discr.place() else { continue }; - debug!(?discr, ?bb); - - let discr_ty = discr.ty(body, tcx).ty; - let Ok(discr_layout) = finder.ecx.layout_of(discr_ty) else { continue }; - - let Some(discr) = finder.map.find(discr.as_ref()) else { continue }; - debug!(?discr); - - let cost = CostChecker::new(tcx, param_env, None, body); - - let mut state = State::new(ConditionSet::default(), finder.map); - - let conds = if let Some((value, then, else_)) = targets.as_static_if() { - let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { - continue; - }; - arena.alloc_from_iter([ - Condition { value, polarity: Polarity::Eq, target: then }, - Condition { value, polarity: Polarity::Ne, target: else_ }, - ]) - } else { - arena.alloc_from_iter(targets.iter().filter_map(|(value, target)| { - let value = ScalarInt::try_from_uint(value, discr_layout.size)?; - Some(Condition { value, polarity: Polarity::Eq, target }) - })) - }; - let conds = ConditionSet(conds); - state.insert_value_idx(discr, conds, finder.map); - - finder.find_opportunity(bb, state, cost, 0); + for bb in body.basic_blocks.indices() { + finder.start_from_switch(bb); } let opportunities = finder.opportunities; @@ -216,6 +181,46 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { } /// Recursion entry point to find threading opportunities. + #[instrument(level = "trace", skip(self))] + fn start_from_switch(&mut self, bb: BasicBlock) -> Option<!> { + let bbdata = &self.body[bb]; + if bbdata.is_cleanup || self.loop_headers.contains(bb) { + return None; + } + let (discr, targets) = bbdata.terminator().kind.as_switch()?; + let discr = discr.place()?; + debug!(?discr, ?bb); + + let discr_ty = discr.ty(self.body, self.tcx).ty; + let discr_layout = self.ecx.layout_of(discr_ty).ok()?; + + let discr = self.map.find(discr.as_ref())?; + debug!(?discr); + + let cost = CostChecker::new(self.tcx, self.param_env, None, self.body); + let mut state = State::new(ConditionSet::default(), self.map); + + let conds = if let Some((value, then, else_)) = targets.as_static_if() { + let value = ScalarInt::try_from_uint(value, discr_layout.size)?; + self.arena.alloc_from_iter([ + Condition { value, polarity: Polarity::Eq, target: then }, + Condition { value, polarity: Polarity::Ne, target: else_ }, + ]) + } else { + self.arena.alloc_from_iter(targets.iter().filter_map(|(value, target)| { + let value = ScalarInt::try_from_uint(value, discr_layout.size)?; + Some(Condition { value, polarity: Polarity::Eq, target }) + })) + }; + let conds = ConditionSet(conds); + state.insert_value_idx(discr, conds, self.map); + + self.find_opportunity(bb, state, cost, 0); + None + } + + /// Recursively walk statements backwards from this bb's terminator to find threading + /// opportunities. #[instrument(level = "trace", skip(self, cost), ret)] fn find_opportunity( &mut self, @@ -270,12 +275,13 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { self.process_switch_int(discr, targets, bb, &mut state); self.find_opportunity(pred, state, cost, depth + 1); } - _ => self.recurse_through_terminator(pred, &state, &cost, depth), + _ => self.recurse_through_terminator(pred, || state, &cost, depth), } - } else { + } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { for &pred in predecessors { - self.recurse_through_terminator(pred, &state, &cost, depth); + self.recurse_through_terminator(pred, || state.clone(), &cost, depth); } + self.recurse_through_terminator(last_pred, || state, &cost, depth); } let new_tos = &mut self.opportunities[last_non_rec..]; @@ -566,11 +572,12 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { None } - #[instrument(level = "trace", skip(self, cost))] + #[instrument(level = "trace", skip(self, state, cost))] fn recurse_through_terminator( &mut self, bb: BasicBlock, - state: &State<ConditionSet<'a>>, + // Pass a closure that may clone the state, as we don't want to do it each time. + state: impl FnOnce() -> State<ConditionSet<'a>>, cost: &CostChecker<'_, 'tcx>, depth: usize, ) { @@ -600,7 +607,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { }; // We can recurse through this terminator. - let mut state = state.clone(); + let mut state = state(); if let Some(place_to_flood) = place_to_flood { state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::default()); } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 21439530c08..6ee684605ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -269,6 +269,11 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, ) -> Vec<Candidate<I>>; + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; } impl<D, I> EvalCtxt<'_, D> @@ -420,6 +425,8 @@ where G::consider_builtin_destruct_candidate(self, goal) } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) { + G::consider_builtin_effects_intersection_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 0cef8d9f4bc..3447b39fa5b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -668,8 +668,9 @@ where { let cx = ecx.cx(); let mut requirements = vec![]; - requirements - .extend(cx.super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args)); + requirements.extend( + cx.explicit_super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args), + ); // FIXME(associated_const_equality): Also add associated consts to // the requirements here. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 4e8cb4384f4..9275bcc8e97 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -864,6 +864,68 @@ where ) -> Result<Candidate<I>, NoSolution> { panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + let ty::Tuple(types) = goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + let cx = ecx.cx(); + + let mut first_non_maybe = None; + let mut non_maybe_count = 0; + for ty in types.iter() { + if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) { + first_non_maybe.get_or_insert(ty); + non_maybe_count += 1; + } + } + + match non_maybe_count { + 0 => { + let ty = ty::EffectKind::Maybe.to_ty(cx); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + 1 => { + let ty = first_non_maybe.unwrap(); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + _ => { + let mut min = ty::EffectKind::Maybe; + + for ty in types.iter() { + // We can't find the intersection if the types used are generic. + // + // FIXME(effects) do we want to look at where clauses to get some + // clue for the case where generic types are being used? + let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::intersection(min, kind) else { + return Err(NoSolution); + }; + + min = result; + } + + let ty = min.to_ty(cx); + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.instantiate_normalizes_to_term(goal, ty.into()); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + } + } + } } impl<D, I> EvalCtxt<'_, D> diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 2bc9d35c2b0..f5832f7e5b4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -702,6 +702,47 @@ where } }) } + + fn consider_builtin_effects_intersection_candidate( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + if goal.predicate.polarity != ty::PredicatePolarity::Positive { + return Err(NoSolution); + } + + let ty::Tuple(types) = goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + let cx = ecx.cx(); + let maybe_count = types + .iter() + .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty)) + .filter(|&ty| ty == ty::EffectKind::Maybe) + .count(); + + // Don't do concrete type check unless there are more than one type that will influence the result. + // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`. + if types.len() - maybe_count > 1 { + let mut min = ty::EffectKind::Maybe; + + for ty in types.iter() { + let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else { + return Err(NoSolution); + }; + + let Some(result) = ty::EffectKind::intersection(min, kind) else { + return Err(NoSolution); + }; + + min = result; + } + } + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) + .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + } } impl<D, I> EvalCtxt<'_, D> diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3cdc20b6c65..b2df9a14eb0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2327,7 +2327,7 @@ impl<'a> Parser<'a> { let before = self.prev_token.clone(); let binder = if self.check_keyword(kw::For) { let lo = self.token.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::closure_lifetime_binder, span); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index fde16ac957d..10c7715c7dc 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -457,7 +457,7 @@ impl<'a> Parser<'a> { // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; // Parse type with mandatory colon and (possibly empty) bounds, // or with mandatory equality sign and the second type. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d2043c353fe..1e5b227aaa9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -18,7 +18,7 @@ use rustc_ast::{ }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; use thin_vec::{thin_vec, ThinVec}; #[derive(Copy, Clone, PartialEq)] @@ -280,7 +280,7 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?; if self.check_fn_front_matter(false, Case::Sensitive) { self.parse_ty_bare_fn( lo, @@ -833,12 +833,9 @@ impl<'a> Parser<'a> { let lo = self.token.span; let leading_token = self.prev_token.clone(); let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); - let inner_lo = self.token.span; - let modifiers = self.parse_trait_bound_modifiers()?; let bound = if self.token.is_lifetime() { - self.error_lt_bound_with_modifiers(modifiers); - self.parse_generic_lt_bound(lo, inner_lo, has_parens)? + self.parse_generic_lt_bound(lo, has_parens)? } else if self.eat_keyword(kw::Use) { // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of // lifetimes and ident params (including SelfUpper). These are validated later @@ -848,7 +845,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)? + self.parse_generic_ty_bound(lo, has_parens, &leading_token)? }; Ok(bound) @@ -858,50 +855,64 @@ impl<'a> Parser<'a> { /// ```ebnf /// LT_BOUND = LIFETIME /// ``` - fn parse_generic_lt_bound( - &mut self, - lo: Span, - inner_lo: Span, - has_parens: bool, - ) -> PResult<'a, GenericBound> { - let bound = GenericBound::Outlives(self.expect_lifetime()); + fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> { + let lt = self.expect_lifetime(); + let bound = GenericBound::Outlives(lt); if has_parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P<GenericBound>)`? - self.recover_paren_lifetime(lo, inner_lo)?; + self.recover_paren_lifetime(lo, lt.ident.span)?; } Ok(bound) } /// Emits an error if any trait bound modifiers were present. - fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) { - match modifiers.constness { + fn error_lt_bound_with_modifiers( + &self, + modifiers: TraitBoundModifiers, + binder_span: Option<Span>, + ) -> ErrorGuaranteed { + let TraitBoundModifiers { constness, asyncness, polarity } = modifiers; + + match constness { BoundConstness::Never => {} BoundConstness::Always(span) | BoundConstness::Maybe(span) => { - self.dcx().emit_err(errors::ModifierLifetime { - span, - modifier: modifiers.constness.as_str(), - }); + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: constness.as_str() }); } } - match modifiers.polarity { + match polarity { BoundPolarity::Positive => {} BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { - self.dcx().emit_err(errors::ModifierLifetime { - span, - modifier: modifiers.polarity.as_str(), - }); + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: polarity.as_str() }); + } + } + + match asyncness { + BoundAsyncness::Normal => {} + BoundAsyncness::Async(span) => { + return self + .dcx() + .emit_err(errors::ModifierLifetime { span, modifier: asyncness.as_str() }); } } + + if let Some(span) = binder_span { + return self.dcx().emit_err(errors::ModifierLifetime { span, modifier: "for<...>" }); + } + + unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?") } /// Recover on `('lifetime)` with `(` already eaten. - fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> { - let inner_span = inner_lo.to(self.prev_token.span); + fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); - let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(inner_span) { + let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) { (Some(span), snippet) } else { (None, String::new()) @@ -916,7 +927,7 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"] + /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let constness = if self.eat(&token::Tilde) { @@ -970,15 +981,23 @@ impl<'a> Parser<'a> { /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH /// ``` /// - /// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`. + /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. fn parse_generic_ty_bound( &mut self, lo: Span, has_parens: bool, - modifiers: TraitBoundModifiers, leading_token: &Token, ) -> PResult<'a, GenericBound> { - let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let modifiers = self.parse_trait_bound_modifiers()?; + let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + + // Recover erroneous lifetime bound with modifiers or binder. + // e.g. `T: for<'a> 'a` or `T: ~const 'a`. + if self.token.is_lifetime() { + let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); + return self.parse_generic_lt_bound(lo, has_parens); + } + let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() @@ -1094,16 +1113,19 @@ impl<'a> Parser<'a> { } /// Optionally parses `for<$generic_params>`. - pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, ThinVec<GenericParam>> { + pub(super) fn parse_late_bound_lifetime_defs( + &mut self, + ) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> { if self.eat_keyword(kw::For) { + let lo = self.token.span; self.expect_lt()?; let params = self.parse_generic_params()?; self.expect_gt()?; - // We rely on AST validation to rule out invalid cases: There must not be type - // parameters, and the lifetime parameters must not have bounds. - Ok(params) + // We rely on AST validation to rule out invalid cases: There must not be + // type or const parameters, and parameters must not have bounds. + Ok((params, Some(lo.to(self.prev_token.span)))) } else { - Ok(ThinVec::new()) + Ok((ThinVec::new(), None)) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5a560325ab9..d7513fbad63 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -782,6 +782,7 @@ passes_used_compiler_linker = passes_used_static = attribute must be applied to a `static` variable + .label = but this is a {$target} passes_useless_assignment = useless assignment of {$is_field_assign -> diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5f8e4a8b7a7..0eb9d1ce59f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -274,7 +274,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.check_repr(attrs, span, target, item, hir_id); - self.check_used(attrs, target); + self.check_used(attrs, target, span); } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { @@ -1930,12 +1930,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attrs: &[Attribute], target: Target) { + fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) { let mut used_linker_span = None; let mut used_compiler_span = None; for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { span: attr.span }); + self.dcx().emit_err(errors::UsedStatic { + attr_span: attr.span, + span: target_span, + target: target.name(), + }); } let inner = attr.meta_item_list(); match inner.as_deref() { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7734dba3670..a026ff3b13b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -551,7 +551,10 @@ pub struct ReprConflictingLint; #[diag(passes_used_static)] pub struct UsedStatic { #[primary_span] + pub attr_span: Span, + #[label] pub span: Span, + pub target: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 80f7ca544f3..2e4421d50e3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1766,6 +1766,8 @@ options! { "enable LLVM inlining (default: yes)"), inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable MIR inlining (default: no)"), + inline_mir_forwarder_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], + "inlining threshold when the caller is a simple forwarding function (default: 30)"), inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], "inlining threshold for functions with inline hint (default: 100)"), inline_mir_preserve_debug: Option<bool> = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index e23f4289e98..4eefd0eb17c 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -160,7 +160,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); + let GenericPredicates { parent, predicates, effects_min_tys: _ } = + tables.tcx.predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates @@ -181,7 +182,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; - let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id); + let GenericPredicates { parent, predicates, effects_min_tys: _ } = + tables.tcx.explicit_predicates_of(def_id); stable_mir::ty::GenericPredicates { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 74c3fcc9b9e..9382460d6d4 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -600,7 +600,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { ty::GenericParamDefKind::Type { has_default, synthetic } => { GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } } - ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => { + ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => { GenericParamDefKind::Const { has_default: *has_default } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3b6147c4c0f..7da9211bcbf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -194,6 +194,14 @@ symbols! { Display, DoubleEndedIterator, Duration, + EffectsCompat, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsMaybe, + EffectsNoRuntime, + EffectsRuntime, + EffectsTyCompat, + Effects__, Encodable, Encoder, Enumerate, @@ -1606,6 +1614,7 @@ symbols! { rustc_do_not_const_check, rustc_doc_primitive, rustc_dummy, + rustc_dump_def_parents, rustc_dump_item_bounds, rustc_dump_predicates, rustc_dump_user_args, @@ -1658,6 +1667,7 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, + rustc_runtime, rustc_safe_intrinsic, rustc_serialize, rustc_skip_during_method_dispatch, diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1f4fb57d996..f023a0eb53a 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -5,8 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" -derivative = "2.2.0" itertools = "0.12" rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } @@ -15,7 +13,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } -rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } @@ -28,7 +25,6 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } rustc_type_ir = { path = "../rustc_type_ir" } -rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 4b5b1d77b30..34da8e576ce 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -88,7 +88,7 @@ impl<'tcx> InferCtxt<'tcx> { found_args: Vec<ArgKind>, is_closure: bool, closure_arg_span: Option<Span>, - ) -> Diag<'tcx> { + ) -> Diag<'_> { let kind = if is_closure { "closure" } else { "function" }; let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { 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 f4a026c0367..ccf86dbb1d0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -241,8 +241,8 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( } } -#[extension(pub trait TypeErrCtxtExt<'tcx>)] -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn suggest_restricting_param_bound( &self, err: &mut Diag<'_>, @@ -1845,7 +1845,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut Diag<'tcx>, + err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, ) { match obligation.cause.code().peel_derives() { @@ -1884,7 +1884,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCauseCode<'tcx>, found_node: Option<Node<'_>>, param_env: ty::ParamEnv<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { pub(crate) fn build_fn_sig_ty<'tcx>( infcx: &InferCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -2104,7 +2104,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn note_conflicting_closure_bounds( &self, cause: &ObligationCauseCode<'tcx>, - err: &mut Diag<'tcx>, + err: &mut Diag<'_>, ) { // First, look for an `WhereClauseInExpr`, which means we can get // the uninstantiated predicate list of the called function. And check @@ -4995,6 +4995,12 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>( let ty::ClauseKind::Projection(proj) = clause else { return; }; + // avoid ICEing since effects desugared associated types don't have names. + // this path should only be hit for `~const` on invalid places, so they + // will have an informative error already. + if tcx.is_effects_desugared_assoc_ty(proj.projection_term.def_id) { + return; + } let name = tcx.item_name(proj.projection_term.def_id); let mut predicates = generics.predicates.iter().peekable(); let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; 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 d3096cf4b52..adf1076a7c9 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 @@ -82,8 +82,8 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( )); } -#[extension(pub trait TypeErrCtxtExt<'tcx>)] -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn report_fulfillment_errors( &self, mut errors: Vec<FulfillmentError<'tcx>>, @@ -228,7 +228,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: OverflowCause<'tcx>, span: Span, suggest_increasing_limit: bool, - ) -> Diag<'tcx> { + ) -> Diag<'a> { fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String where T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, @@ -1101,7 +1101,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let ty::FnPtr(sig) = by_ref_captures.kind() && !sig.skip_binder().output().is_unit() { - let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn { + let mut err = self.dcx().create_err(AsyncClosureNotFn { span: self.tcx.def_span(closure_def_id), kind: expected_kind.as_str(), }); @@ -1351,7 +1351,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let span = obligation.cause.span; let mut diag = match ty.kind() { @@ -1445,8 +1445,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } -#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)] -impl<'tcx> TypeErrCtxt<'_, 'tcx> { +#[extension(pub(super) trait InferCtxtPrivExt<'a, 'tcx>)] +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_trait( &self, goal: ty::TraitPredicate<'tcx>, @@ -2884,7 +2884,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = - self.tcx.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion) + self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion) && let Ok(ref mut s1) = err.suggestions && let Ok(ref mut s2) = diag.suggestions { @@ -3379,7 +3379,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { found_kind: ty::ClosureKind, kind: ty::ClosureKind, trait_prefix: &'static str, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let closure_span = self.tcx.def_span(closure_def_id); let mut err = ClosureKindMismatch { @@ -3422,7 +3422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { found_trait_ref: ty::TraitRef<'tcx>, expected_trait_ref: ty::TraitRef<'tcx>, terr: TypeError<'tcx>, - ) -> Diag<'tcx> { + ) -> Diag<'a> { let self_ty = found_trait_ref.self_ty(); let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() { ( @@ -3473,7 +3473,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, found_trait_ref: ty::TraitRef<'tcx>, expected_trait_ref: ty::TraitRef<'tcx>, - ) -> Result<Diag<'tcx>, ErrorGuaranteed> { + ) -> Result<Diag<'a>, ErrorGuaranteed> { let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); @@ -3553,7 +3553,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) .unwrap_or((found_span, None, found)); - self.report_arg_count_mismatch( + self.infcx.report_arg_count_mismatch( span, closure_span, expected, @@ -3569,7 +3569,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, span: Span, - ) -> Result<Diag<'tcx>, ErrorGuaranteed> { + ) -> Result<Diag<'a>, ErrorGuaranteed> { if !self.tcx.features().generic_const_exprs { let guar = self .dcx() diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4d10d33fa6e..f1611bd049d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -187,7 +187,7 @@ fn predicates_reference_self( ) -> SmallVec<[Span; 1]> { let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); let predicates = if supertraits_only { - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) } else { tcx.predicates_of(trait_def_id) }; @@ -256,7 +256,7 @@ fn super_predicates_have_non_lifetime_binders( if !tcx.features().non_lifetime_binders { return SmallVec::new(); } - tcx.super_predicates_of(trait_def_id) + tcx.explicit_super_predicates_of(trait_def_id) .predicates .iter() .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(*span)) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8c5dc88184c..9508a3e8e15 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -574,7 +574,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check supertraits hold. This is so that their associated type bounds // will be checked in the code below. for super_trait in tcx - .super_predicates_of(trait_predicate.def_id()) + .explicit_super_predicates_of(trait_predicate.def_id()) .instantiate(tcx, trait_predicate.trait_ref.args) .predicates .into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f132e36468a..951af4b0920 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -128,7 +128,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { } // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); + let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id()); debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 017b0a45d1f..e54ced85dee 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -117,7 +117,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); let mut direct_super_traits_iter = tcx - .super_predicates_of(inner_most_trait_ref.def_id()) + .explicit_super_predicates_of(inner_most_trait_ref.def_id()) .predicates .into_iter() .filter_map(move |(pred, _)| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 4395eb57cd6..6726db8bb54 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,8 +4,9 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_span::sym; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -14,6 +15,7 @@ pub(crate) fn provide(providers: &mut Providers) { associated_item_def_ids, associated_items, associated_types_for_impl_traits_in_associated_fn, + associated_type_for_effects, associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers @@ -44,7 +46,8 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied(), - ), + ) + .chain(tcx.associated_type_for_effects(def_id)), ) } hir::ItemKind::Impl(impl_) => { @@ -70,7 +73,8 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { ) }) .copied() - })), + })) + .chain(tcx.associated_type_for_effects(def_id)), ) } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), @@ -143,6 +147,7 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty container: ty::TraitContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, + is_effects_desugaring: false, } } @@ -162,9 +167,138 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::ImplContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, + is_effects_desugaring: false, } } +/// Given an `def_id` of a trait or a trait impl: +/// +/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes +/// a new def id corresponding to a new associated type for the effects. +/// +/// If `def_id` is an impl, then synthesize the associated type according +/// to the constness of the impl. +fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { + // don't synthesize the associated type even if the user has written `const_trait` + // if the effects feature is disabled. + if !tcx.features().effects { + return None; + } + let (feed, parent_did) = match tcx.def_kind(def_id) { + DefKind::Trait => { + let trait_def_id = def_id; + let attr = tcx.get_attr(def_id, sym::const_trait)?; + + let span = attr.span; + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); + + let local_def_id = trait_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + // Copy span of the attribute. + trait_assoc_ty.def_ident_span(Some(span)); + + trait_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: None, + container: ty::TraitContainer, + fn_has_self_parameter: false, + opt_rpitit_info: None, + is_effects_desugaring: true, + }); + + // No default type + trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false }); + + trait_assoc_ty.is_type_alias_impl_trait(false); + + (trait_assoc_ty, trait_def_id) + } + DefKind::Impl { .. } => { + let impl_def_id = def_id; + let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?; + + // first get the DefId of the assoc type on the trait, if there is not, + // then we don't need to generate it on the impl. + let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?; + + // FIXME(effects): span + let span = tcx.def_ident_span(def_id).unwrap(); + + let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy); + + let local_def_id = impl_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + impl_assoc_ty.def_ident_span(Some(span)); + + impl_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: Some(trait_assoc_id), + container: ty::ImplContainer, + fn_has_self_parameter: false, + opt_rpitit_info: None, + is_effects_desugaring: true, + }); + + // no default value. + impl_assoc_ty.defaultness(hir::Defaultness::Final); + + // set the type of the associated type! If this is a const impl, + // we set to Maybe, otherwise we set to `Runtime`. + let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) { + tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span)) + } else { + tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span)) + }; + // FIXME(effects): make impls use `Min` for their effect types + impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt( + tcx, + tcx.adt_def(type_def_id), + ty::GenericArgs::empty(), + ))); + + (impl_assoc_ty, impl_def_id) + } + def_kind => bug!( + "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}", + def_id, + def_kind + ), + }; + + feed.feed_hir(); + + // visibility is public. + feed.visibility(ty::Visibility::Public); + + // Copy generics_of of the trait/impl, making the trait/impl as parent. + feed.generics_of({ + let parent_generics = tcx.generics_of(parent_did); + let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); + + ty::Generics { + parent: Some(parent_did.to_def_id()), + parent_count, + own_params: vec![], + param_def_id_to_index: parent_generics.param_def_id_to_index.clone(), + has_self: false, + has_late_bound_regions: None, + host_effect_index: parent_generics.host_effect_index, + } + }); + feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[])); + + // There are no inferred outlives for the synthesized associated type. + feed.inferred_outlives_of(&[]); + + Some(feed.def_id().to_def_id()) +} + /// Given an `fn_def_id` of a trait or a trait implementation: /// /// if `fn_def_id` is a function defined inside a trait, then it synthesizes @@ -275,6 +409,7 @@ fn associated_type_for_impl_trait_in_trait( fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), + is_effects_desugaring: false, }); // Copy visility of the containing function. @@ -326,6 +461,7 @@ fn associated_type_for_impl_trait_in_impl( container: ty::ImplContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), + is_effects_desugaring: false, }); // Copy visility of the containing function. diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs new file mode 100644 index 00000000000..f7942f2f982 --- /dev/null +++ b/compiler/rustc_type_ir/src/effects.rs @@ -0,0 +1,59 @@ +use crate::inherent::{AdtDef, IntoKind, Ty}; +use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime}; +use crate::Interner; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum EffectKind { + Maybe, + Runtime, + NoRuntime, +} + +impl EffectKind { + pub fn try_from_def_id<I: Interner>(tcx: I, def_id: I::DefId) -> Option<EffectKind> { + if tcx.is_lang_item(def_id, EffectsMaybe) { + Some(EffectKind::Maybe) + } else if tcx.is_lang_item(def_id, EffectsRuntime) { + Some(EffectKind::Runtime) + } else if tcx.is_lang_item(def_id, EffectsNoRuntime) { + Some(EffectKind::NoRuntime) + } else { + None + } + } + + pub fn to_def_id<I: Interner>(self, tcx: I) -> I::DefId { + let lang_item = match self { + EffectKind::Maybe => EffectsMaybe, + EffectKind::NoRuntime => EffectsNoRuntime, + EffectKind::Runtime => EffectsRuntime, + }; + + tcx.require_lang_item(lang_item) + } + + pub fn try_from_ty<I: Interner>(tcx: I, ty: I::Ty) -> Option<EffectKind> { + if let crate::Adt(def, _) = ty.kind() { + Self::try_from_def_id(tcx, def.def_id()) + } else { + None + } + } + + pub fn to_ty<I: Interner>(self, tcx: I) -> I::Ty { + I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) + } + + /// Returns an intersection between two effect kinds. If one effect kind + /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this + /// returns the less permissive effect kind (`Runtime`). + pub fn intersection(a: Self, b: Self) -> Option<Self> { + use EffectKind::*; + match (a, b) { + (Maybe, x) | (x, Maybe) => Some(x), + (Runtime, Runtime) => Some(Runtime), + (NoRuntime, NoRuntime) => Some(NoRuntime), + (Runtime, NoRuntime) | (NoRuntime, Runtime) => None, + } + } +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b89ea30fc34..6665158c7cd 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -209,8 +209,7 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; - // FIXME: Rename this so it's obvious it's only *immediate* super predicates. - fn super_predicates_of( + fn explicit_super_predicates_of( self, def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index cf5ec1ab3fe..cf00c37caa2 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -17,6 +17,11 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsMaybe, + EffectsNoRuntime, + EffectsRuntime, FnPtrTrait, FusedIterator, Future, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 9b8ca5efdda..d7442e7c89c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -35,6 +35,7 @@ mod macros; mod binder; mod canonical; mod const_kind; +mod effects; mod flags; mod generic_arg; mod interner; @@ -51,6 +52,7 @@ pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; pub use const_kind::*; +pub use effects::*; pub use flags::*; pub use generic_arg::*; pub use interner::*; |
