diff options
Diffstat (limited to 'compiler')
177 files changed, 2407 insertions, 1686 deletions
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 6e42cf37b86..4f21ff41529 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -11,12 +11,11 @@ #![doc(rust_logo)] #![allow(internal_features)] #![feature(rustdoc_internals)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(never_type)] #![feature(negative_impls)] #![feature(stmt_expr_attributes)] diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 5ccc7d51066..c17020ed663 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym}; +#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint. #[allow(hidden_glob_reexports)] use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP}; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 41f7418ddde..d802dbbcb9e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -157,7 +157,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::AddrOf(*k, *m, ohs) } ExprKind::Let(pat, scrutinee, span, is_recovered) => { - hir::ExprKind::Let(self.arena.alloc(hir::Let { + hir::ExprKind::Let(self.arena.alloc(hir::LetExpr { span: self.lower_span(*span), pat: self.lower_pat(pat), ty: None, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 793fe9cfd5e..9078b1f889c 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -55,7 +55,7 @@ pub(super) fn index_hir<'hir>( OwnerNode::TraitItem(item) => collector.visit_trait_item(item), OwnerNode::ImplItem(item) => collector.visit_impl_item(item), OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item), - OwnerNode::AssocOpaqueTy(..) => unreachable!(), + OwnerNode::Synthetic => unreachable!(), }; for (local_id, node) in collector.nodes.iter_enumerated() { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6a7ee936f66..d2744e8ff68 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,7 +55,9 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate}; +use rustc_hir::{ + ConstArg, GenericArg, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate, +}; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::span_bug; @@ -797,7 +799,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Param { .. } => { (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) } - LifetimeRes::Fresh { param, .. } => { + LifetimeRes::Fresh { param, kind, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( self.current_hir_id_owner.def_id, @@ -808,7 +810,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); debug!(?_def_id); - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) + (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind)) } LifetimeRes::Static | LifetimeRes::Error => return None, res => panic!( @@ -1605,13 +1607,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { for lifetime in captured_lifetimes_to_duplicate { let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - let old_def_id = match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id, + let (old_def_id, missing_kind) = match res { + LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None), - LifetimeRes::Fresh { param, binder: _ } => { + LifetimeRes::Fresh { param, kind, .. } => { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); if let Some(old_def_id) = self.orig_opt_local_def_id(param) { - old_def_id + (old_def_id, Some(kind)) } else { self.dcx() .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); @@ -1651,6 +1653,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { duplicated_lifetime_node_id, duplicated_lifetime_def_id, self.lower_ident(lifetime.ident), + missing_kind, )); // Now make an arg that we can use for the generic params of the opaque tykind. @@ -1668,27 +1671,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bounds = this .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); - let generic_params = this.arena.alloc_from_iter( - synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| { - let hir_id = this.lower_node_id(new_node_id); - let (name, kind) = if ident.name == kw::UnderscoreLifetime { - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) - } else { - (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) - }; + let generic_params = + this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( + |&(new_node_id, new_def_id, ident, missing_kind)| { + let hir_id = this.lower_node_id(new_node_id); + let (name, kind) = if ident.name == kw::UnderscoreLifetime { + ( + hir::ParamName::Fresh, + hir::LifetimeParamKind::Elided( + missing_kind.unwrap_or(MissingLifetimeKind::Underscore), + ), + ) + } else { + (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) + }; - hir::GenericParam { - hir_id, - def_id: new_def_id, - name, - span: ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }), - ); + hir::GenericParam { + hir_id, + def_id: new_def_id, + name, + span: ident.span, + pure_wrt_drop: false, + kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, + source: hir::GenericParamSource::Generics, + } + }, + )); debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 4db8ffd3e54..2c396a64789 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -463,13 +463,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { constraint.span, "return type notation is experimental" ); - } else { - gate!( - &self, - associated_type_bounds, - constraint.span, - "associated type bounds are unstable" - ); } } visit::walk_assoc_constraint(self, constraint) @@ -615,7 +608,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { } gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); - gate_all_legacy_dont_use!(associated_type_bounds, "associated type bounds are unstable"); // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now, // used to be gated under associated_type_bounds, which are right above, so RTN needs to // be too. diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index f2ca509e14b..587536e1f9a 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -132,6 +132,12 @@ borrowck_moved_due_to_usage_in_operator = *[false] operator } +borrowck_opaque_type_lifetime_mismatch = + opaque type used twice with different lifetimes + .label = lifetime `{$arg}` used here + .prev_lifetime_label = lifetime `{$prev}` previously used here + .note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types + borrowck_opaque_type_non_generic_param = expected generic {$kind} parameter, found `{$ty}` .label = {STREQ($ty, "'static") -> diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0109f188772..aa98d060f5f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -716,7 +716,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .copied() .find_map(find_fn_kind_from_did), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx - .explicit_item_bounds(def_id) + .explicit_item_super_predicates(def_id) .iter_instantiated_copied(tcx, args) .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))), ty::Closure(_, args) => match args.as_closure().kind() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a27d016e0ba..36c2723b66d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -2,7 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] use core::ops::ControlFlow; -use hir::ExprKind; +use hir::{ExprKind, Param}; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -725,25 +725,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => local_decl.source_info.span, }; - let def_id = self.body.source.def_id(); - let hir_id = if let Some(local_def_id) = def_id.as_local() - && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) - { - let body = self.infcx.tcx.hir().body(body_id); - BindingFinder { span: pat_span }.visit_body(body).break_value() - } else { - None - }; - // With ref-binding patterns, the mutability suggestion has to apply to // the binding, not the reference (which would be a type error): // // `let &b = a;` -> `let &(mut b) = a;` - if let Some(hir_id) = hir_id + // or + // `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)` + let def_id = self.body.source.def_id(); + if let Some(local_def_id) = def_id.as_local() + && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) + && let body = self.infcx.tcx.hir().body(body_id) + && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value() + && let node = self.infcx.tcx.hir_node(hir_id) && let hir::Node::Local(hir::Local { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. - }) = self.infcx.tcx.hir_node(hir_id) + }) + | hir::Node::Param(Param { + pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, + .. + }) = node && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { @@ -1310,6 +1311,16 @@ impl<'tcx> Visitor<'tcx> for BindingFinder { hir::intravisit::walk_stmt(self, s) } } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result { + if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat + && *span == self.span + { + ControlFlow::Break(param.hir_id) + } else { + ControlFlow::Continue(()) + } + } } pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 415ba095a1b..9f4f88b2b93 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -4,7 +4,7 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_chains)] diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 8a172233037..193b6d3e3d9 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -9,17 +9,77 @@ use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::RegionVid; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::ObligationCtxt; +use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::session_diagnostics::NonGenericOpaqueTypeParam; use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { + fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> { + let scc = self.constraint_sccs.scc(vid); + self.scc_values + .universal_regions_outlived_by(scc) + .find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)) + } + + fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> { + let region = arg.as_region()?; + + if let ty::RePlaceholder(..) = region.kind() { + None + } else { + Some(self.to_region_vid(region)) + } + } + + /// Check that all opaque types have the same region parameters if they have the same + /// non-region parameters. This is necessary because within the new solver we perform various query operations + /// modulo regions, and thus could unsoundly select some impls that don't hold. + fn check_unique( + &self, + infcx: &InferCtxt<'tcx>, + opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, + ) { + for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() { + for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) { + if a.def_id != b.def_id { + continue; + } + // Non-lifetime params differ -> ok + if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) { + continue; + } + trace!(?a, ?b); + for (a, b) in a.args.iter().zip(b.args) { + trace!(?a, ?b); + let Some(r1) = self.generic_arg_to_region(a) else { + continue; + }; + let Some(r2) = self.generic_arg_to_region(b) else { + continue; + }; + if self.eval_equal(r1, r2) { + continue; + } + + infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { + arg: self.universal_name(r1).unwrap().into(), + prev: self.universal_name(r2).unwrap().into(), + span: a_ty.span, + prev_span: b_ty.span, + }); + } + } + } + } + /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. /// @@ -65,6 +125,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { + self.check_unique(infcx, &opaque_ty_decls); + let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); let member_constraints: FxIndexMap<_, _> = self @@ -80,26 +142,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut arg_regions = vec![self.universal_regions.fr_static]; - let to_universal_region = |vid, arg_regions: &mut Vec<_>| { - trace!(?vid); - let scc = self.constraint_sccs.scc(vid); - trace!(?scc); - match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| { - self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?) - }) { - Some(region) => { - let vid = self.universal_regions.to_region_vid(region); - arg_regions.push(vid); - region - } - None => { - arg_regions.push(vid); - ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "opaque type with non-universal region args", - ) - } + let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid) + { + Some(region) => { + let vid = self.universal_regions.to_region_vid(region); + arg_regions.push(vid); + region + } + None => { + arg_regions.push(vid); + ty::Region::new_error_with_message( + infcx.tcx, + concrete_type.span, + "opaque type with non-universal region args", + ) } }; @@ -378,10 +434,6 @@ fn check_opaque_type_parameter_valid( // Only check the parent generics, which will ignore any of the // duplicated lifetime args that come from reifying late-bounds. for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() { - if let Err(guar) = arg.error_reported() { - return Err(guar); - } - let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) if is_ty_alias => { diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 77021ae4321..40c2ef1c91e 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -304,6 +304,19 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { pub param_span: Span, } +#[derive(Diagnostic)] +#[diag(borrowck_opaque_type_lifetime_mismatch)] +pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> { + pub arg: GenericArg<'tcx>, + pub prev: GenericArg<'tcx>, + #[primary_span] + #[label] + #[note] + pub span: Span, + #[label(borrowck_prev_lifetime_label)] + pub prev_span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum CaptureReasonLabel<'a> { #[label(borrowck_moved_due_to_call)] diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index e5ebf97cfc4..a673c4c2aca 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ok(output) } - pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>( + pub(super) fn instantiate_canonical<T>( &mut self, span: Span, canonical: &Canonical<'tcx, T>, @@ -69,8 +69,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - let (instantiated, _) = - self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + let (instantiated, _) = self.infcx.instantiate_canonical(span, canonical); instantiated } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 8af78b08f69..a4c1066ee8e 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -39,8 +39,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // (e.g., the `_` in the code above) with fresh variables. // Then replace the bound items in the fn sig with fresh variables, // so that they represent the view from "inside" the closure. - let user_provided_sig = self - .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); + let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig); let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( body.span, BoundRegionConversionTime::FnCall, @@ -88,7 +87,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.tcx(), ty::CoroutineArgsParts { parent_args: args.parent_args(), - kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()), + kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), return_ty: user_provided_sig.output(), tupled_upvars_ty, // For async closures, none of these can be annotated, so just fill diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 412d50f493e..acda2a7524c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1109,7 +1109,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.tcx(); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; - let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); + let annotation = self.instantiate_canonical(span, user_ty); if let ty::UserType::TypeOf(def, args) = annotation && let DefKind::InlineConst = tcx.def_kind(def) { diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 62c02817011..76805617c93 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -189,7 +189,7 @@ pub fn parse_asm_args<'a>( args.templates.push(template); continue; } else { - return p.unexpected(); + p.unexpected_any()? }; allow_templates = false; diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 35a0857fe51..5905bdd7108 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -151,7 +151,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes }; if parser.token != token::Eof { - return parser.unexpected(); + parser.unexpected()?; } Ok(Assert { cond_expr, custom_message }) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index c802d9bbefb..25694af78f1 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -757,13 +757,6 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - sym::ptr_guaranteed_cmp => { - intrinsic_args!(fx, args => (a, b); intrinsic); - - let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b).load_scalar(fx); - ret.write_cvalue(fx, CValue::by_val(val, fx.layout_of(fx.tcx.types.u8))); - } - sym::caller_location => { intrinsic_args!(fx, args => (); intrinsic); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a4ee3015b8d..345c22394f2 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -19,11 +19,11 @@ #![feature( rustc_private, decl_macro, - associated_type_bounds, never_type, trusted_len, hash_raw_entry )] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index c3f17563b0a..649ff9df2cc 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -315,6 +315,7 @@ pub unsafe fn create_module<'ll>( // // On the wasm targets it will get hooked up to the "producer" sections // `processed-by` information. + #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); let name_metadata = llvm::LLVMMDStringInContext( diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 87b6f0e914c..b19f52182b6 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -81,10 +81,6 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S return library.kind.is_statically_included().then_some(def_id); } - if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) { - return None; - } - // Only consider nodes that actually have exported symbols. match tcx.def_kind(def_id) { DefKind::Fn | DefKind::Static { .. } => {} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 92f0be541c0..9be8dcf166d 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -4,7 +4,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index ba023f96107..5532ff6e6a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,7 +1,6 @@ use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::FunctionCx; -use crate::common::IntPredicate; use crate::errors; use crate::errors::InvalidMonomorphization; use crate::meth; @@ -456,12 +455,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } - sym::ptr_guaranteed_cmp => { - let a = args[0].immediate(); - let b = args[1].immediate(); - bx.icmp(IntPredicate::IntEQ, a, b) - } - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { let ty = fn_args.type_at(0); let pointee_size = bx.layout_of(ty).size; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 7b7cdae0ed6..df564f705bc 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -2,6 +2,7 @@ use crate::base; use crate::common; use crate::traits::*; use rustc_hir as hir; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty; @@ -40,23 +41,34 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { .iter() .map(|(op, op_sp)| match *op { hir::InlineAsmOperand::Const { ref anon_const } => { - let const_value = cx - .tcx() - .const_eval_poly(anon_const.def_id.to_def_id()) - .unwrap_or_else(|_| { - span_bug!(*op_sp, "asm const cannot be resolved") - }); - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); - let string = common::asm_const_to_str( - cx.tcx(), - *op_sp, - const_value, - cx.layout_of(ty), - ); - GlobalAsmOperandRef::Const { string } + match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(const_value) => { + let ty = cx + .tcx() + .typeck_body(anon_const.body) + .node_type(anon_const.hir_id); + let string = common::asm_const_to_str( + cx.tcx(), + *op_sp, + const_value, + cx.layout_of(ty), + ); + GlobalAsmOperandRef::Const { string } + } + Err(ErrorHandled::Reported { .. }) => { + // An error has already been reported and + // compilation is guaranteed to fail if execution + // hits this path. So an empty string instead of + // a stringified constant value will suffice. + GlobalAsmOperandRef::Const { string: String::new() } + } + Err(ErrorHandled::TooGeneric(_)) => { + span_bug!( + *op_sp, + "asm const cannot be resolved; too generic" + ) + } + } } hir::InlineAsmOperand::SymFn { ref anon_const } => { let ty = cx diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 730e8977803..3283bcc4c45 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1034,8 +1034,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx> { trace!("{:?} is now live", local); - // We avoid `ty.is_trivially_sized` since that (a) cannot assume WF, so it recurses through - // all fields of a tuple, and (b) does something expensive for ADTs. + // We avoid `ty.is_trivially_sized` since that does something expensive for ADTs. fn is_very_trivially_sized(ty: Ty<'_>) -> bool { match ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -1054,9 +1053,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 17bb59aae8f..58eaef65e55 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -111,6 +111,8 @@ fn intern_as_new_static<'tcx>( feed.generics_of(tcx.generics_of(static_id).clone()); feed.def_ident_span(tcx.def_ident_span(static_id)); feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id)); + + feed.feed_hir() } /// How a constant value should be interned. @@ -291,7 +293,9 @@ pub fn intern_const_alloc_for_constprop< return Ok(()); } // Move allocation to `tcx`. - for _ in intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))? { + if let Some(_) = + (intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?).next() + { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 15720f25c5c..e87e60f62dc 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -99,7 +99,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self; - let ConstCx { tcx, param_env, .. } = *ccx; + let ConstCx { tcx, param_env, body, .. } = *ccx; let diag_trait = |err, self_ty: Ty<'_>, trait_id| { let trait_ref = TraitRef::from_method(tcx, trait_id, args); @@ -297,10 +297,12 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); - if let Some(feature) = feature - && ccx.tcx.sess.is_nightly_build() - { - err.help(format!("add `#![feature({feature})]` to the crate attributes to enable",)); + if let Some(feature) = feature { + ccx.tcx.disabled_nightly_features( + &mut err, + body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)), + [(String::new(), feature)], + ); } if let ConstContext::Static(_) = ccx.const_kind() { diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 040a8aa6b63..756984642c7 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -189,6 +189,7 @@ mod no_sync { use super::Mode; use std::cell::RefCell; + #[doc(no_inline)] pub use std::cell::RefMut as LockGuard; pub struct Lock<T>(RefCell<T>); diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md index 057a0b1645c..cd981db1058 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0719.md +++ b/compiler/rustc_error_codes/src/error_codes/E0719.md @@ -3,8 +3,6 @@ An associated type value was specified more than once. Erroneous code example: ```compile_fail,E0719 -#![feature(associated_type_bounds)] - trait FooTrait {} trait BarTrait {} @@ -19,8 +17,6 @@ specify the associated type with the new trait. Corrected example: ``` -#![feature(associated_type_bounds)] - trait FooTrait {} trait BarTrait {} trait FooBarTrait: FooTrait + BarTrait {} diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4f033e3fefa..fceccb7e9b6 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1638,6 +1638,27 @@ impl HumanEmitter { *style, ); } + if let Some(line) = annotated_file.lines.get(line_idx) { + for ann in &line.annotations { + if let AnnotationType::MultilineStart(pos) = ann.annotation_type + { + // In the case where we have elided the entire start of the + // multispan because those lines were empty, we still need + // to draw the `|`s across the `...`. + draw_multiline_line( + &mut buffer, + last_buffer_line_num, + width_offset, + pos, + if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }, + ); + } + } + } } else if line_idx_delta == 2 { let unannotated_line = annotated_file .file @@ -1665,6 +1686,24 @@ impl HumanEmitter { *style, ); } + if let Some(line) = annotated_file.lines.get(line_idx) { + for ann in &line.annotations { + if let AnnotationType::MultilineStart(pos) = ann.annotation_type + { + draw_multiline_line( + &mut buffer, + last_buffer_line_num, + width_offset, + pos, + if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }, + ); + } + } + } } } @@ -2417,7 +2456,15 @@ impl FileWithAnnotatedLines { // the beginning doesn't have an underline, but the current logic seems to be // working correctly. let middle = min(ann.line_start + 4, ann.line_end); - for line in ann.line_start + 1..middle { + // We'll show up to 4 lines past the beginning of the multispan start. + // We will *not* include the tail of lines that are only whitespace. + let until = (ann.line_start..middle) + .rev() + .filter_map(|line| file.get_line(line - 1).map(|s| (line + 1, s))) + .find(|(_, s)| !s.trim().is_empty()) + .map(|(line, _)| line) + .unwrap_or(ann.line_start); + for line in ann.line_start + 1..until { // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`). add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 723f13dbe8d..238bc63ec58 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,7 +7,6 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index e550f7242c3..c9a3aeedd02 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,7 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(array_windows)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(associated_type_defaults)] #![feature(if_let_guard)] #![feature(let_chains)] @@ -12,6 +12,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_span)] #![feature(try_blocks)] +#![feature(yeet_expr)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 8a68b39e496..c8983619e70 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -62,7 +62,7 @@ pub(crate) fn parse_external_mod( // Ensure file paths are acyclic. if let Some(pos) = module.file_path_stack.iter().position(|p| p == &mp.file_path) { - Err(ModError::CircularInclusion(module.file_path_stack[pos..].to_vec()))?; + do yeet ModError::CircularInclusion(module.file_path_stack[pos..].to_vec()); } // Actually parse the external file as a module. diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index a3510dc9bff..2b0b58eb1d9 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -276,8 +276,7 @@ error: foo | 2 | fn foo() { | __________^ -3 | | -4 | | +... | 5 | | } | |___^ test diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 7e5197f16f9..a83f9f56beb 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -59,6 +59,8 @@ declare_features! ( (accepted, asm_sym, "1.66.0", Some(93333)), /// Allows the definition of associated constants in `trait` or `impl` blocks. (accepted, associated_consts, "1.20.0", Some(29646)), + /// Allows the user of associated type bounds. + (accepted, associated_type_bounds, "CURRENT_RUSTC_VERSION", Some(52662)), /// Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None), /// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions. @@ -85,7 +87,7 @@ declare_features! ( /// Enables `#[cfg(panic = "...")]` config key. (accepted, cfg_panic, "1.60.0", Some(77443)), /// Allows `cfg(target_abi = "...")`. - (accepted, cfg_target_abi, "CURRENT_RUSTC_VERSION", Some(80970)), + (accepted, cfg_target_abi, "1.78.0", Some(80970)), /// Allows `cfg(target_feature = "...")`. (accepted, cfg_target_feature, "1.27.0", Some(29717)), /// Allows `cfg(target_vendor = "...")`. @@ -147,7 +149,7 @@ declare_features! ( /// Allows the use of destructuring assignments. (accepted, destructuring_assignment, "1.59.0", Some(71126)), /// Allows using the `#[diagnostic]` attribute tool namespace - (accepted, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(111996)), + (accepted, diagnostic_namespace, "1.78.0", Some(111996)), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146)), /// Allows `..` in tuple (struct) patterns. @@ -203,6 +205,8 @@ declare_features! ( (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872)), /// Allows referencing `Self` and projections in impl-trait. (accepted, impl_trait_projections, "1.74.0", Some(103532)), + /// Allows using imported `main` function + (accepted, imported_main, "CURRENT_RUSTC_VERSION", Some(28937)), /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237)), /// Allows inferring outlives requirements (RFC 2093). diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e5a29f3a846..d4d7833cb21 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -150,16 +150,6 @@ pub enum AttributeDuplicates { FutureWarnPreceding, } -/// A convenience macro to deal with `$($expr)?`. -macro_rules! or_default { - ($default:expr,) => { - $default - }; - ($default:expr, $next:expr) => { - $next - }; -} - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -181,10 +171,10 @@ macro_rules! template { } macro_rules! ungated { - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)? $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, - only_local: or_default!(false, $($only_local)?), + encode_cross_crate: $encode_cross_crate, type_: $typ, template: $tpl, gate: Ungated, @@ -194,20 +184,20 @@ macro_rules! ungated { } macro_rules! gated { - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $gate:ident, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, - only_local: or_default!(false, $($only_local)?), + encode_cross_crate: $encode_cross_crate, type_: $typ, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, - only_local: or_default!(false, $($only_local)?), + encode_cross_crate: $encode_cross_crate, type_: $typ, template: $tpl, duplicates: $duplicates, @@ -217,13 +207,13 @@ macro_rules! gated { } macro_rules! rustc_attr { - (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(, @only_local: $only_local:expr)? $(,)?) => { + (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr, $encode_cross_crate:expr $(,)?) => { rustc_attr!( $attr, $typ, $tpl, $duplicate, - $(@only_local: $only_local,)? + $encode_cross_crate, concat!( "the `#[", stringify!($attr), @@ -232,10 +222,10 @@ macro_rules! rustc_attr { ), ) }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, - only_local: or_default!(false, $($only_local)?), + encode_cross_crate: $encode_cross_crate, type_: $typ, template: $tpl, duplicates: $duplicates, @@ -253,12 +243,19 @@ macro_rules! experimental { const IMPL_DETAIL: &str = "internal implementation detail"; const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; +#[derive(PartialEq)] +pub enum EncodeCrossCrate { + Yes, + No, +} + pub struct BuiltinAttribute { pub name: Symbol, - /// Whether this attribute is only used in the local crate. + /// Whether this attribute is encode cross crate. /// - /// If so, it is not encoded in the crate metadata. - pub only_local: bool, + /// If so, it is encoded in the crate metadata. + /// Otherwise, it can only be used in the local crate. + pub encode_cross_crate: EncodeCrossCrate, pub type_: AttributeType, pub template: AttributeTemplate, pub duplicates: AttributeDuplicates, @@ -273,65 +270,71 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== // Conditional compilation: - ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk), - ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk), + ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk, EncodeCrossCrate::Yes), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk, EncodeCrossCrate::Yes), // Testing: ungated!( ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, - @only_local: true, + EncodeCrossCrate::No, ), ungated!( should_panic, Normal, template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing, - @only_local: true, + EncodeCrossCrate::No, ), // FIXME(Centril): This can be used on stable but shouldn't. ungated!( reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing, - @only_local: true, + EncodeCrossCrate::No, ), // Macros: - ungated!(automatically_derived, Normal, template!(Word), WarnFollowing), + ungated!(automatically_derived, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), ungated!( macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly, - @only_local: true, + EncodeCrossCrate::No, ), - ungated!(macro_escape, Normal, template!(Word), WarnFollowing, @only_local: true), // Deprecated synonym for `macro_use`. - ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing), - ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, @only_local: true), + ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`. + ungated!( + macro_export, Normal, template!(Word, List: "local_inner_macros"), + WarnFollowing, EncodeCrossCrate::Yes + ), + ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No), ungated!( proc_macro_derive, Normal, template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), - ErrorFollowing, @only_local: true, + ErrorFollowing, EncodeCrossCrate::No, ), - ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, @only_local: true), + ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No), // Lints: ungated!( warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - DuplicatesOk, @only_local: true, + DuplicatesOk, EncodeCrossCrate::No, ), ungated!( allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - DuplicatesOk, @only_local: true, + DuplicatesOk, EncodeCrossCrate::No, ), gated!( expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, - @only_local: true, lint_reasons, experimental!(expect) + EncodeCrossCrate::No, lint_reasons, experimental!(expect) ), ungated!( forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - DuplicatesOk, @only_local: true, + DuplicatesOk, EncodeCrossCrate::No ), ungated!( deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - DuplicatesOk, @only_local: true, + DuplicatesOk, EncodeCrossCrate::No + ), + ungated!( + must_use, Normal, template!(Word, NameValueStr: "reason"), + FutureWarnFollowing, EncodeCrossCrate::Yes ), - ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), gated!( must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, - experimental!(must_not_suspend) + EncodeCrossCrate::Yes, experimental!(must_not_suspend) ), ungated!( deprecated, Normal, @@ -340,22 +343,22 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, NameValueStr: "reason" ), - ErrorFollowing + ErrorFollowing, EncodeCrossCrate::Yes ), // Crate properties: ungated!( crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing, - @only_local: true, + EncodeCrossCrate::No, ), ungated!( crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk, - @only_local: true, + EncodeCrossCrate::No, ), // crate_id is deprecated ungated!( crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing, - @only_local: true, + EncodeCrossCrate::No, ), // ABI, linking, symbols, and FFI @@ -363,81 +366,88 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ link, Normal, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#), DuplicatesOk, - @only_local: true, + EncodeCrossCrate::No, + ), + ungated!( + link_name, Normal, template!(NameValueStr: "name"), + FutureWarnPreceding, EncodeCrossCrate::Yes ), - ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), - ungated!(no_link, Normal, template!(Word), WarnFollowing, @only_local: true), - ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), - ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, @only_local: true), - ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, @only_local: true), - ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), - ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), - ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding), + ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), + ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), + ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), // Limits: ungated!( recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing, - @only_local: true + EncodeCrossCrate::No ), ungated!( type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing, - @only_local: true + EncodeCrossCrate::No ), gated!( move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing, - @only_local: true, large_assignments, experimental!(move_size_limit) + EncodeCrossCrate::No, large_assignments, experimental!(move_size_limit) ), // Entry point: - gated!(unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)), - ungated!(start, Normal, template!(Word), WarnFollowing, @only_local: true), - ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, @only_local: true), - ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, @only_local: true), + gated!( + unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, + EncodeCrossCrate::Yes, experimental!(unix_sigpipe) + ), + ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Modules, prelude, and resolution: - ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing, @only_local: true), - ungated!(no_std, CrateLevel, template!(Word), WarnFollowing, @only_local: true), - ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing, @only_local: true), - ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing), + ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing, EncodeCrossCrate::No), + ungated!(no_std, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // Runtime ungated!( windows_subsystem, CrateLevel, template!(NameValueStr: "windows|console"), FutureWarnFollowing, - @only_local: true + EncodeCrossCrate::No ), - ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070 + ungated!(panic_handler, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // RFC 2070 // Code generation: - ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), - ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), - ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), + ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, EncodeCrossCrate::No), + ungated!(cold, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), ungated!( target_feature, Normal, template!(List: r#"enable = "name""#), - DuplicatesOk, @only_local: true, + DuplicatesOk, EncodeCrossCrate::No, ), - ungated!(track_caller, Normal, template!(Word), WarnFollowing), - ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, @only_local: true), + ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), + ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No), gated!( no_sanitize, Normal, template!(List: "address, kcfi, memory, thread"), DuplicatesOk, - @only_local: true, experimental!(no_sanitize) + EncodeCrossCrate::No, experimental!(no_sanitize) ), gated!( coverage, Normal, template!(Word, List: "on|off"), - WarnFollowing, @only_local: true, + WarnFollowing, EncodeCrossCrate::No, coverage_attribute, experimental!(coverage) ), ungated!( - doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk + doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk, + EncodeCrossCrate::Yes ), // Debugging ungated!( debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), - DuplicatesOk, @only_local: true + DuplicatesOk, EncodeCrossCrate::No ), // ========================================================================== @@ -446,54 +456,55 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Linking: gated!( - naked, Normal, template!(Word), WarnFollowing, @only_local: true, + naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, naked_functions, experimental!(naked) ), // Testing: gated!( - test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks, + test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, + EncodeCrossCrate::Yes, custom_test_frameworks, "custom test frameworks are an unstable feature", ), // RFC #1268 gated!( - marker, Normal, template!(Word), WarnFollowing, @only_local: true, + marker, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, marker_trait_attr, experimental!(marker) ), gated!( - thread_local, Normal, template!(Word), WarnFollowing, @only_local: true, + thread_local, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "`#[thread_local]` is an experimental feature, and does not currently handle destructors", ), gated!( no_core, CrateLevel, template!(Word), WarnFollowing, - @only_local: true, experimental!(no_core) + EncodeCrossCrate::No, experimental!(no_core) ), // RFC 2412 gated!( optimize, Normal, template!(List: "size|speed"), ErrorPreceding, - @only_local: true, optimize_attribute, experimental!(optimize) + EncodeCrossCrate::No, optimize_attribute, experimental!(optimize) ), gated!( ffi_pure, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(ffi_pure) + EncodeCrossCrate::No, experimental!(ffi_pure) ), gated!( ffi_const, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(ffi_const) + EncodeCrossCrate::No, experimental!(ffi_const) ), gated!( register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk, - @only_local: true, experimental!(register_tool), + EncodeCrossCrate::No, experimental!(register_tool), ), gated!( cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(cmse_nonsecure_entry) + EncodeCrossCrate::No, experimental!(cmse_nonsecure_entry) ), // RFC 2632 gated!( - const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl, + const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, const_trait_impl, "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ `impls` and all default bodies as `const`, which may be removed or renamed in the \ future." @@ -501,25 +512,25 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // lang-team MCP 147 gated!( deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing, - experimental!(deprecated_safe), + EncodeCrossCrate::Yes, experimental!(deprecated_safe), ), // `#[collapse_debuginfo]` gated!( collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing, - @only_local: true, experimental!(collapse_debuginfo) + EncodeCrossCrate::No, experimental!(collapse_debuginfo) ), // RFC 2397 gated!( do_not_recommend, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(do_not_recommend) + EncodeCrossCrate::No, experimental!(do_not_recommend) ), // `#[cfi_encoding = ""]` gated!( cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding, - experimental!(cfi_encoding) + EncodeCrossCrate::Yes, experimental!(cfi_encoding) ), // ========================================================================== @@ -528,43 +539,48 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!( feature, CrateLevel, - template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true, + template!(List: "name1, name2, ..."), DuplicatesOk, EncodeCrossCrate::No, ), // DuplicatesOk since it has its own validation ungated!( stable, Normal, - template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true, + template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, EncodeCrossCrate::No, ), ungated!( unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, + EncodeCrossCrate::Yes + ), + ungated!( + rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + DuplicatesOk, EncodeCrossCrate::Yes ), - ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!( rustc_const_stable, Normal, - template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true, + template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::No, ), ungated!( rustc_default_body_unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), - DuplicatesOk, @only_local: true + DuplicatesOk, EncodeCrossCrate::No ), gated!( - allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + DuplicatesOk, EncodeCrossCrate::Yes, "allow_internal_unstable side-steps feature gating and stability checks", ), gated!( rustc_allow_const_fn_unstable, Normal, - template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, @only_local: true, + template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" ), gated!( allow_internal_unsafe, Normal, template!(Word), WarnFollowing, - @only_local: true, "allow_internal_unsafe side-steps the unsafe_code lint", + EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", ), rustc_attr!( rustc_allowed_through_unstable_modules, Normal, template!(Word), - WarnFollowing, @only_local: true, + WarnFollowing, EncodeCrossCrate::No, "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ through unstable paths" ), @@ -573,16 +589,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes: Type system related: // ========================================================================== - gated!(fundamental, Normal, template!(Word), WarnFollowing, experimental!(fundamental)), + gated!(fundamental, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, experimental!(fundamental)), gated!( may_dangle, Normal, template!(Word), WarnFollowing, - @only_local: true, dropck_eyepatch, + EncodeCrossCrate::No, dropck_eyepatch, "`may_dangle` has unstable semantics and may be removed in the future", ), rustc_attr!( rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing, - @only_local: true, + EncodeCrossCrate::No, "`rustc_never_type_fallback` is used to experiment with never type fallback and work on \ never type stabilization, and will never be stable" ), @@ -593,49 +609,49 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_allocator, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL + EncodeCrossCrate::No, IMPL_DETAIL ), rustc_attr!( rustc_nounwind, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL + EncodeCrossCrate::No, IMPL_DETAIL ), rustc_attr!( rustc_reallocator, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL + EncodeCrossCrate::No, IMPL_DETAIL ), rustc_attr!( rustc_deallocator, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL + EncodeCrossCrate::No, IMPL_DETAIL ), rustc_attr!( rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL + EncodeCrossCrate::No, IMPL_DETAIL ), gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, - @only_local: true, allocator_internals, experimental!(default_lib_allocator), + EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator), ), gated!( needs_allocator, Normal, template!(Word), WarnFollowing, - @only_local: true, allocator_internals, experimental!(needs_allocator), + EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator), ), gated!( panic_runtime, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(panic_runtime) + EncodeCrossCrate::No, experimental!(panic_runtime) ), gated!( needs_panic_runtime, Normal, template!(Word), WarnFollowing, - @only_local: true, experimental!(needs_panic_runtime) + EncodeCrossCrate::No, experimental!(needs_panic_runtime) ), gated!( compiler_builtins, Normal, template!(Word), WarnFollowing, - @only_local: true, + EncodeCrossCrate::No, "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ which contains compiler-rt intrinsics and will never be stable", ), gated!( profiler_runtime, Normal, template!(Word), WarnFollowing, - @only_local: true, + EncodeCrossCrate::No, "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ which contains the profiler runtime and will never be stable", ), @@ -645,11 +661,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== gated!( - linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, @only_local: true, + linkage, Normal, template!(NameValueStr: "external|internal|..."), + ErrorPreceding, EncodeCrossCrate::No, "the `linkage` attribute is experimental and not portable across platforms", ), rustc_attr!( - rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, @only_local: true, INTERNAL_UNSTABLE + rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::No, INTERNAL_UNSTABLE ), // ========================================================================== @@ -659,16 +677,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_builtin_macro, Normal, template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, - IMPL_DETAIL, + EncodeCrossCrate::Yes, IMPL_DETAIL ), rustc_attr!( rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, - @only_local: true, INTERNAL_UNSTABLE + EncodeCrossCrate::No, INTERNAL_UNSTABLE ), rustc_attr!( rustc_macro_transparency, Normal, template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, - "used internally for testing macro hygiene", + EncodeCrossCrate::Yes, "used internally for testing macro hygiene", ), // ========================================================================== @@ -681,36 +699,50 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, NameValueStr: "message" ), - ErrorFollowing, + ErrorFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), rustc_attr!( rustc_confusables, Normal, template!(List: r#""name1", "name2", ..."#), - ErrorFollowing, + ErrorFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE, ), // Enumerates "identity-like" conversion methods to suggest on type mismatch. rustc_attr!( - rustc_conversion_suggestion, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + rustc_conversion_suggestion, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), // Prevents field reads in the marked trait or method to be considered // during dead code analysis. rustc_attr!( - rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + rustc_trivial_field_reads, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), // Used by the `rustc::potential_query_instability` lint to warn methods which // might not be stable during incremental compilation. - rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + rustc_attr!( + rustc_lint_query_instability, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic // APIs. Any function with this attribute will be checked by that lint. - rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + rustc_attr!( + rustc_lint_diagnostics, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` // types (as well as any others in future). - rustc_attr!(rustc_lint_opt_ty, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), + rustc_attr!( + rustc_lint_opt_ty, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // Used by the `rustc::bad_opt_access` lint on fields // types (as well as any others in future). - rustc_attr!(rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), WarnFollowing, INTERNAL_UNSTABLE), + rustc_attr!( + rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), + WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + ), // ========================================================================== // Internal attributes, Const related: @@ -718,18 +750,20 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_promotable, Normal, template!(Word), WarnFollowing, - @only_local: true, IMPL_DETAIL), + EncodeCrossCrate::No, IMPL_DETAIL), rustc_attr!( rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, - INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), // Do not const-check this function's body. It will always get replaced during CTFE. rustc_attr!( - rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), // Ensure the argument to this function is &&str during const-check. rustc_attr!( - rustc_const_panic_str, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + rustc_const_panic_str, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::Yes, INTERNAL_UNSTABLE ), // ========================================================================== @@ -738,16 +772,19 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing, + EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ niche optimizations in libcore and libstd and will never be stable", ), rustc_attr!( rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing, + EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ niche optimizations in libcore and libstd and will never be stable", ), rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::Yes, "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ niche optimizations in libcore and libstd and will never be stable", ), @@ -756,27 +793,29 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Misc: // ========================================================================== gated!( - lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, @only_local: true, lang_items, + lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items, "language items are subject to change", ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), rustc_attr!( rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." ), rustc_attr!( - rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true, + rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." ), rustc_attr!( - rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: true, + rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." ), rustc_attr!( - rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, + rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( @@ -784,16 +823,17 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ AttributeType::Normal, template!(List: "implement_via_object = (true|false)"), ErrorFollowing, - @only_local: true, + EncodeCrossCrate::No, "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" ), rustc_attr!( - rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, + rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), + ErrorFollowing, EncodeCrossCrate::Yes, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ the given type by annotating all impl items with #[rustc_allow_incoherent_impl]." ), rustc_attr!( - rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, + rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "#[rustc_box] allows creating boxes \ and it is only intended to be used in `alloc`." ), @@ -801,7 +841,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ BuiltinAttribute { name: sym::rustc_diagnostic_item, // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. - only_local: false, + encode_cross_crate: EncodeCrossCrate::Yes, type_: Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, @@ -815,74 +855,74 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ gated!( // Used in resolve: prelude_import, Normal, template!(Word), WarnFollowing, - @only_local: true, "`#[prelude_import]` is for use by rustc only", + EncodeCrossCrate::No, "`#[prelude_import]` is for use by rustc only", ), gated!( - rustc_paren_sugar, Normal, template!(Word), WarnFollowing, @only_local: true, + rustc_paren_sugar, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, unboxed_closures, "unboxed_closures are still evolving", ), rustc_attr!( - rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true, + rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ overflow checking behavior of several libcore functions that are inlined \ across crates and will never be stable", ), rustc_attr!( rustc_reservation_impl, Normal, - template!(NameValueStr: "reservation message"), ErrorFollowing, + template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_reservation_impl]` attribute is internally used \ for reserving for `for<T> From<!> for T` impl" ), rustc_attr!( rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, - @only_local: true, "the `#[rustc_test_marker]` attribute is used internally to track tests", + EncodeCrossCrate::No, "the `#[rustc_test_marker]` attribute is used internally to track tests", ), rustc_attr!( rustc_unsafe_specialization_marker, Normal, template!(Word), - WarnFollowing, @only_local: true, + WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations" ), rustc_attr!( rustc_specialization_trait, Normal, template!(Word), - WarnFollowing, @only_local: true, + WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_specialization_trait]` attribute is used to check specializations" ), rustc_attr!( - rustc_main, Normal, template!(Word), WarnFollowing, @only_local: true, + rustc_main, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_main]` attribute is used internally to specify test entry point function", ), rustc_attr!( rustc_skip_array_during_method_dispatch, Normal, template!(Word), - WarnFollowing, @only_local: true, + WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \ from method dispatch when the receiver is an array, for compatibility in editions < 2021." ), rustc_attr!( rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), - ErrorFollowing, @only_local: true, + ErrorFollowing, EncodeCrossCrate::No, "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \ definition of a trait, it's currently in experimental form and should be changed before \ being exposed outside of the std" ), rustc_attr!( rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, - r#"`rustc_doc_primitive` is a rustc internal attribute"#, + EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#, ), rustc_attr!( rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, - @only_local: true, + EncodeCrossCrate::No, "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" ), rustc_attr!( - rustc_intrinsic, Normal, template!(Word), ErrorFollowing, + rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", ), rustc_attr!( - rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, + rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" ), rustc_attr!( - rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, + rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", ), @@ -890,109 +930,135 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Testing: // ========================================================================== - rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), rustc_attr!( TEST, rustc_outlives, Normal, template!(Word), - WarnFollowing, @only_local: true + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_capture_analysis, Normal, template!(Word), - WarnFollowing, @only_local: true + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_insignificant_dtor, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes + ), + rustc_attr!( + TEST, rustc_strict_coherence, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes + ), + rustc_attr!( + TEST, rustc_variance, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), - rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), - rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing, @only_local: true), rustc_attr!( TEST, rustc_variance_of_opaques, Normal, template!(Word), - WarnFollowing, @only_local: true + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), - WarnFollowing, @only_local: true), - rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), + WarnFollowing, EncodeCrossCrate::Yes + ), rustc_attr!( TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), - WarnFollowing, @only_local: true + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_regions, Normal, template!(Word), - WarnFollowing, @only_local: true + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_error, Normal, - template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly + template!(Word, List: "delayed_bug_from_inside_query"), + WarnFollowingWordOnly, EncodeCrossCrate::Yes + ), + rustc_attr!( + TEST, rustc_dump_user_args, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::Yes ), - rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), rustc_attr!( - TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), - DuplicatesOk, @only_local: true + TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk, + EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), - DuplicatesOk, @only_local: true + TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk, + EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_clean, Normal, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - DuplicatesOk, @only_local: true + DuplicatesOk, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_partition_reused, Normal, - template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_partition_codegened, Normal, - template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true + template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_expected_cgu_reuse, Normal, template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk, - @only_local: true + EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_symbol_name, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_polymorphize_error, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes ), - rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing), rustc_attr!( - TEST, rustc_def_path, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_def_path, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), + DuplicatesOk, EncodeCrossCrate::Yes ), - rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk), gated!( custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#), - ErrorFollowing, @only_local: true, + ErrorFollowing, EncodeCrossCrate::No, "the `#[custom_mir]` attribute is just used for the Rust test suite", ), rustc_attr!( - TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_dump_program_clauses, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_dump_env_program_clauses, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing, - @only_local: true + TEST, rustc_object_lifetime_default, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No ), - rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing), rustc_attr!( - TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk, - @only_local: true + TEST, rustc_dump_vtable, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes + ), + rustc_attr!( + TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), + DuplicatesOk, EncodeCrossCrate::No ), gated!( - omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing, - @only_local: true, + omit_gdb_pretty_printer_section, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No, "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", ), rustc_attr!( TEST, pattern_complexity, CrateLevel, template!(NameValueStr: "N"), - ErrorFollowing, @only_local: true, + ErrorFollowing, EncodeCrossCrate::No, ), ]; @@ -1004,10 +1070,14 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } -/// Whether this builtin attribute is only used in the local crate. -/// If so, it is not encoded in the crate metadata. -pub fn is_builtin_only_local(name: Symbol) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.only_local) +/// Whether this builtin attribute is encoded cross crate. +/// This means it can be used cross crate. +pub fn encode_cross_crate(name: Symbol) -> bool { + if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) { + if attr.encode_cross_crate == EncodeCrossCrate::Yes { true } else { false } + } else { + true + } } pub fn is_valid_for_get_attr(name: Symbol) -> bool { diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index cbc0ce8c974..cb28bb4e8e4 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -124,7 +124,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u pub use accepted::ACCEPTED_FEATURES; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ - deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, + deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 05bb7480732..eaaf7ca34e0 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -98,7 +98,7 @@ declare_features! ( (removed, external_doc, "1.54.0", Some(44732), Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), /// Allows using `#[ffi_returns_twice]` on foreign functions. - (removed, ffi_returns_twice, "CURRENT_RUSTC_VERSION", Some(58314), + (removed, ffi_returns_twice, "1.78.0", Some(58314), Some("being investigated by the ffi-unwind project group")), /// Allows generators to be cloned. (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c3f216936df..a3b13c4d907 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -214,7 +214,7 @@ declare_features! ( /// Allows using `#[omit_gdb_pretty_printer_section]`. (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Set the maximum pattern complexity allowed (not limited by default). - (internal, pattern_complexity, "CURRENT_RUSTC_VERSION", None), + (internal, pattern_complexity, "1.78.0", None), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -301,11 +301,11 @@ declare_features! ( (unstable, csky_target_feature, "1.73.0", Some(44839)), (unstable, ermsb_target_feature, "1.49.0", Some(44839)), (unstable, hexagon_target_feature, "1.27.0", Some(44839)), - (unstable, lahfsahf_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (unstable, lahfsahf_target_feature, "1.78.0", Some(44839)), (unstable, loongarch_target_feature, "1.73.0", Some(44839)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), - (unstable, prfchw_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), (unstable, rtm_target_feature, "1.35.0", Some(44839)), (unstable, sse4a_target_feature, "1.27.0", Some(44839)), @@ -346,13 +346,11 @@ declare_features! ( /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Allows using `label` operands in inline assembly. - (unstable, asm_goto, "CURRENT_RUSTC_VERSION", Some(119364)), + (unstable, asm_goto, "1.78.0", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`. (unstable, associated_const_equality, "1.58.0", Some(92827)), - /// Allows the user of associated type bounds. - (unstable, associated_type_bounds, "1.34.0", Some(52662)), /// Allows associated type defaults. (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows `async || body` closures. @@ -412,7 +410,7 @@ declare_features! ( /// Allows references to types with interior mutability within constants (unstable, const_refs_to_cell, "1.51.0", Some(80384)), /// Allows creating pointers and references to `static` items in constants. - (unstable, const_refs_to_static, "CURRENT_RUSTC_VERSION", Some(119618)), + (unstable, const_refs_to_static, "1.78.0", Some(119618)), /// Allows `impl const Trait for T` syntax. (unstable, const_trait_impl, "1.42.0", Some(67792)), /// Allows the `?` operator in const contexts. @@ -464,9 +462,9 @@ declare_features! ( /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), /// Allow using 128-bit (quad precision) floating point numbers. - (unstable, f128, "CURRENT_RUSTC_VERSION", Some(116909)), + (unstable, f128, "1.78.0", Some(116909)), /// Allow using 16-bit (half precision) floating point numbers. - (unstable, f16, "CURRENT_RUSTC_VERSION", Some(116909)), + (unstable, f16, "1.78.0", Some(116909)), /// Allows the use of `#[ffi_const]` on foreign functions. (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. @@ -476,7 +474,7 @@ declare_features! ( /// Support delegating implementation of functions to other already implemented functions. (incomplete, fn_delegation, "1.76.0", Some(118212)), /// Allows impls for the Freeze trait. - (internal, freeze_impls, "CURRENT_RUSTC_VERSION", Some(121675)), + (internal, freeze_impls, "1.78.0", Some(121675)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. @@ -495,8 +493,6 @@ declare_features! ( (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)), - /// Allows using imported `main` function - (unstable, imported_main, "1.53.0", Some(28937)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allow anonymous constants from an inline `const` block diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 1810193c16b..e8cecb1930f 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -810,6 +810,8 @@ pub enum LifetimeRes { param: NodeId, /// Id of the introducing place. See `Param`. binder: NodeId, + /// Kind of elided lifetime + kind: hir::MissingLifetimeKind, }, /// This variant is used for anonymous lifetimes that we did not resolve during /// late resolution. Those lifetimes will be inferred by typechecking. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 186b8716d9a..141b8a41801 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -456,6 +456,18 @@ impl GenericBound<'_> { pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>]; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic, Debug)] +pub enum MissingLifetimeKind { + /// An explicit `'_`. + Underscore, + /// An elided lifetime `&' ty`. + Ampersand, + /// An elided lifetime in brackets with written brackets. + Comma, + /// An elided lifetime with elided brackets. + Brackets, +} + #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum LifetimeParamKind { // Indicates that the lifetime definition was explicitly declared (e.g., in @@ -464,7 +476,7 @@ pub enum LifetimeParamKind { // Indication that the lifetime was elided (e.g., in both cases in // `fn foo(x: &u8) -> &'_ u8 { x }`). - Elided, + Elided(MissingLifetimeKind), // Indication that the lifetime name was somehow in error. Error, @@ -512,7 +524,7 @@ impl<'hir> GenericParam<'hir> { /// /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information. pub fn is_elided_lifetime(&self) -> bool { - matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided }) + matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) }) } } @@ -1259,7 +1271,7 @@ pub struct Arm<'hir> { /// In an `if let`, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of /// the desugaring to if-let. Only let-else supports the type annotation at present. #[derive(Debug, Clone, Copy, HashStable_Generic)] -pub struct Let<'hir> { +pub struct LetExpr<'hir> { pub span: Span, pub pat: &'hir Pat<'hir>, pub ty: Option<&'hir Ty<'hir>>, @@ -1852,7 +1864,7 @@ pub enum ExprKind<'hir> { /// /// These are not `Local` and only occur as expressions. /// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`. - Let(&'hir Let<'hir>), + Let(&'hir LetExpr<'hir>), /// An `if` block, with an optional else block. /// /// I.e., `if <expr> { <expr> } else { <expr> }`. @@ -2552,11 +2564,6 @@ pub struct OpaqueTy<'hir> { pub in_trait: bool, } -#[derive(Copy, Clone, Debug, HashStable_Generic)] -pub struct AssocOpaqueTy { - // Add some data if necessary -} - /// From whence the opaque type came. #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] pub enum OpaqueTyOrigin { @@ -3367,7 +3374,7 @@ pub enum OwnerNode<'hir> { TraitItem(&'hir TraitItem<'hir>), ImplItem(&'hir ImplItem<'hir>), Crate(&'hir Mod<'hir>), - AssocOpaqueTy(&'hir AssocOpaqueTy), + Synthetic, } impl<'hir> OwnerNode<'hir> { @@ -3377,7 +3384,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ForeignItem(ForeignItem { ident, .. }) | OwnerNode::ImplItem(ImplItem { ident, .. }) | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident), - OwnerNode::Crate(..) | OwnerNode::AssocOpaqueTy(..) => None, + OwnerNode::Crate(..) | OwnerNode::Synthetic => None, } } @@ -3390,7 +3397,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { span, .. }) | OwnerNode::TraitItem(TraitItem { span, .. }) => span, OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => inner_span, - OwnerNode::AssocOpaqueTy(..) => unreachable!(), + OwnerNode::Synthetic => unreachable!(), } } @@ -3449,7 +3456,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { owner_id, .. }) | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id, OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner, - OwnerNode::AssocOpaqueTy(..) => unreachable!(), + OwnerNode::Synthetic => unreachable!(), } } @@ -3493,7 +3500,7 @@ impl<'hir> Into<Node<'hir>> for OwnerNode<'hir> { OwnerNode::ImplItem(n) => Node::ImplItem(n), OwnerNode::TraitItem(n) => Node::TraitItem(n), OwnerNode::Crate(n) => Node::Crate(n), - OwnerNode::AssocOpaqueTy(n) => Node::AssocOpaqueTy(n), + OwnerNode::Synthetic => Node::Synthetic, } } } @@ -3531,7 +3538,8 @@ pub enum Node<'hir> { WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>), // FIXME: Merge into `Node::Infer`. ArrayLenInfer(&'hir InferArg), - AssocOpaqueTy(&'hir AssocOpaqueTy), + // Created by query feeding + Synthetic, // Span by reference to minimize `Node`'s size #[allow(rustc::pass_by_value)] Err(&'hir Span), @@ -3582,7 +3590,7 @@ impl<'hir> Node<'hir> { | Node::Infer(..) | Node::WhereBoundPredicate(..) | Node::ArrayLenInfer(..) - | Node::AssocOpaqueTy(..) + | Node::Synthetic | Node::Err(..) => None, } } @@ -3640,35 +3648,42 @@ impl<'hir> Node<'hir> { } } - pub fn body_id(&self) -> Option<BodyId> { + #[inline] + pub fn associated_body(&self) -> Option<(LocalDefId, BodyId)> { match self { Node::Item(Item { + owner_id, kind: - ItemKind::Static(_, _, body) - | ItemKind::Const(_, _, body) - | ItemKind::Fn(_, _, body), + ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), .. }) | Node::TraitItem(TraitItem { + owner_id, kind: - TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { - kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), - .. - }) - | Node::Expr(Expr { - kind: - ExprKind::ConstBlock(ConstBlock { body, .. }) - | ExprKind::Closure(Closure { body, .. }) - | ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })), + owner_id, + kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), .. - }) => Some(*body), + }) => Some((owner_id.def_id, *body)), + + Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { + Some((*def_id, *body)) + } + + Node::AnonConst(constant) => Some((constant.def_id, constant.body)), + Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), + _ => None, } } + pub fn body_id(&self) -> Option<BodyId> { + Some(self.associated_body()?.1) + } + pub fn generics(self) -> Option<&'hir Generics<'hir>> { match self { Node::ForeignItem(ForeignItem { @@ -3688,7 +3703,7 @@ impl<'hir> Node<'hir> { Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)), Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)), Node::Crate(i) => Some(OwnerNode::Crate(i)), - Node::AssocOpaqueTy(i) => Some(OwnerNode::AssocOpaqueTy(i)), + Node::Synthetic => Some(OwnerNode::Synthetic), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 186bb234a45..3cf1093eeec 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -753,7 +753,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::DropTemps(ref subexpression) => { try_visit!(visitor.visit_expr(subexpression)); } - ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => { + ExprKind::Let(LetExpr { span: _, pat, ty, init, is_recovered: _ }) => { // match the visit order in walk_local try_visit!(visitor.visit_expr(init)); try_visit!(visitor.visit_pat(pat)); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 9921686ce28..c5c4075c6ba 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -5,7 +5,6 @@ #![feature(associated_type_defaults)] #![feature(closure_track_caller)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 1c68de51ba6..9bf4d63267a 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -118,6 +118,11 @@ hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed .label = overflowed on value after {$discr} .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome +hir_analysis_escaping_bound_var_in_ty_of_assoc_const_binding = + the type of the associated constant `{$assoc_const}` cannot capture late-bound generic parameters + .label = its type cannot capture the late-bound {$var_def_kind} `{$var_name}` + .var_defined_here_label = the late-bound {$var_def_kind} `{$var_name}` is defined here + hir_analysis_field_already_declared = field `{$field_name}` is already declared .label = field already declared @@ -316,6 +321,22 @@ hir_analysis_opaque_captures_higher_ranked_lifetime = `impl Trait` cannot captur .label = `impl Trait` implicitly captures all lifetimes in scope .note = lifetime declared here +hir_analysis_param_in_ty_of_assoc_const_binding = + the type of the associated constant `{$assoc_const}` must not depend on {$param_category -> + [self] `Self` + [synthetic] `impl Trait` + *[normal] generic parameters + } + .label = its type must not depend on {$param_category -> + [self] `Self` + [synthetic] `impl Trait` + *[normal] the {$param_def_kind} `{$param_name}` + } + .param_defined_here_label = {$param_category -> + [synthetic] the `impl Trait` is specified here + *[normal] the {$param_def_kind} `{$param_name}` is defined here + } + hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it @@ -432,6 +453,8 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de .label = needs at most one field with non-trivial size or alignment, but has {$field_count} .labels = this field has non-zero size or requires alignment +hir_analysis_ty_of_assoc_const_binding_note = `{$assoc_const}` has type `{$ty}` + hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) .label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index c6942b0f456..3067e2d0b71 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,12 +1,15 @@ -use rustc_data_structures::fx::FxIndexMap; +use std::ops::ControlFlow; + +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::{self as ty, Ty}; +use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_trait_selection::traits; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter}; @@ -433,14 +436,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { binding.kind { let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args)); - // Since the arguments passed to the alias type above may contain early-bound - // generic parameters, the instantiated type may contain some as well. - // Therefore wrap it in `EarlyBinder`. - // FIXME(fmease): Reject escaping late-bound vars. - tcx.feed_anon_const_type( - anon_const.def_id, - ty::EarlyBinder::bind(ty.skip_binder()), - ); + let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, binding.hir_id); + tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); } alias_ty @@ -530,3 +527,167 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { Ok(()) } } + +/// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings. +/// +/// FIXME(const_generics): This is a temporary and semi-artifical restriction until the +/// arrival of *generic const generics*[^1]. +/// +/// It might actually be possible that we can already support early-bound generic params +/// in such types if we just lifted some more checks in other places, too, for example +/// inside [`ty::Const::from_anon_const`]. However, even if that were the case, we should +/// probably gate this behind another feature flag. +/// +/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>. +fn check_assoc_const_binding_type<'tcx>( + tcx: TyCtxt<'tcx>, + assoc_const: Ident, + ty: ty::Binder<'tcx, Ty<'tcx>>, + hir_id: hir::HirId, +) -> Ty<'tcx> { + // We can't perform the checks for early-bound params during name resolution unlike E0770 + // because this information depends on *type* resolution. + // We can't perform these checks in `resolve_bound_vars` either for the same reason. + // Consider the trait ref `for<'a> Trait<'a, C = { &0 }>`. We need to know the fully + // resolved type of `Trait::C` in order to know if it references `'a` or not. + + let ty = ty.skip_binder(); + if !ty.has_param() && !ty.has_escaping_bound_vars() { + return ty; + } + + let mut collector = GenericParamAndBoundVarCollector { + tcx, + params: Default::default(), + vars: Default::default(), + depth: ty::INNERMOST, + }; + let mut guar = ty.visit_with(&mut collector).break_value(); + + let ty_note = ty + .make_suggestable(tcx, false) + .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); + + let enclosing_item_owner_id = tcx + .hir() + .parent_owner_iter(hir_id) + .find_map(|(owner_id, parent)| parent.generics().map(|_| owner_id)) + .unwrap(); + let generics = tcx.generics_of(enclosing_item_owner_id); + for index in collector.params { + let param = generics.param_at(index as _, tcx); + let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; + guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { + span: assoc_const.span, + assoc_const, + param_name: param.name, + param_def_kind: tcx.def_descr(param.def_id), + param_category: if is_self_param { + "self" + } else if param.kind.is_synthetic() { + "synthetic" + } else { + "normal" + }, + param_defined_here_label: + (!is_self_param).then(|| tcx.def_ident_span(param.def_id).unwrap()), + ty_note, + })); + } + for (var_def_id, var_name) in collector.vars { + guar.get_or_insert(tcx.dcx().emit_err( + crate::errors::EscapingBoundVarInTyOfAssocConstBinding { + span: assoc_const.span, + assoc_const, + var_name, + var_def_kind: tcx.def_descr(var_def_id), + var_defined_here_label: tcx.def_ident_span(var_def_id).unwrap(), + ty_note, + }, + )); + } + + let guar = guar.unwrap_or_else(|| bug!("failed to find gen params or bound vars in ty")); + Ty::new_error(tcx, guar) +} + +struct GenericParamAndBoundVarCollector<'tcx> { + tcx: TyCtxt<'tcx>, + params: FxIndexSet<u32>, + vars: FxIndexSet<(DefId, Symbol)>, + depth: ty::DebruijnIndex, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> { + type Result = ControlFlow<ErrorGuaranteed>; + + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( + &mut self, + binder: &ty::Binder<'tcx, T>, + ) -> Self::Result { + self.depth.shift_in(1); + let result = binder.super_visit_with(self); + self.depth.shift_out(1); + result + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match ty.kind() { + ty::Param(param) => { + self.params.insert(param.index); + } + ty::Bound(db, bt) if *db >= self.depth => { + self.vars.insert(match bt.kind { + ty::BoundTyKind::Param(def_id, name) => (def_id, name), + ty::BoundTyKind::Anon => { + let reported = self + .tcx + .dcx() + .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var)); + return ControlFlow::Break(reported); + } + }); + } + _ if ty.has_param() || ty.has_bound_vars() => return ty.super_visit_with(self), + _ => {} + } + ControlFlow::Continue(()) + } + + fn visit_region(&mut self, re: ty::Region<'tcx>) -> Self::Result { + match re.kind() { + ty::ReEarlyParam(param) => { + self.params.insert(param.index); + } + ty::ReBound(db, br) if db >= self.depth => { + self.vars.insert(match br.kind { + ty::BrNamed(def_id, name) => (def_id, name), + ty::BrAnon | ty::BrEnv => { + let guar = self + .tcx + .dcx() + .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind)); + return ControlFlow::Break(guar); + } + }); + } + _ => {} + } + ControlFlow::Continue(()) + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { + match ct.kind() { + ty::ConstKind::Param(param) => { + self.params.insert(param.index); + } + ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { + let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var"); + return ControlFlow::Break(guar); + } + _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self), + _ => {} + } + ControlFlow::Continue(()) + } +} diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 428eea2f686..42e303c10ea 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use smallvec::SmallVec; /// Report an error that a generic argument did not match the generic parameter that was @@ -41,9 +41,11 @@ fn generic_arg_mismatch_err( if let GenericParamDefKind::Const { .. } = param.kind { if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) { err.help("const arguments cannot yet be inferred with `_`"); - if sess.is_nightly_build() { - err.help("add `#![feature(generic_arg_infer)]` to the crate attributes to enable"); - } + tcx.disabled_nightly_features( + &mut err, + param.def_id.as_local().map(|local| tcx.local_def_id_to_hir_id(local)), + [(String::new(), sym::generic_arg_infer)], + ); } } 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 ec9e928ce59..d2fdff6177e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1305,7 +1305,7 @@ fn compare_number_of_generics<'tcx>( .iter() .filter(|p| match p.kind { hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Elided, + kind: hir::LifetimeParamKind::Elided(_), } => { // A fn can have an arbitrary number of extra elided lifetimes for the // same signature. diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 35755a46df3..07054c184f4 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -441,7 +441,7 @@ pub fn check_intrinsic_type( sym::ptr_guaranteed_cmp => ( 1, - 0, + 1, vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], tcx.types.u8, ), @@ -579,7 +579,7 @@ pub fn check_intrinsic_type( sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool), - sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), + sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 22afddad633..8760901b71b 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -291,12 +291,16 @@ fn default_body_is_unstable( reason: reason_str, }); + let inject_span = item_did + .as_local() + .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id))); rustc_session::parse::add_feature_diagnostics_for_issue( &mut err, &tcx.sess, feature, rustc_feature::GateIssue::Library(issue), false, + inject_span, ); err.emit(); @@ -427,7 +431,7 @@ fn fn_sig_suggestion<'tcx>( let asyncness = if tcx.asyncness(assoc.def_id).is_async() { output = if let ty::Alias(_, alias_ty) = *output.kind() { - tcx.explicit_item_bounds(alias_ty.def_id) + tcx.explicit_item_super_predicates(alias_ty.def_id) .iter_instantiated_copied(tcx, alias_ty.args) .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) .unwrap_or_else(|| { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f5250045344..b5377e40bfd 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -196,7 +196,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(), + hir::OwnerNode::Synthetic => unreachable!(), }; if let Some(generics) = node.generics() { @@ -999,9 +999,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), // Implments `ConstParamTy`, suggest adding the feature to enable. Ok(..) => true, }; - if may_suggest_feature && tcx.sess.is_nightly_build() { - diag.help( - "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types", + if may_suggest_feature { + tcx.disabled_nightly_features( + &mut diag, + Some(param.hir_id), + [( + " more complex and user defined types".to_string(), + sym::adt_const_params, + )], ); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5cd6862786b..bd56275b159 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -61,6 +61,9 @@ pub fn provide(providers: &mut Providers) { type_alias_is_lazy: type_of::type_alias_is_lazy, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, + item_super_predicates: item_bounds::item_super_predicates, + explicit_item_super_predicates: item_bounds::explicit_item_super_predicates, + item_non_self_assumptions: item_bounds::item_non_self_assumptions, generics_of: generics_of::generics_of, predicates_of: predicates_of::predicates_of, predicates_defined_on, @@ -633,7 +636,9 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(def_id); tcx.ensure().predicates_of(def_id); tcx.ensure().explicit_item_bounds(def_id); + tcx.ensure().explicit_item_super_predicates(def_id); tcx.ensure().item_bounds(def_id); + tcx.ensure().item_super_predicates(def_id); } hir::ItemKind::TyAlias(..) => { @@ -689,6 +694,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { hir::TraitItemKind::Type(_, Some(_)) => { tcx.ensure().item_bounds(def_id); + tcx.ensure().item_super_predicates(def_id); tcx.ensure().type_of(def_id); // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); @@ -698,6 +704,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { hir::TraitItemKind::Type(_, None) => { tcx.ensure().item_bounds(def_id); + tcx.ensure().item_super_predicates(def_id); // #74612: Visit and try to find bad placeholders // even if there is no concrete type. let mut visitor = HirPlaceholderCollector::default(); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index c86788db988..bc6abc53cad 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -508,29 +508,9 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S visitor.has_late_bound_regions } - match node { - Node::TraitItem(item) => match &item.kind { - hir::TraitItemKind::Fn(sig, _) => has_late_bound_regions(tcx, item.generics, sig.decl), - _ => None, - }, - Node::ImplItem(item) => match &item.kind { - hir::ImplItemKind::Fn(sig, _) => has_late_bound_regions(tcx, item.generics, sig.decl), - _ => None, - }, - Node::ForeignItem(item) => match item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, generics) => { - has_late_bound_regions(tcx, generics, fn_decl) - } - _ => None, - }, - Node::Item(item) => match &item.kind { - hir::ItemKind::Fn(sig, .., generics, _) => { - has_late_bound_regions(tcx, generics, sig.decl) - } - _ => None, - }, - _ => None, - } + let decl = node.fn_decl()?; + let generics = node.generics()?; + has_late_bound_regions(tcx, generics, decl) } struct AnonConstInParamTyDetector { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 78c390d0924..f914f1f9b17 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,5 +1,6 @@ use super::ItemCtxt; use crate::astconv::{AstConv, PredicateFilter}; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::GenericArgs; @@ -19,6 +20,7 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, + filter: PredicateFilter, ) -> &'tcx [(ty::Clause<'tcx>, Span)] { let item_ty = Ty::new_projection( tcx, @@ -27,7 +29,7 @@ fn associated_type_bounds<'tcx>( ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, filter); // Associated types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); @@ -63,10 +65,11 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, + filter: PredicateFilter, ) -> &'tcx [(ty::Clause<'tcx>, Span)] { ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); - let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); + let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, filter); // Opaque types are implicitly sized unless a `?Sized` bound is found icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); @@ -79,6 +82,21 @@ pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, ) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { + explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All) +} + +pub(super) fn explicit_item_super_predicates( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { + explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly) +} + +pub(super) fn explicit_item_bounds_with_filter( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + filter: PredicateFilter, +) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. @@ -95,6 +113,7 @@ pub(super) fn explicit_item_bounds( ty::GenericArgs::identity_for_item(tcx, def_id), ), item.span, + filter, )); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( @@ -109,7 +128,7 @@ pub(super) fn explicit_item_bounds( kind: hir::TraitItemKind::Type(bounds, _), span, .. - }) => associated_type_bounds(tcx, def_id, bounds, *span), + }) => associated_type_bounds(tcx, def_id, bounds, *span, filter), hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }), span, @@ -117,7 +136,7 @@ pub(super) fn explicit_item_bounds( }) => { let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) + opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) } // Since RPITITs are astconv'd as projections in `ast_ty_to_ty`, when we're asking // for the item bounds of the *opaques* in a trait's default method signature, we @@ -135,7 +154,7 @@ pub(super) fn explicit_item_bounds( let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); tcx.arena.alloc_slice( - &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) + &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) .to_vec() .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }), ) @@ -155,6 +174,31 @@ pub(super) fn item_bounds( }) } +pub(super) fn item_super_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { + tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| { + tcx.mk_clauses_from_iter( + util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(), + ) + }) +} + +pub(super) fn item_non_self_assumptions( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { + let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect(); + let own_bounds: FxIndexSet<_> = + tcx.item_super_predicates(def_id).skip_binder().iter().collect(); + if all_bounds.len() == own_bounds.len() { + ty::EarlyBinder::bind(ty::List::empty()) + } else { + ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied())) + } +} + struct AssocTyToOpaque<'tcx> { tcx: TyCtxt<'tcx>, fn_def_id: DefId, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6aae4aa21b8..66c9fb93500 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -123,43 +123,22 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // 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 ast_generics = match node { - Node::TraitItem(item) => item.generics, - - Node::ImplItem(item) => item.generics, - - Node::Item(item) => match item.kind { + let ast_generics = node.generics().unwrap_or(NO_GENERICS); + if let Node::Item(item) = node { + match item.kind { ItemKind::Impl(impl_) => { if impl_.defaultness.is_default() { is_default_impl_trait = tcx .impl_trait_ref(def_id) .map(|t| ty::Binder::dummy(t.instantiate_identity())); } - impl_.generics } - ItemKind::Fn(.., generics, _) - | ItemKind::TyAlias(_, generics) - | ItemKind::Const(_, generics, _) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) => generics, - - ItemKind::Trait(_, _, generics, self_bounds, ..) - | ItemKind::TraitAlias(generics, self_bounds) => { + + ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); - generics } - ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics, - _ => NO_GENERICS, - }, - - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Static(..) => NO_GENERICS, - ForeignItemKind::Fn(_, _, generics) => generics, - ForeignItemKind::Type => NO_GENERICS, - }, - - _ => NO_GENERICS, + _ => {} + } }; let generics = tcx.generics_of(def_id); @@ -703,45 +682,17 @@ pub(super) fn type_param_predicates( let mut extend = None; let item_hir_id = tcx.local_def_id_to_hir_id(item_def_id); - let ast_generics = match tcx.hir_node(item_hir_id) { - Node::TraitItem(item) => item.generics, - - Node::ImplItem(item) => item.generics, - - Node::Item(item) => { - match item.kind { - ItemKind::Fn(.., generics, _) - | ItemKind::Impl(&hir::Impl { generics, .. }) - | ItemKind::TyAlias(_, generics) - | ItemKind::Const(_, generics, _) - | ItemKind::OpaqueTy(&OpaqueTy { - generics, - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) => generics, - ItemKind::Trait(_, _, generics, ..) => { - // Implied `Self: Trait` and supertrait bounds. - if param_id == item_hir_id { - let identity_trait_ref = - ty::TraitRef::identity(tcx, item_def_id.to_def_id()); - extend = Some((identity_trait_ref.to_predicate(tcx), item.span)); - } - generics - } - _ => return result, - } - } - - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(_, _, generics) => generics, - _ => return result, - }, - _ => return result, - }; + let hir_node = tcx.hir_node(item_hir_id); + let Some(ast_generics) = hir_node.generics() else { return result }; + if let Node::Item(item) = hir_node + && let ItemKind::Trait(..) = item.kind + // Implied `Self: Trait` and supertrait bounds. + && param_id == item_hir_id + { + let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id.to_def_id()); + extend = Some((identity_trait_ref.to_predicate(tcx), item.span)); + } let icx = ItemCtxt::new(tcx, item_def_id); let extra_predicates = extend.into_iter().chain( 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 d1da2fa0fdc..86b075a84a7 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -262,7 +262,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou visitor.visit_impl_item(item) } hir::OwnerNode::Crate(_) => {} - hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(), + hir::OwnerNode::Synthetic => unreachable!(), } let mut rl = ResolveBoundVars::default(); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7bf87f444db..fb919714afd 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -295,6 +295,44 @@ pub struct AssocTypeBindingNotAllowed { pub fn_trait_expansion: Option<ParenthesizedFnTraitExpansion>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_param_in_ty_of_assoc_const_binding)] +pub(crate) struct ParamInTyOfAssocConstBinding<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub assoc_const: Ident, + pub param_name: Symbol, + pub param_def_kind: &'static str, + pub param_category: &'static str, + #[label(hir_analysis_param_defined_here_label)] + pub param_defined_here_label: Option<Span>, + #[subdiagnostic] + pub ty_note: Option<TyOfAssocConstBindingNote<'tcx>>, +} + +#[derive(Subdiagnostic, Clone, Copy)] +#[note(hir_analysis_ty_of_assoc_const_binding_note)] +pub(crate) struct TyOfAssocConstBindingNote<'tcx> { + pub assoc_const: Ident, + pub ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_escaping_bound_var_in_ty_of_assoc_const_binding)] +pub(crate) struct EscapingBoundVarInTyOfAssocConstBinding<'tcx> { + #[primary_span] + #[label] + pub span: Span, + pub assoc_const: Ident, + pub var_name: Symbol, + pub var_def_kind: &'static str, + #[label(hir_analysis_var_defined_here_label)] + pub var_defined_here_label: Span, + #[subdiagnostic] + pub ty_note: Option<TyOfAssocConstBindingNote<'tcx>>, +} + #[derive(Subdiagnostic)] #[help(hir_analysis_parenthesized_fn_trait_expansion)] pub struct ParenthesizedFnTraitExpansion { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 19ab2045cc5..5fe8d1fe586 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -68,7 +68,6 @@ This API is completely unstable and subject to change. #![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(never_type)] #![feature(lazy_cell)] #![feature(slice_partition_dedup)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e070db9423d..c7651cf3264 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -121,7 +121,7 @@ impl<'a> State<'a> { self.print_bounds(":", pred.bounds); } Node::ArrayLenInfer(_) => self.word("_"), - Node::AssocOpaqueTy(..) => unreachable!(), + Node::Synthetic => unreachable!(), Node::Err(_) => self.word("/*ERROR*/"), } } @@ -1387,7 +1387,7 @@ impl<'a> State<'a> { // Print `}`: self.bclose_maybe_open(expr.span, true); } - hir::ExprKind::Let(&hir::Let { pat, ty, init, .. }) => { + hir::ExprKind::Let(&hir::LetExpr { pat, ty, init, .. }) => { self.print_let(pat, ty, init); } hir::ExprKind::If(test, blk, elseopt) => { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 4b3359858f1..1805e9fbb98 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note("`if` expressions without `else` evaluate to `()`"); err.help("consider adding an `else` block that evaluates to the expected type"); *error = true; - if let ExprKind::Let(hir::Let { span, pat, init, .. }) = cond_expr.kind + if let ExprKind::Let(hir::LetExpr { span, pat, init, .. }) = cond_expr.kind && let ExprKind::Block(block, _) = then_expr.kind // Refutability checks occur on the MIR, so we approximate it here by checking // if we have an enum with a single variant or a struct in the pattern. @@ -645,7 +645,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in [first_ty, second_ty] { for (clause, _) in self .tcx - .explicit_item_bounds(rpit_def_id) + .explicit_item_super_predicates(rpit_def_id) .iter_instantiated_copied(self.tcx, args) { let pred = clause.kind().rebind(match clause.kind().skip_binder() { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9a500fa712b..0e75a47683d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -184,16 +184,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::TypeInference, span: callee_expr.span, }); + // We may actually receive a coroutine back whose kind is different + // from the closure that this dispatched from. This is because when + // we have no captures, we automatically implement `FnOnce`. This + // impl forces the closure kind to `FnOnce` i.e. `u8`. + let kind_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: callee_expr.span, + }); let call_sig = self.tcx.mk_fn_sig( [coroutine_closure_sig.tupled_inputs_ty], coroutine_closure_sig.to_coroutine( self.tcx, closure_args.parent_args(), - // Inherit the kind ty of the closure, since we're calling this - // coroutine with the most relaxed `AsyncFn*` trait that we can. - // We don't necessarily need to do this here, but it saves us - // computing one more infer var that will get constrained later. - closure_args.kind_ty(), + kind_ty, self.tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ), diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 4bea4bb3e82..b32c5e2c357 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -262,6 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); + let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, @@ -279,7 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sig.to_coroutine( tcx, parent_args, - closure_kind_ty, + coroutine_kind_ty, tcx.coroutine_for_closure(expr_def_id), coroutine_upvars_ty, ) @@ -325,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty, closure_kind, self.tcx - .explicit_item_bounds(def_id) + .explicit_item_super_predicates(def_id) .iter_instantiated_copied(self.tcx, args) .map(|(c, s)| (c.as_predicate(), s)), ), @@ -902,7 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self .tcx - .explicit_item_bounds(def_id) + .explicit_item_super_predicates(def_id) .iter_instantiated_copied(self.tcx, args) .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return Some(ret_ty), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1a142f27809..4c01c201ad2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1261,7 +1261,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> { + pub(super) fn check_expr_let( + &self, + let_expr: &'tcx hir::LetExpr<'tcx>, + hir_id: HirId, + ) -> Ty<'tcx> { // for let statements, this is done in check_stmt let init = let_expr.init; self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 43e95544594..2dc355b72f6 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - hir::ExprKind::Let(hir::Let { pat, init, .. }) => { + hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => { self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow)) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index dd44fdd8893..1d885b801d9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -138,7 +138,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[inline] pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); - self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); + let mut typeck = self.typeck_results.borrow_mut(); + let mut node_ty = typeck.node_types_mut(); + if let Some(ty) = node_ty.get(id) + && let Err(e) = ty.error_reported() + { + // Do not overwrite nodes that were already marked as `{type error}`. This allows us to + // silence unnecessary errors from obligations that were set earlier than a type error + // was produced, but that is overwritten by later analysis. This happens in particular + // for `Sized` obligations introduced in gather_locals. (#117846) + self.set_tainted_by_errors(e); + return; + } + + node_ty.insert(id, ty); if let Err(e) = ty.error_reported() { self.set_tainted_by_errors(e); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 536d44a0ccb..5c56c6acd27 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1892,11 +1892,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx hir::Pat<'tcx>, ty: Ty<'tcx>, ) { + struct V<'tcx> { + tcx: TyCtxt<'tcx>, + pat_hir_ids: Vec<hir::HirId>, + } + + impl<'tcx> Visitor<'tcx> for V<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + self.pat_hir_ids.push(p.hir_id); + hir::intravisit::walk_pat(self, p); + } + } if let Err(guar) = ty.error_reported() { // Override the types everywhere with `err()` to avoid knock on errors. let err = Ty::new_error(self.tcx, guar); self.write_ty(hir_id, err); self.write_ty(pat.hir_id, err); + let mut visitor = V { tcx: self.tcx, pat_hir_ids: vec![] }; + hir::intravisit::walk_pat(&mut visitor, pat); + // Mark all the subpatterns as `{type error}` as well. This allows errors for specific + // subpatterns to be silenced. + for hir_id in visitor.pat_hir_ids { + self.write_ty(hir_id, err); + } self.locals.borrow_mut().insert(hir_id, err); self.locals.borrow_mut().insert(pat.hir_id, err); } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 4d37f725c94..6dae1fab6dc 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -29,7 +29,7 @@ impl<'a> DeclOrigin<'a> { } } -/// A declaration is an abstraction of [hir::Local] and [hir::Let]. +/// A declaration is an abstraction of [hir::Local] and [hir::LetExpr]. /// /// It must have a hir_id, as this is how we connect gather_locals to the check functions. pub(super) struct Declaration<'a> { @@ -48,9 +48,9 @@ impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { } } -impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> { - fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self { - let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr; +impl<'a> From<(&'a hir::LetExpr<'a>, hir::HirId)> for Declaration<'a> { + fn from((let_expr, hir_id): (&'a hir::LetExpr<'a>, hir::HirId)) -> Self { + let hir::LetExpr { pat, ty, span, init, is_recovered: _ } = *let_expr; Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d86b4912c89..d259e71f957 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,7 +5,6 @@ #![feature(try_blocks)] #![feature(never_type)] #![feature(box_patterns)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(control_flow_enum)] #[macro_use] @@ -95,29 +94,7 @@ macro_rules! type_error_struct { fn primary_body_of( node: Node<'_>, ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { - match node { - Node::Item(item) => match item.kind { - hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => { - Some((body, Some(ty), None)) - } - hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), - _ => None, - }, - Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(sig))) - } - _ => None, - }, - Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), - hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), - _ => None, - }, - Node::AnonConst(constant) => Some((constant.body, None, None)), - _ => None, - } + Some((node.body_id()?, node.ty(), node.fn_sig())) } fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e4d5ebb82e8..eada5a0bc30 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -386,10 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let infcx = &self.infcx; let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) = - infcx.instantiate_canonical_with_fresh_inference_vars( - span, - ¶m_env_and_self_ty, - ); + infcx.instantiate_canonical(span, ¶m_env_and_self_ty); debug!( "probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty @@ -661,13 +658,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // of the iterations in the autoderef loop, so there is no problem with it // being discoverable in another one of these iterations. // - // Using `instantiate_canonical_with_fresh_inference_vars` on our + // Using `instantiate_canonical` on our // `Canonical<QueryResponse<Ty<'tcx>>>` and then *throwing away* the // `CanonicalVarValues` will exactly give us such a generalization - it // will still match the original object type, but it won't pollute our // type variables in any form, so just do that! let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = - self.fcx.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); + self.fcx.instantiate_canonical(self.span, self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); @@ -1420,15 +1417,13 @@ impl<'tcx> Pick<'tcx> { } _ => {} } - if tcx.sess.is_nightly_build() { - for (candidate, feature) in &self.unstable_candidates { - lint.help(format!( - "add `#![feature({})]` to the crate attributes to enable `{}`", - feature, - tcx.def_path_str(candidate.item.def_id), - )); - } - } + tcx.disabled_nightly_features( + lint, + Some(scope_expr_id), + self.unstable_candidates.iter().map(|(candidate, feature)| { + (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) + }), + ); }, ); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index be14f5bf0d8..b71e88a1579 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -410,7 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype( span, coroutine_args.as_coroutine().kind_ty(), - Ty::from_closure_kind(self.tcx, closure_kind), + Ty::from_coroutine_closure_kind(self.tcx, closure_kind), ); } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 1d203a29b14..bcc476393ea 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -38,8 +38,8 @@ mod instantiate; pub mod query_response; impl<'tcx> InferCtxt<'tcx> { - /// Creates an instantiation S for the canonical value with fresh - /// inference variables and applies it to the canonical value. + /// Creates an instantiation S for the canonical value with fresh inference + /// variables and placeholders then applies it to the canonical value. /// Returns both the instantiated result *and* the instantiation S. /// /// This can be invoked as part of constructing an @@ -50,7 +50,7 @@ impl<'tcx> InferCtxt<'tcx> { /// At the end of processing, the instantiation S (once /// canonicalized) then represents the values that you computed /// for each of the canonical inputs to your query. - pub fn instantiate_canonical_with_fresh_inference_vars<T>( + pub fn instantiate_canonical<T>( &self, span: Span, canonical: &Canonical<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d2a95593cd..7ce6c35f8c3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -403,8 +403,10 @@ impl<'tcx> InferCtxt<'tcx> { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - self.tcx.explicit_item_bounds(def_id).iter_instantiated_copied(self.tcx, args).find_map( - |(predicate, _)| { + self.tcx + .explicit_item_super_predicates(def_id) + .iter_instantiated_copied(self.tcx, args) + .find_map(|(predicate, _)| { predicate .kind() .map_bound(|kind| match kind { @@ -417,8 +419,7 @@ impl<'tcx> InferCtxt<'tcx> { }) .no_bound_vars() .flatten() - }, - ) + }) } } @@ -2553,7 +2554,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i), hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i), hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"), - hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(), + hir::OwnerNode::Synthetic => unreachable!(), } let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap(); 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 13e2152e45e..0686994b037 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 @@ -990,7 +990,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let generics_def_id = tcx.res_generics_def_id(path.res)?; let generics = tcx.generics_of(generics_def_id); if generics.has_impl_trait() { - None?; + do yeet (); } let insert_span = path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi()); @@ -1044,7 +1044,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let generics = tcx.generics_of(def_id); let segment: Option<_> = try { if !segment.infer_args || generics.has_impl_trait() { - None?; + do yeet (); } let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 503645191aa..fe70b631cdb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -13,8 +13,8 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnosti use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node, - TyKind, + self as hir, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, + LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; use rustc_middle::ty::{ self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, @@ -355,20 +355,8 @@ pub fn suggest_new_region_bound( // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any if let Some(id) = scope_def_id && let Some(generics) = tcx.hir().get_generics(id) - && let mut spans_suggs = generics - .params - .iter() - .filter(|p| p.is_elided_lifetime()) - .map(|p| { - if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { - // Ampersand (elided without '_) - (p.span.shrink_to_hi(), format!("{name} ")) - } else { - // Underscore (elided with '_) - (p.span, name.to_string()) - } - }) - .collect::<Vec<_>>() + && let mut spans_suggs = + make_elided_region_spans_suggs(name, generics.params.iter()) && spans_suggs.len() > 1 { let use_lt = if existing_lt_name == None { @@ -430,6 +418,57 @@ pub fn suggest_new_region_bound( } } +fn make_elided_region_spans_suggs<'a>( + name: &str, + generic_params: impl Iterator<Item = &'a GenericParam<'a>>, +) -> Vec<(Span, String)> { + let mut spans_suggs = Vec::new(); + let mut bracket_span = None; + let mut consecutive_brackets = 0; + + let mut process_consecutive_brackets = + |span: Option<Span>, spans_suggs: &mut Vec<(Span, String)>| { + if span + .is_some_and(|span| bracket_span.map_or(true, |bracket_span| span == bracket_span)) + { + consecutive_brackets += 1; + } else if let Some(bracket_span) = bracket_span.take() { + let sugg = std::iter::once("<") + .chain(std::iter::repeat(name).take(consecutive_brackets).intersperse(", ")) + .chain([">"]) + .collect(); + spans_suggs.push((bracket_span.shrink_to_hi(), sugg)); + consecutive_brackets = 0; + } + bracket_span = span; + }; + + for p in generic_params { + if let GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(kind) } = p.kind { + match kind { + MissingLifetimeKind::Underscore => { + process_consecutive_brackets(None, &mut spans_suggs); + spans_suggs.push((p.span, name.to_string())) + } + MissingLifetimeKind::Ampersand => { + process_consecutive_brackets(None, &mut spans_suggs); + spans_suggs.push((p.span.shrink_to_hi(), format!("{name} "))); + } + MissingLifetimeKind::Comma => { + process_consecutive_brackets(None, &mut spans_suggs); + spans_suggs.push((p.span.shrink_to_hi(), format!("{name}, "))); + } + MissingLifetimeKind::Brackets => { + process_consecutive_brackets(Some(p.span), &mut spans_suggs); + } + } + } + } + process_consecutive_brackets(None, &mut spans_suggs); + + spans_suggs +} + impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub fn get_impl_ident_and_self_ty_from_trait( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 24eaff08220..fda3564bdbe 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -299,8 +299,11 @@ impl<T> Trait<T> for X { } (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias)) if let Some(def_id) = t.principal_def_id() - && tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any( - |(pred, _span)| match pred.kind().skip_binder() { + && tcx + .explicit_item_super_predicates(alias.def_id) + .skip_binder() + .iter() + .any(|(pred, _span)| match pred.kind().skip_binder() { ty::ClauseKind::Trait(trait_predicate) if trait_predicate.polarity == ty::ImplPolarity::Positive => @@ -308,8 +311,7 @@ impl<T> Trait<T> for X { trait_predicate.def_id() == def_id } _ => false, - }, - ) => + }) => { diag.help(format!( "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \ @@ -412,7 +414,7 @@ impl<T> Trait<T> for X { ty::Alias(..) => values.expected, _ => values.found, }; - let preds = tcx.explicit_item_bounds(opaque_ty.def_id); + let preds = tcx.explicit_item_super_predicates(opaque_ty.def_id); for (pred, _span) in preds.skip_binder() { let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder() else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 44e14387c5c..a3ff655b609 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -678,7 +678,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { let infcx = self.build(); - let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index a6f8115c27e..02b8ded285f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -94,9 +94,6 @@ impl<'tcx> InferCtxt<'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> InferResult<'tcx, ()> { - if a.references_error() || b.references_error() { - return Ok(InferOk { value: (), obligations: vec![] }); - } let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 3ef37bf3466..bd981c20567 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -300,7 +300,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator<Item = ty::Region<'tcx>> { let tcx = self.tcx; - let bounds = tcx.item_bounds(alias_ty.def_id); + let bounds = tcx.item_super_predicates(alias_ty.def_id); trace!("{:#?}", bounds.skip_binder()); bounds .iter_instantiated(tcx, alias_ty.args) diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 029bddda1e1..ee9ce842d00 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -18,15 +18,16 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(extend_one)] #![feature(let_chains)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(iterator_try_collect)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(try_blocks)] +#![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 95f312a31b3..26fc3f20b2c 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -191,7 +191,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe levels.add_id(hir::CRATE_HIR_ID); levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID) } - hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(), + hir::OwnerNode::Synthetic => unreachable!(), }, } @@ -1078,6 +1078,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { feature, GateIssue::Language, lint_from_cli, + None, ); }, ); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 3e10879e241..91f907e4567 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -295,7 +295,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => { elaborate( cx.tcx, - cx.tcx.explicit_item_bounds(def).instantiate_identity_iter_copied(), + cx.tcx + .explicit_item_super_predicates(def) + .instantiate_identity_iter_copied(), ) // We only care about self bounds for the impl-trait .filter_only_self() diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index f456dd09dea..3d0846ae6de 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -38,6 +38,9 @@ metadata_crate_dep_multiple = cannot satisfy dependencies so `{$crate_name}` only shows up once .help = having upstream crates all available in one format will likely make this go away +metadata_crate_dep_not_static = + `{$crate_name}` was unavailable as a static crate, preventing fully static linking + metadata_crate_location_unknown_type = extern location for {$crate_name} is of an unknown type: {$path} diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index b80a9e9612a..4d1bd455412 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -54,7 +54,7 @@ use crate::creader::CStore; use crate::errors::{ BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired, - RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes, + NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes, }; use rustc_data_structures::fx::FxHashMap; @@ -123,13 +123,15 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { CrateType::Rlib => Linkage::NotLinked, }; + let mut unavailable_as_static = Vec::new(); + match preferred_linkage { // If the crate is not linked, there are no link-time dependencies. Linkage::NotLinked => return Vec::new(), Linkage::Static => { // Attempt static linkage first. For dylibs and executables, we may be // able to retry below with dynamic linkage. - if let Some(v) = attempt_static(tcx) { + if let Some(v) = attempt_static(tcx, &mut unavailable_as_static) { return v; } @@ -169,11 +171,11 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let src = tcx.used_crate_source(cnum); if src.dylib.is_some() { info!("adding dylib: {}", name); - add_library(tcx, cnum, RequireDynamic, &mut formats); + add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static); let deps = tcx.dylib_dependency_formats(cnum); for &(depnum, style) in deps.iter() { info!("adding {:?}: {}", style, tcx.crate_name(depnum)); - add_library(tcx, depnum, style, &mut formats); + add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static); } } } @@ -201,7 +203,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { { assert!(src.rlib.is_some() || src.rmeta.is_some()); info!("adding staticlib: {}", tcx.crate_name(cnum)); - add_library(tcx, cnum, RequireStatic, &mut formats); + add_library(tcx, cnum, RequireStatic, &mut formats, &mut unavailable_as_static); ret[cnum.as_usize() - 1] = Linkage::Static; } } @@ -252,6 +254,7 @@ fn add_library( cnum: CrateNum, link: LinkagePreference, m: &mut FxHashMap<CrateNum, LinkagePreference>, + unavailable_as_static: &mut Vec<CrateNum>, ) { match m.get(&cnum) { Some(&link2) => { @@ -263,7 +266,13 @@ fn add_library( // This error is probably a little obscure, but I imagine that it // can be refined over time. if link2 != link || link == RequireStatic { - tcx.dcx().emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) }); + tcx.dcx().emit_err(CrateDepMultiple { + crate_name: tcx.crate_name(cnum), + non_static_deps: unavailable_as_static + .drain(..) + .map(|cnum| NonStaticCrateDep { crate_name: tcx.crate_name(cnum) }) + .collect(), + }); } } None => { @@ -272,7 +281,7 @@ fn add_library( } } -fn attempt_static(tcx: TyCtxt<'_>) -> Option<DependencyList> { +fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<DependencyList> { let all_crates_available_as_rlib = tcx .crates(()) .iter() @@ -281,7 +290,11 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option<DependencyList> { if tcx.dep_kind(cnum).macros_only() { return None; } - Some(tcx.used_crate_source(cnum).rlib.is_some()) + let is_rlib = tcx.used_crate_source(cnum).rlib.is_some(); + if !is_rlib { + unavailable.push(cnum); + } + Some(is_rlib) }) .all(|is_rlib| is_rlib); if !all_crates_available_as_rlib { diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 8bf6b665de8..b50ae057709 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -38,6 +38,14 @@ pub struct RustcLibRequired<'a> { #[help] pub struct CrateDepMultiple { pub crate_name: Symbol, + #[subdiagnostic] + pub non_static_deps: Vec<NonStaticCrateDep>, +} + +#[derive(Subdiagnostic)] +#[note(metadata_crate_dep_not_static)] +pub struct NonStaticCrateDep { + pub crate_name: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 03783fa9798..596da58b091 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1063,6 +1063,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ty::EarlyBinder::bind(&*output) } + fn get_explicit_item_super_predicates( + self, + index: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + let lazy = self.root.tables.explicit_item_super_predicates.get(self, index); + let output = if lazy.is_default() { + &mut [] + } else { + tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) + }; + ty::EarlyBinder::bind(&*output) + } + fn get_variant( self, kind: DefKind, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 1c59af51589..1aabd296641 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -206,6 +206,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) { provide! { tcx, def_id, other, cdata, explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) } + explicit_item_super_predicates => { cdata.get_explicit_item_super_predicates(def_id.index, tcx) } explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d8cfceab460..42724f7dd2b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -817,8 +817,8 @@ struct AnalyzeAttrState { #[inline] fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { let mut should_encode = false; - if rustc_feature::is_builtin_only_local(attr.name_or_empty()) { - // Attributes marked local-only don't need to be encoded for downstream crates. + if !rustc_feature::encode_cross_crate(attr.name_or_empty()) { + // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. } else if attr.doc_str().is_some() { // We keep all doc comments reachable to rustdoc because they might be "imported" into // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into @@ -1067,14 +1067,11 @@ fn should_encode_mir( // Full-fledged functions + closures DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); - let mut opt = tcx.sess.opts.unstable_opts.always_encode_mir + let opt = tcx.sess.opts.unstable_opts.always_encode_mir || (tcx.sess.opts.output_types.should_codegen() && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); - if let Some(intrinsic) = tcx.intrinsic(def_id) { - opt &= !intrinsic.must_be_overridden; - } // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); @@ -1494,6 +1491,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let DefKind::OpaqueTy = def_kind { self.encode_explicit_item_bounds(def_id); + self.encode_explicit_item_super_predicates(def_id); self.tables .is_type_alias_impl_trait .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); @@ -1602,6 +1600,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } + fn encode_explicit_item_super_predicates(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_explicit_item_super_predicates({:?})", def_id); + let bounds = self.tcx.explicit_item_super_predicates(def_id).skip_binder(); + record_defaulted_array!(self.tables.explicit_item_super_predicates[def_id] <- bounds); + } + #[instrument(level = "debug", skip(self))] fn encode_info_for_assoc_item(&mut self, def_id: DefId) { let tcx = self.tcx; @@ -1614,6 +1618,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { AssocItemContainer::TraitContainer => { if let ty::AssocKind::Type = item.kind { self.encode_explicit_item_bounds(def_id); + self.encode_explicit_item_super_predicates(def_id); } } AssocItemContainer::ImplContainer => { @@ -2201,7 +2206,7 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata { let mmap = if len > 0 { let mut mmap = MmapMut::map_anon(len).unwrap(); for _ in 0..len { - (&mut mmap[..]).write(&[d.read_u8()]).unwrap(); + (&mut mmap[..]).write_all(&[d.read_u8()]).unwrap(); } mmap.flush().unwrap(); Some(mmap.make_read_only().unwrap()) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8aa31ef564f..5b0be8ac230 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -387,6 +387,7 @@ define_tables! { // corresponding DefPathHash. def_path_hashes: Table<DefIndex, u64>, explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, + explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, 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>>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5043bd855cc..5e74ce86007 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -20,44 +20,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::spec::abi::Abi; -#[inline] -pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { - match node { - Node::Item(Item { - owner_id, - kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), - .. - }) - | Node::TraitItem(TraitItem { - owner_id, - kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), - .. - }) - | Node::ImplItem(ImplItem { - owner_id, - kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), - .. - }) => Some((owner_id.def_id, *body)), - - Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { - Some((*def_id, *body)) - } - - Node::AnonConst(constant) => Some((constant.def_id, constant.body)), - Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), - - _ => None, - } -} - -fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool { - match associated_body(node) { - Some((_, b)) => b.hir_id == hir_id, - None => false, - } -} - // FIXME: the structure was necessary in the past but now it // only serves as "namespace" for HIR-related methods, and can be // removed if all the methods are reasonably renamed and moved to tcx @@ -114,20 +76,16 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { if self.current_id == CRATE_HIR_ID { return None; } - loop { - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.def_key(self.current_id.owner.def_id).parent; - let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { - let def_id = LocalDefId { local_def_index }; - self.map.tcx.local_def_id_to_hir_id(def_id).owner - }); - self.current_id = HirId::make_owner(parent_id.def_id); + let parent_id = self.map.def_key(self.current_id.owner.def_id).parent; + let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + self.map.tcx.local_def_id_to_hir_id(def_id).owner + }); + self.current_id = HirId::make_owner(parent_id.def_id); - // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. - let node = self.map.tcx.hir_owner_node(self.current_id.owner); - return Some((self.current_id.owner, node)); - } + let node = self.map.tcx.hir_owner_node(self.current_id.owner); + return Some((self.current_id.owner, node)); } } @@ -273,7 +231,7 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { for (_, node) in self.parent_iter(hir_id) { - if let Some((def_id, _)) = associated_body(node) { + if let Some((def_id, _)) = node.associated_body() { return def_id; } } @@ -286,20 +244,18 @@ impl<'hir> Map<'hir> { /// item (possibly associated), a closure, or a `hir::AnonConst`. pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId { let parent = self.tcx.parent_hir_id(hir_id); - assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}"); + assert_eq!(self.tcx.hir_node(parent).body_id().unwrap().hir_id, hir_id, "{hir_id:?}"); parent } pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { - associated_body(self.tcx.parent_hir_node(hir_id)).unwrap().0 + self.tcx.parent_hir_node(hir_id).associated_body().unwrap().0 } /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> { - let node = self.tcx.hir_node_by_def_id(id); - let (_, body_id) = associated_body(node)?; - Some(body_id) + self.tcx.hir_node_by_def_id(id).body_id() } /// Given a body owner's id, returns the `BodyId` associated with it. @@ -954,7 +910,7 @@ impl<'hir> Map<'hir> { Node::Crate(item) => item.spans.inner_span, Node::WhereBoundPredicate(pred) => pred.span, Node::ArrayLenInfer(inf) => inf.span, - Node::AssocOpaqueTy(..) => unreachable!(), + Node::Synthetic => unreachable!(), Node::Err(span) => *span, } } @@ -1219,7 +1175,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::Crate(..) => String::from("(root_crate)"), Node::WhereBoundPredicate(_) => node_str("where bound predicate"), Node::ArrayLenInfer(_) => node_str("array len infer"), - Node::AssocOpaqueTy(..) => unreachable!(), + Node::Synthetic => unreachable!(), Node::Err(_) => node_str("error"), } } @@ -1314,7 +1270,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_item(&mut self, item: &'hir Item<'hir>) { - if associated_body(Node::Item(item)).is_some() { + if Node::Item(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1355,7 +1311,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { - if associated_body(Node::TraitItem(item)).is_some() { + if Node::TraitItem(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1364,7 +1320,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { } fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { - if associated_body(Node::ImplItem(item)).is_some() { + if Node::ImplItem(item).associated_body().is_some() { self.body_owners.push(item.owner_id.def_id); } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index c3e4a03ad16..e52a5863fd0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -24,13 +24,13 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![cfg_attr(bootstrap, feature(exhaustive_patterns))] -#![cfg_attr(not(bootstrap), feature(min_exhaustive_patterns))] +#![feature(min_exhaustive_patterns)] #![feature(rustdoc_internals)] #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(closure_track_caller)] #![feature(core_intrinsics)] #![feature(const_type_name)] #![feature(discriminant_kind)] @@ -48,7 +48,7 @@ #![feature(trusted_len)] #![feature(type_alias_impl_trait)] #![feature(strict_provenance)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(rustc_attrs)] #![feature(control_flow_enum)] #![feature(trait_upcasting)] diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index f9edbb3c5ae..6275942bafe 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -671,11 +671,11 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, i // So we do not read exactly 16 bytes into the u128, just the "payload". let uint = match endianness { Endian::Little => { - source.read(&mut buf)?; + source.read_exact(&mut buf[..source.len()])?; Ok(u128::from_le_bytes(buf)) } Endian::Big => { - source.read(&mut buf[16 - source.len()..])?; + source.read_exact(&mut buf[16 - source.len()..])?; Ok(u128::from_be_bytes(buf)) } }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index db40cb29082..48edbde68e5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -280,13 +280,6 @@ pub struct CoroutineInfo<'tcx> { /// using `run_passes`. pub by_move_body: Option<Body<'tcx>>, - /// The body of the coroutine, modified to take its upvars by mutable ref rather than by - /// immutable ref. - /// - /// FIXME(async_closures): This is literally the same body as the parent body. Find a better - /// way to represent the by-mut signature (or cap the closure-kind of the coroutine). - pub by_mut_body: Option<Body<'tcx>>, - /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option<CoroutineLayout<'tcx>>, @@ -307,7 +300,6 @@ impl<'tcx> CoroutineInfo<'tcx> { yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), by_move_body: None, - by_mut_body: None, coroutine_drop: None, coroutine_layout: None, } @@ -674,10 +666,6 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref()?.by_move_body.as_ref() } - pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> { - self.coroutine.as_ref()?.by_mut_body.as_ref() - } - #[inline] pub fn coroutine_kind(&self) -> Option<CoroutineKind> { self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 845b1717550..be960669ff4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -345,8 +345,11 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | - ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } | + ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: _def_id, + receiver_by_ref: _, + } | + ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 865299e15c8..10d92583a55 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -343,11 +343,14 @@ rustc_queries! { } } - /// Returns the list of bounds that can be used for - /// `SelectionCandidate::ProjectionCandidate(_)` and - /// `ProjectionTyCandidate::TraitDef`. - /// Specifically this is the bounds written on the trait's type - /// definition, or those after the `impl` keyword + /// Returns the list of bounds that are required to be satsified + /// by a implementation or definition. For associated types, these + /// must be satisfied for an implementation to be well-formed, + /// and for opaque types, these are required to be satisfied by + /// the hidden-type of the opaque. + /// + /// Syntactially, these are the bounds written on the trait's type + /// definition, or those after the `impl` keyword for an opaque: /// /// ```ignore (incomplete) /// type X: Bound + 'lt @@ -363,7 +366,16 @@ 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 + /// share the `Self` type of the item. These are a subset of the bounds + /// that may explicitly be used for things like closure signature + /// deduction. + query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -390,6 +402,14 @@ rustc_queries! { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } + query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } + } + + query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } + } + /// Look up all native libraries this crate depends on. /// These are assembled from the following places: /// - `extern` blocks (depending on their `link` attributes) @@ -703,8 +723,8 @@ rustc_queries! { separate_provide_extern } - query adt_sized_constraint(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> { - desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } + query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<Ty<'tcx>>> { + desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) } } query adt_dtorck_constraint( diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index dc4cd203415..6dcea2aaff1 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -164,6 +164,19 @@ pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, + pub normalization_nested_goals: NestedNormalizationGoals<'tcx>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] +pub struct NestedNormalizationGoals<'tcx>(pub Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>); +impl<'tcx> NestedNormalizationGoals<'tcx> { + pub fn empty() -> Self { + NestedNormalizationGoals(vec![]) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } } // FIXME: Having to clone `region_constraints` for folding feels bad and @@ -183,6 +196,10 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { .iter() .map(|opaque| opaque.try_fold_with(folder)) .collect::<Result<_, F::Error>>()?, + normalization_nested_goals: self + .normalization_nested_goals + .clone() + .try_fold_with(folder)?, })) } @@ -190,6 +207,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), + normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), }) } } @@ -197,7 +215,8 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { try_visit!(self.region_constraints.visit_with(visitor)); - self.opaque_types.visit_with(visitor) + try_visit!(self.opaque_types.visit_with(visitor)); + self.normalization_nested_goals.visit_with(visitor) } } @@ -239,7 +258,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { /// /// This is necessary as we treat nested goals different depending on /// their source. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeVisitable, TypeFoldable)] pub enum GoalSource { Misc, /// We're proving a where-bound of an impl. @@ -256,12 +275,6 @@ pub enum GoalSource { ImplWhereBound, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] -pub enum IsNormalizesToHack { - Yes, - No, -} - /// Possible ways the given goal can be proven. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CandidateSource { diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 90180af3b16..16842c8208f 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -19,8 +19,8 @@ //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html use super::{ - CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack, - NoSolution, QueryInput, QueryResult, + CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, NoSolution, + QueryInput, QueryResult, }; use crate::{infer::canonical::CanonicalVarValues, ty}; use format::ProofTreeFormatter; @@ -50,7 +50,7 @@ pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>; #[derive(Eq, PartialEq)] pub enum GoalEvaluationKind<'tcx> { Root { orig_values: Vec<ty::GenericArg<'tcx>> }, - Nested { is_normalizes_to_hack: IsNormalizesToHack }, + Nested, } #[derive(Eq, PartialEq)] diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 8d3109a7b28..43931205017 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -55,10 +55,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result { let goal_text = match eval.kind { GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL", - GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack { - IsNormalizesToHack::No => "GOAL", - IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", - }, + GoalEvaluationKind::Nested => "GOAL", }; write!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?; self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation)) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2e1c7df6454..a7144316769 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -590,10 +590,10 @@ impl<'tcx> AdtDef<'tcx> { tcx.adt_destructor(self.did()) } - /// Returns a list of types such that `Self: Sized` if and only if that - /// type is `Sized`, or `ty::Error` if this type has a recursive layout. - pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> { - tcx.adt_sized_constraint(self.did()) + /// Returns a type such that `Self: Sized` if and only if that type is `Sized`, + /// or `None` if the type is always sized. + pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<Ty<'tcx>>> { + if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None } } } @@ -601,5 +601,5 @@ impl<'tcx> AdtDef<'tcx> { #[derive(HashStable)] pub enum Representability { Representable, - Infinite, + Infinite(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 17ba97c5fd3..8a87538e788 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -43,7 +43,9 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal} #[cfg(parallel_compiler)] use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Diag, DiagCtxt, DiagMessage, ErrorGuaranteed, LintDiagnostic, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, DiagCtxt, DiagMessage, ErrorGuaranteed, LintDiagnostic, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; @@ -594,6 +596,27 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { pub fn feed_owner_id(&self) -> TyCtxtFeed<'tcx, hir::OwnerId> { TyCtxtFeed { tcx: self.tcx, key: hir::OwnerId { def_id: self.key } } } + + // Fills in all the important parts needed by HIR queries + pub fn feed_hir(&self) { + self.local_def_id_to_hir_id(HirId::make_owner(self.def_id())); + + let node = hir::OwnerNode::Synthetic; + let bodies = Default::default(); + let attrs = hir::AttributeMap::EMPTY; + + let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map); + let node = node.into(); + self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { + opt_hash_including_bodies, + nodes: IndexVec::from_elem_n( + hir::ParentedNode { parent: hir::ItemLocalId::INVALID, node }, + 1, + ), + bodies, + }))); + self.feed_owner_id().hir_attrs(attrs); + } } /// The central data structure of the compiler. It stores references @@ -1805,7 +1828,7 @@ impl<'tcx> TyCtxt<'tcx> { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; let future_trait = self.require_lang_item(LangItem::Future, None); - self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { + self.explicit_item_super_predicates(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { return false; }; @@ -2174,6 +2197,45 @@ impl<'tcx> TyCtxt<'tcx> { lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate); } + /// Find the crate root and the appropriate span where `use` and outer attributes can be + /// inserted at. + pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option<Span> { + for (_hir_id, node) in self.hir().parent_iter(hir_id) { + if let hir::Node::Crate(m) = node { + return Some(m.spans.inject_use_span.shrink_to_lo()); + } + } + None + } + + pub fn disabled_nightly_features<E: rustc_errors::EmissionGuarantee>( + self, + diag: &mut Diag<'_, E>, + hir_id: Option<HirId>, + features: impl IntoIterator<Item = (String, Symbol)>, + ) { + if !self.sess.is_nightly_build() { + return; + } + + let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id)); + for (desc, feature) in features { + // FIXME: make this string translatable + let msg = + format!("add `#![feature({feature})]` to the crate attributes to enable{desc}"); + if let Some(span) = span { + diag.span_suggestion_verbose( + span, + msg, + format!("#![feature({feature})]\n"), + Applicability::MachineApplicable, + ); + } else { + diag.help(msg); + } + } + } + /// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically /// generated by `#[derive(LintDiagnostic)]`). #[track_caller] diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 788ccd5dbbd..5e256dc8d26 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -85,6 +85,7 @@ where /// Allows access to the current `ImplicitCtxt` in a closure if one is available. #[inline] +#[track_caller] pub fn with_context_opt<F, R>(f: F) -> R where F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, @@ -147,9 +148,13 @@ where /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. /// The closure is passed None if there is no `ImplicitCtxt` available. #[inline] +#[track_caller] pub fn with_opt<F, R>(f: F) -> R where F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R, { - with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) + with_context_opt( + #[track_caller] + |opt_context| f(opt_context.map(|context| context.tcx)), + ) } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index bbcc244cb26..da5d57db5be 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { return InhabitedPredicate::True; } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 814c3629b08..4748e961019 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -90,15 +90,19 @@ pub enum InstanceDef<'tcx> { /// and dispatch to the `FnMut::call_mut` instance for the closure. ClosureOnceShim { call_once: DefId, track_caller: bool }, - /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or - /// `<[Fn coroutine-closure] as FnMut>::call_mut`. + /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` /// /// The body generated here differs significantly from the `ClosureOnceShim`, /// since we need to generate a distinct coroutine type that will move the /// closure's upvars *out* of the closure. ConstructCoroutineInClosureShim { coroutine_closure_def_id: DefId, - target_kind: ty::ClosureKind, + // Whether the generated MIR body takes the coroutine by-ref. This is + // because the signature of `<{async fn} as FnMut>::call_mut` is: + // `fn(&mut self, args: A) -> <Self as FnOnce>::Output`, that is to say + // that it returns the `FnOnce`-flavored coroutine but takes the closure + // by mut ref (and similarly for `Fn::call`). + receiver_by_ref: bool, }, /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` @@ -107,7 +111,7 @@ pub enum InstanceDef<'tcx> { /// /// This will select the body that is produced by the `ByMoveBody` transform, and thus /// take and use all of its upvars by-move rather than by-ref. - CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind }, + CoroutineKindShim { coroutine_def_id: DefId }, /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking @@ -192,9 +196,9 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: def_id, - target_kind: _, + receiver_by_ref: _, } - | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ } + | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -651,10 +655,7 @@ impl<'tcx> Instance<'tcx> { Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else { Some(Instance { - def: ty::InstanceDef::CoroutineKindShim { - coroutine_def_id, - target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), - }, + def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id }, args, }) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8565f90957f..6632d980bff 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1752,9 +1752,8 @@ impl<'tcx> TyCtxt<'tcx> { let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) - } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) { - bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { + debug_assert!(rustc_feature::encode_cross_crate(attr)); self.item_attrs(did).iter().filter(filter_fn) } } @@ -1786,12 +1785,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether an item is annotated with an attribute. pub fn has_attr(self, did: impl Into<DefId>, attr: Symbol) -> bool { - let did: DefId = did.into(); - if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) { - bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); - } else { - self.get_attrs(did, attr).next().is_some() - } + self.get_attrs(did, attr).next().is_some() } /// Returns `true` if this is an `auto trait`. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 802953867ac..995b439d10a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -4,7 +4,7 @@ use crate::query::Providers; use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing}; use crate::ty::GenericArgKind; use crate::ty::{ - ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, + ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_apfloat::ieee::{Double, Single}; @@ -270,6 +270,31 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } + /// Prints `(...)` around what `f` prints. + fn parenthesized( + &mut self, + f: impl FnOnce(&mut Self) -> Result<(), PrintError>, + ) -> Result<(), PrintError> { + self.write_str("(")?; + f(self)?; + self.write_str(")")?; + Ok(()) + } + + /// Prints `(...)` around what `f` prints if `parenthesized` is true, otherwise just prints `f`. + fn maybe_parenthesized( + &mut self, + f: impl FnOnce(&mut Self) -> Result<(), PrintError>, + parenthesized: bool, + ) -> Result<(), PrintError> { + if parenthesized { + self.parenthesized(f)?; + } else { + f(self)?; + } + Ok(()) + } + /// Prints `<...>` around what `f` prints. fn generic_delimiters( &mut self, @@ -1490,12 +1515,137 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? - ty::ConstKind::Expr(_) => p!("{{const expr}}"), + ty::ConstKind::Expr(expr) => self.pretty_print_const_expr(expr, print_ty)?, ty::ConstKind::Error(_) => p!("{{const error}}"), }; Ok(()) } + fn pretty_print_const_expr( + &mut self, + expr: Expr<'tcx>, + print_ty: bool, + ) -> Result<(), PrintError> { + define_scoped_cx!(self); + match expr { + Expr::Binop(op, c1, c2) => { + let precedence = |binop: rustc_middle::mir::BinOp| { + use rustc_ast::util::parser::AssocOp; + AssocOp::from_ast_binop(binop.to_hir_binop().into()).precedence() + }; + let op_precedence = precedence(op); + let formatted_op = op.to_hir_binop().as_str(); + let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) { + ( + ty::ConstKind::Expr(Expr::Binop(lhs_op, _, _)), + ty::ConstKind::Expr(Expr::Binop(rhs_op, _, _)), + ) => (precedence(lhs_op) < op_precedence, precedence(rhs_op) < op_precedence), + (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), ty::ConstKind::Expr(_)) => { + (precedence(lhs_op) < op_precedence, true) + } + (ty::ConstKind::Expr(_), ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { + (true, precedence(rhs_op) < op_precedence) + } + (ty::ConstKind::Expr(_), ty::ConstKind::Expr(_)) => (true, true), + (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), _) => { + (precedence(lhs_op) < op_precedence, false) + } + (_, ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { + (false, precedence(rhs_op) < op_precedence) + } + (ty::ConstKind::Expr(_), _) => (true, false), + (_, ty::ConstKind::Expr(_)) => (false, true), + _ => (false, false), + }; + + self.maybe_parenthesized( + |this| this.pretty_print_const(c1, print_ty), + lhs_parenthesized, + )?; + p!(write(" {formatted_op} ")); + self.maybe_parenthesized( + |this| this.pretty_print_const(c2, print_ty), + rhs_parenthesized, + )?; + } + Expr::UnOp(op, ct) => { + use rustc_middle::mir::UnOp; + let formatted_op = match op { + UnOp::Not => "!", + UnOp::Neg => "-", + }; + let parenthesized = match ct.kind() { + ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op, + ty::ConstKind::Expr(_) => true, + _ => false, + }; + p!(write("{formatted_op}")); + self.maybe_parenthesized( + |this| this.pretty_print_const(ct, print_ty), + parenthesized, + )? + } + Expr::FunctionCall(fn_def, fn_args) => { + use ty::TyKind; + match fn_def.ty().kind() { + TyKind::FnDef(def_id, gen_args) => { + p!(print_value_path(*def_id, gen_args), "("); + if print_ty { + let tcx = self.tcx(); + let sig = tcx.fn_sig(def_id).instantiate(tcx, gen_args).skip_binder(); + + let mut args_with_ty = fn_args.iter().map(|ct| (ct, ct.ty())); + let output_ty = sig.output(); + + if let Some((ct, ty)) = args_with_ty.next() { + self.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + ": ", + )?; + for (ct, ty) in args_with_ty { + p!(", "); + self.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + ": ", + )?; + } + } + p!(write(") -> {output_ty}")); + } else { + p!(comma_sep(fn_args.iter()), ")"); + } + } + _ => bug!("unexpected type of fn def"), + } + } + Expr::Cast(kind, ct, ty) => { + use ty::abstract_const::CastKind; + if kind == CastKind::As || (kind == CastKind::Use && self.should_print_verbose()) { + let parenthesized = match ct.kind() { + ty::ConstKind::Expr(Expr::Cast(_, _, _)) => false, + ty::ConstKind::Expr(_) => true, + _ => false, + }; + self.maybe_parenthesized( + |this| { + this.typed_value( + |this| this.pretty_print_const(ct, print_ty), + |this| this.pretty_print_type(ty), + " as ", + ) + }, + parenthesized, + )?; + } else { + self.pretty_print_const(ct, print_ty)? + } + } + } + Ok(()) + } + fn pretty_print_const_scalar( &mut self, scalar: Scalar, diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 7abc3cd2838..c66b9864e46 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -251,6 +251,7 @@ impl<'tcx> Region<'tcx> { } ty::ReError(_) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_ERROR; } } @@ -336,7 +337,9 @@ pub struct EarlyParamRegion { impl std::fmt::Debug for EarlyParamRegion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) + // FIXME(BoxyUwU): self.def_id goes first because of `erased-regions-in-hidden-ty.rs` being impossible to write + // error annotations for otherwise. :). Ideally this would be `self.name, self.index, self.def_id`. + write!(f, "{:?}_{}/#{}", self.def_id, self.name, self.index) } } @@ -381,13 +384,25 @@ pub enum BoundRegionKind { BrEnv, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] #[derive(HashStable)] pub struct BoundRegion { pub var: BoundVar, pub kind: BoundRegionKind, } +impl core::fmt::Debug for BoundRegion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + BoundRegionKind::BrAnon => write!(f, "{:?}", self.var), + BoundRegionKind::BrEnv => write!(f, "{:?}.Env", self.var), + BoundRegionKind::BrNamed(def, symbol) => { + write!(f, "{:?}.Named({:?}, {:?})", self.var, def, symbol) + } + } + } +} + impl BoundRegionKind { pub fn is_named(&self) -> bool { match *self { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 11065b2a382..6e0a9eb86dd 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -483,7 +483,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { self.to_coroutine( tcx, parent_args, - Ty::from_closure_kind(tcx, goal_kind), + Ty::from_coroutine_closure_kind(tcx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) @@ -2456,6 +2456,25 @@ impl<'tcx> Ty<'tcx> { } } + /// Like [`Ty::to_opt_closure_kind`], but it caps the "maximum" closure kind + /// to `FnMut`. This is because although we have three capability states, + /// `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`, we only need to distinguish two coroutine + /// bodies: by-ref and by-value. + /// + /// See the definition of `AsyncFn` and `AsyncFnMut` and the `CallRefFuture` + /// associated type for why we don't distinguish [`ty::ClosureKind::Fn`] and + /// [`ty::ClosureKind::FnMut`] for the purpose of the generated MIR bodies. + /// + /// This method should be used when constructing a `Coroutine` out of a + /// `CoroutineClosure`, when the `Coroutine`'s `kind` field is being populated + /// directly from the `CoroutineClosure`'s `kind`. + pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => tcx.types.i16, + ty::ClosureKind::FnOnce => tcx.types.i32, + } + } + /// Fast path helper for testing if a type is `Sized`. /// /// Returning true means the type is known to be sized. Returning @@ -2484,13 +2503,16 @@ impl<'tcx> Ty<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::Dynamic(_, _, ty::DynStar) => true, - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _args) => def.sized_constraint(tcx).skip_binder().is_empty(), + ty::Adt(def, args) => def + .sized_constraint(tcx) + .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 4287b382604..d8541f4b25a 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -568,6 +568,11 @@ impl<'a, V> LocalTableInContextMut<'a, V> { self.data.get_mut(&id.local_id) } + pub fn get(&mut self, id: hir::HirId) -> Option<&V> { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.get(&id.local_id) + } + pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.entry(id.local_id) diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index a67ec991582..43853a10896 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -28,14 +28,17 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>( args: fmt::Arguments<'_>, location: &Location<'_>, ) -> ! { - tls::with_opt(move |tcx| { - let msg = format!("{location}: {args}"); - match (tcx, span) { - (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), - (Some(tcx), None) => tcx.dcx().bug(msg), - (None, _) => panic_any(msg), - } - }) + tls::with_opt( + #[track_caller] + move |tcx| { + let msg = format!("{location}: {args}"); + match (tcx, span) { + (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg), + (Some(tcx), None) => tcx.dcx().bug(msg), + (None, _) => panic_any(msg), + } + }, + ) } /// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index f7a3879a7d4..5c17c0b3088 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -106,8 +106,8 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability { representable_ids.insert(def_id); } } - recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite + let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); + Representability::Infinite(guar) } } @@ -268,7 +268,7 @@ pub fn recursive_type_error( tcx: TyCtxt<'_>, mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, representable_ids: &FxHashSet<LocalDefId>, -) { +) -> ErrorGuaranteed { const ITEM_LIMIT: usize = 5; // Rotate the cycle so that the item with the lowest span is first @@ -344,7 +344,7 @@ pub fn recursive_type_error( suggestion, Applicability::HasPlaceholders, ) - .emit(); + .emit() } fn find_item_ty_spans( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index e7808ff880b..d2cbbf9be32 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -229,7 +229,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, scrutinee_span: Span, ) -> BlockAnd<()> { - let scrutinee_span = scrutinee_span; let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 411119b521b..acadfe7b35e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1013,8 +1013,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(source_scope) = scope { self.source_scope = source_scope; } - - self.expr_into_dest(Place::return_place(), block, expr_id) + if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) { + let source_info = self.source_info(rustc_span::DUMMY_SP); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + self.cfg.start_new_block().unit() + } else { + self.expr_into_dest(Place::return_place(), block, expr_id) + } } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index e3f202b7f18..7b22aea9158 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,11 +5,10 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(try_blocks)] #[macro_use] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 20d3b3f98ce..cfa853417ca 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -938,9 +938,6 @@ fn report_non_exhaustive_match<'p, 'tcx>( }; // In the case of an empty match, replace the '`_` not covered' diagnostic with something more // informative. - let mut err; - let pattern; - let patterns_len; if is_empty_match && !non_empty_enum { return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty { cx, @@ -948,33 +945,23 @@ fn report_non_exhaustive_match<'p, 'tcx>( span: sp, ty: scrut_ty, }); - } else { - // FIXME: migration of this diagnostic will require list support - let joined_patterns = joined_uncovered_patterns(cx, &witnesses); - err = create_e0004( - cx.tcx.sess, - sp, - format!("non-exhaustive patterns: {joined_patterns} not covered"), - ); - err.span_label( - sp, - format!( - "pattern{} {} not covered", - rustc_errors::pluralize!(witnesses.len()), - joined_patterns - ), - ); - patterns_len = witnesses.len(); - pattern = if witnesses.len() < 4 { - witnesses - .iter() - .map(|witness| cx.hoist_witness_pat(witness).to_string()) - .collect::<Vec<String>>() - .join(" | ") - } else { - "_".to_string() - }; - }; + } + + // FIXME: migration of this diagnostic will require list support + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); + let mut err = create_e0004( + cx.tcx.sess, + sp, + format!("non-exhaustive patterns: {joined_patterns} not covered"), + ); + err.span_label( + sp, + format!( + "pattern{} {} not covered", + rustc_errors::pluralize!(witnesses.len()), + joined_patterns + ), + ); // Point at the definition of non-covered `enum` variants. if let Some(AdtDefinedHere { adt_def_span, ty, variants }) = @@ -1021,6 +1008,23 @@ fn report_non_exhaustive_match<'p, 'tcx>( } } + // Whether we suggest the actual missing patterns or `_`. + let suggest_the_witnesses = witnesses.len() < 4; + let suggested_arm = if suggest_the_witnesses { + let pattern = witnesses + .iter() + .map(|witness| cx.hoist_witness_pat(witness).to_string()) + .collect::<Vec<String>>() + .join(" | "); + if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { + // Arms with a never pattern don't take a body. + pattern + } else { + format!("{pattern} => todo!()") + } + } else { + format!("_ => todo!()") + }; let mut suggestion = None; let sm = cx.tcx.sess.source_map(); match arms { @@ -1033,7 +1037,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( }; suggestion = Some(( sp.shrink_to_hi().with_hi(expr_span.hi()), - format!(" {{{indentation}{more}{pattern} => todo!(),{indentation}}}",), + format!(" {{{indentation}{more}{suggested_arm},{indentation}}}",), )); } [only] => { @@ -1059,7 +1063,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( }; suggestion = Some(( only.span.shrink_to_hi(), - format!("{comma}{pre_indentation}{pattern} => todo!()"), + format!("{comma}{pre_indentation}{suggested_arm}"), )); } [.., prev, last] => { @@ -1082,7 +1086,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( if let Some(spacing) = spacing { suggestion = Some(( last.span.shrink_to_hi(), - format!("{comma}{spacing}{pattern} => todo!()"), + format!("{comma}{spacing}{suggested_arm}"), )); } } @@ -1093,13 +1097,13 @@ fn report_non_exhaustive_match<'p, 'tcx>( let msg = format!( "ensure that all possible cases are being handled by adding a match arm with a wildcard \ pattern{}{}", - if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() { + if witnesses.len() > 1 && suggest_the_witnesses && suggestion.is_some() { ", a match arm with multiple or-patterns" } else { // we are either not suggesting anything, or suggesting `_` "" }, - match patterns_len { + match witnesses.len() { // non-exhaustive enum case 0 if suggestion.is_some() => " as shown", 0 => "", diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index f18a2354301..c5adb81b614 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -2,7 +2,6 @@ #![feature(box_patterns)] #![feature(exact_size_is_empty)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(try_blocks)] #[macro_use] diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 54b13a40e92..0d18d4fd69e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1964,15 +1964,21 @@ fn check_must_not_suspend_ty<'tcx>( debug!("Checking must_not_suspend for {}", ty); match *ty.kind() { - ty::Adt(..) if ty.is_box() => { - let boxed_ty = ty.boxed_ty(); - let descr_pre = &format!("{}boxed ", data.descr_pre); + ty::Adt(_, args) if ty.is_box() => { + let boxed_ty = args.type_at(0); + let allocator_ty = args.type_at(1); check_must_not_suspend_ty( tcx, boxed_ty, hir_id, param_env, - SuspendCheckData { descr_pre, ..data }, + SuspendCheckData { descr_pre: &format!("{}boxed ", data.descr_pre), ..data }, + ) || check_must_not_suspend_ty( + tcx, + allocator_ty, + hir_id, + param_env, + SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, ) } ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index e40f4520671..000b96ee801 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -67,45 +67,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { by_move_body.source = mir::MirSource { instance: InstanceDef::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), - target_kind: ty::ClosureKind::FnOnce, }, promoted: None, }; body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); - - // If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body. - // This is actually just a copy of the by-ref body, but with a different self type. - // FIXME(async_closures): We could probably unify this with the by-ref body somehow. - if coroutine_kind == ty::ClosureKind::Fn { - let by_mut_coroutine_ty = Ty::new_coroutine( - tcx, - coroutine_def_id.to_def_id(), - ty::CoroutineArgs::new( - tcx, - ty::CoroutineArgsParts { - parent_args: args.as_coroutine().parent_args(), - kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut), - resume_ty: args.as_coroutine().resume_ty(), - yield_ty: args.as_coroutine().yield_ty(), - return_ty: args.as_coroutine().return_ty(), - witness: args.as_coroutine().witness(), - tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(), - }, - ) - .args, - ); - let mut by_mut_body = body.clone(); - by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty; - dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(())); - by_mut_body.source = mir::MirSource { - instance: InstanceDef::CoroutineKindShim { - coroutine_def_id: coroutine_def_id.to_def_id(), - target_kind: ty::ClosureKind::FnMut, - }, - promoted: None, - }; - body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body); - } } } diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 9a1d8bae6b4..69dc4f2ddea 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -1,13 +1,12 @@ +use std::fmt::{self, Debug}; + use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::WithNumNodes; -use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; -use rustc_middle::mir::coverage::*; +use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; -use super::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops}; - -use std::fmt::{self, Debug}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops}; /// The coverage counter or counter expression associated with a particular /// BCB node or BCB edge. @@ -18,10 +17,6 @@ pub(super) enum BcbCounter { } impl BcbCounter { - fn is_expression(&self) -> bool { - matches!(self, Self::Expression { .. }) - } - pub(super) fn as_term(&self) -> CovTerm { match *self { BcbCounter::Counter { id, .. } => CovTerm::Counter(id), @@ -60,10 +55,6 @@ pub(super) struct CoverageCounters { /// We currently don't iterate over this map, but if we do in the future, /// switch it back to `FxIndexMap` to avoid query stability hazards. bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, - /// Tracks which BCBs have a counter associated with some incoming edge. - /// Only used by assertions, to verify that BCBs with incoming edge - /// counters do not have their own physical counters (expressions are allowed). - bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>, /// Table of expression data, associating each expression ID with its /// corresponding operator (+ or -) and its LHS/RHS operands. expressions: IndexVec<ExpressionId, Expression>, @@ -83,7 +74,6 @@ impl CoverageCounters { counter_increment_sites: IndexVec::new(), bcb_counters: IndexVec::from_elem_n(None, num_bcbs), bcb_edge_counters: FxHashMap::default(), - bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs), expressions: IndexVec::new(), }; @@ -122,14 +112,6 @@ impl CoverageCounters { } fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { - assert!( - // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also - // have an expression (to be injected into an existing `BasicBlock` represented by this - // `BasicCoverageBlock`). - counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb), - "attempt to add a `Counter` to a BCB target with existing incoming edge counters" - ); - if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { bug!( "attempt to set a BasicCoverageBlock coverage counter more than once; \ @@ -146,19 +128,6 @@ impl CoverageCounters { to_bcb: BasicCoverageBlock, counter_kind: BcbCounter, ) -> BcbCounter { - // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also - // have an expression (to be injected into an existing `BasicBlock` represented by this - // `BasicCoverageBlock`). - if let Some(node_counter) = self.bcb_counter(to_bcb) - && !node_counter.is_expression() - { - bug!( - "attempt to add an incoming edge counter from {from_bcb:?} \ - when the target BCB already has {node_counter:?}" - ); - } - - self.bcb_has_incoming_edge_counters.insert(to_bcb); if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) { bug!( "attempt to set an edge counter more than once; from_bcb: \ diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index b2407c54507..83189c6a50a 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -13,7 +13,6 @@ use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans}; use crate::MirPass; -use rustc_middle::hir; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, @@ -368,8 +367,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir // to HIR for it. let hir_node = tcx.hir_node_by_def_id(def_id); - let (_, fn_body_id) = - hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); let hir_body = tcx.hir().body(fn_body_id); let maybe_fn_sig = hir_node.fn_sig(); diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 07e6ecccaa4..483fd753e70 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -23,10 +23,6 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } - if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) { - return false; - } - // This just reproduces the logic from Instance::requires_inline. match tcx.def_kind(def_id) { DefKind::Ctor(..) | DefKind::Closure => return true, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 74e7d51ea96..24bc263e5a7 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -8,7 +8,6 @@ #![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(never_type)] #![feature(option_get_or_insert_default)] #![feature(round_char_boundary)] @@ -638,12 +637,6 @@ fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { } fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { - if tcx.intrinsic(did).is_some_and(|i| i.must_be_overridden) { - span_bug!( - tcx.def_span(did), - "this intrinsic must be overridden by the codegen backend, it has no meaningful body", - ) - } if tcx.is_constructor(did.to_def_id()) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 77478cc741d..17a1c3c7157 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -186,9 +186,6 @@ fn run_passes_inner<'tcx>( if let Some(by_move_body) = coroutine.by_move_body.as_mut() { run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); } - if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() { - run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each); - } } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index dd2b24ad669..71de64c6d26 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::query::Providers; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt}; -use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_index::{Idx, IndexVec}; @@ -72,37 +72,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id, - target_kind, - } => match target_kind { - ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"), - ty::ClosureKind::FnMut => { - // No need to optimize the body, it has already been optimized - // since we steal it from the `AsyncFn::call` body and just fix - // the return type. - return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); - } - ty::ClosureKind::FnOnce => { - build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) - } - }, + receiver_by_ref, + } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => { - return tcx - .optimized_mir(coroutine_def_id) - .coroutine_by_mut_body() - .unwrap() - .clone(); - } - ty::ClosureKind::FnOnce => { - return tcx - .optimized_mir(coroutine_def_id) - .coroutine_by_move_body() - .unwrap() - .clone(); - } - }, + ty::InstanceDef::CoroutineKindShim { coroutine_def_id } => { + return tcx.optimized_mir(coroutine_def_id).coroutine_by_move_body().unwrap().clone(); + } ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end @@ -123,21 +98,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() { coroutine_body.coroutine_drop().unwrap() } else { - match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() { - ty::ClosureKind::Fn => { - unreachable!() - } - ty::ClosureKind::FnMut => coroutine_body - .coroutine_by_mut_body() - .unwrap() - .coroutine_drop() - .unwrap(), - ty::ClosureKind::FnOnce => coroutine_body - .coroutine_by_move_body() - .unwrap() - .coroutine_drop() - .unwrap(), - } + assert_eq!( + args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), + ty::ClosureKind::FnOnce + ); + coroutine_body.coroutine_by_move_body().unwrap().coroutine_drop().unwrap() }; let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); @@ -1053,12 +1018,26 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t fn build_construct_coroutine_by_move_shim<'tcx>( tcx: TyCtxt<'tcx>, coroutine_closure_def_id: DefId, + receiver_by_ref: bool, ) -> Body<'tcx> { - let self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); + let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); let ty::CoroutineClosure(_, args) = *self_ty.kind() else { bug!(); }; + // We use `*mut Self` here because we only need to emit an ABI-compatible shim body, + // rather than match the signature exactly. + // + // The self type here is a coroutine-closure, not a coroutine, and we never read from + // it because it never has any captures, because this is only true in the Fn/FnMut + // implementation, not the AsyncFn/AsyncFnMut implementation, which is implemented only + // if the coroutine-closure has no captures. + if receiver_by_ref { + // Triple-check that there's no captures here. + assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit); + self_ty = Ty::new_mut_ptr(tcx, self_ty); + } + let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { tcx.mk_fn_sig( [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()), @@ -1114,49 +1093,19 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnOnce, + receiver_by_ref, }); let body = new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span); - dump_mir(tcx, false, "coroutine_closure_by_move", &0, &body, |_, _| Ok(())); - - body -} - -fn build_construct_coroutine_by_mut_shim<'tcx>( - tcx: TyCtxt<'tcx>, - coroutine_closure_def_id: DefId, -) -> Body<'tcx> { - let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone(); - let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); - let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else { - bug!(); - }; - let args = args.as_coroutine_closure(); - - body.local_decls[RETURN_PLACE].ty = - tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| { - sig.to_coroutine_given_kind_and_upvars( - tcx, - args.parent_args(), - tcx.coroutine_for_closure(coroutine_closure_def_id), - ty::ClosureKind::FnMut, - tcx.lifetimes.re_erased, - args.tupled_upvars_ty(), - args.coroutine_captures_by_ref_ty(), - ) - })); - body.local_decls[CAPTURE_STRUCT_LOCAL].ty = - Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty); - - body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnMut, - }); - - body.pass_count = 0; - dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(())); + dump_mir( + tcx, + false, + if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }, + &0, + &body, + |_, _| Ok(()), + ); body } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2b89d17a937..0f4b2463c58 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1117,11 +1117,6 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> return false; } - if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) { - // These are implemented by backends directly and have no meaningful body. - return false; - } - if def_id.is_local() { // Local items cannot be referred to locally without monomorphizing them locally. return true; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index eb9a10f4bda..d08c50b5b06 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -380,12 +380,12 @@ impl<'a> Parser<'a> { }; if let Some(item) = nt_meta { - return match item.meta(item.path.span) { + match item.meta(item.path.span) { Some(meta) => { self.bump(); - Ok(meta) + return Ok(meta); } - None => self.unexpected(), + None => self.unexpected()?, }; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e27a5f93799..136145dd182 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -943,7 +943,10 @@ impl<'a> Parser<'a> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure - let res = self.parse_expr_dot_or_call_with_(e0, lo); + let res = ensure_sufficient_stack( + // this expr demonstrates the recursion it guards against + || self.parse_expr_dot_or_call_with_(e0, lo), + ); if attrs.is_empty() { res } else { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 263b2a90643..fde16ac957d 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -481,7 +481,7 @@ impl<'a> Parser<'a> { })) } else { self.maybe_recover_bounds_doubled_colon(&ty)?; - self.unexpected() + self.unexpected_any() } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 79492fe62ed..18d210eacfa 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1514,7 +1514,7 @@ impl<'a> Parser<'a> { let ident = this.parse_field_ident("enum", vlo)?; if this.token == token::Not { - if let Err(err) = this.unexpected::<()>() { + if let Err(err) = this.unexpected() { err.with_note(fluent::parse_macro_expands_to_enum_variant).emit(); } @@ -1937,7 +1937,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; if self.token.kind == token::Not { - if let Err(mut err) = self.unexpected::<FieldDef>() { + if let Err(mut err) = self.unexpected() { // Encounter the macro invocation err.subdiagnostic(self.dcx(), MacroExpandsToAdtField { adt_ty }); return Err(err); @@ -2067,7 +2067,7 @@ impl<'a> Parser<'a> { let params = self.parse_token_tree(); // `MacParams` let pspan = params.span(); if !self.check(&token::OpenDelim(Delimiter::Brace)) { - return self.unexpected(); + self.unexpected()?; } let body = self.parse_token_tree(); // `MacBody` // Convert `MacParams MacBody` into `{ MacParams => MacBody }`. @@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> { let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); P(DelimArgs { dspan, delim: Delimiter::Brace, tokens }) } else { - return self.unexpected(); + self.unexpected_any()? }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); @@ -2692,7 +2692,7 @@ impl<'a> Parser<'a> { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let (pat, colon) = this.parse_fn_param_pat_colon()?; if !colon { - let mut err = this.unexpected::<()>().unwrap_err(); + let mut err = this.unexpected().unwrap_err(); return if let Some(ident) = this.parameter_without_type(&mut err, pat, is_name_required, first_param) { @@ -2716,7 +2716,7 @@ impl<'a> Parser<'a> { { // This wasn't actually a type, but a pattern looking like a type, // so we are going to rollback and re-parse for recovery. - ty = this.unexpected(); + ty = this.unexpected_any(); } match ty { Ok(ty) => { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 12879dc429b..125e77d8ee7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -465,7 +465,9 @@ impl<'a> Parser<'a> { matches!(self.recovery, Recovery::Allowed) } - pub fn unexpected<T>(&mut self) -> PResult<'a, T> { + /// Version of [`unexpected`](Parser::unexpected) that "returns" any type in the `Ok` + /// (both those functions never return "Ok", and so can lie like that in the type). + pub fn unexpected_any<T>(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), // We can get `Ok(true)` from `recover_closing_delimiter` @@ -474,6 +476,10 @@ impl<'a> Parser<'a> { } } + pub fn unexpected(&mut self) -> PResult<'a, ()> { + self.unexpected_any() + } + /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> { if self.expected_tokens.is_empty() { @@ -1278,7 +1284,11 @@ impl<'a> Parser<'a> { } fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> { - if let Some(args) = self.parse_delim_args_inner() { Ok(P(args)) } else { self.unexpected() } + if let Some(args) = self.parse_delim_args_inner() { + Ok(P(args)) + } else { + self.unexpected_any() + } } fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 163d10d03f0..9153f2b9d06 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -660,7 +660,7 @@ impl<'a> Parser<'a> { // Add `>` to the list of expected tokens. self.check(&token::Gt); // Handle `,` to `;` substitution - let mut err = self.unexpected::<()>().unwrap_err(); + let mut err = self.unexpected().unwrap_err(); self.bump(); err.span_suggestion_verbose( self.prev_token.span.until(self.token.span), @@ -731,8 +731,6 @@ impl<'a> Parser<'a> { && matches!(args.output, ast::FnRetTy::Default(..)) { self.psess.gated_spans.gate(sym::return_type_notation, span); - } else { - self.psess.gated_spans.gate(sym::associated_type_bounds, span); } } let constraint = diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 79aab47fbe7..2bb4b09e337 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -907,25 +907,47 @@ impl<'a> Parser<'a> { let byte_pos = self.to_span_index(end); let start = InnerOffset(byte_pos.0 + 1); let field = self.argument(start); - // We can only parse `foo.bar` field access, any deeper nesting, - // or another type of expression, like method calls, are not supported + // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any + // deeper nesting, or another type of expression, like method calls, are not supported if !self.consume('}') { return; } if let ArgumentNamed(_) = arg.position { - if let ArgumentNamed(_) = field.position { - self.errors.insert( - 0, - ParseError { - description: "field access isn't supported".to_string(), - note: None, - label: "not supported".to_string(), - span: InnerSpan::new(arg.position_span.start, field.position_span.end), - secondary_label: None, - suggestion: Suggestion::UsePositional, - }, - ); - } + match field.position { + ArgumentNamed(_) => { + self.errors.insert( + 0, + ParseError { + description: "field access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + ArgumentIs(_) => { + self.errors.insert( + 0, + ParseError { + description: "tuple index access isn't supported".to_string(), + note: None, + label: "not supported".to_string(), + span: InnerSpan::new( + arg.position_span.start, + field.position_span.end, + ), + secondary_label: None, + suggestion: Suggestion::UsePositional, + }, + ); + } + _ => {} + }; } } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index eb2399f7a64..1254ae8cfc8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -609,13 +609,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && !self.tcx.sess.target.is_like_wasm && !self.tcx.sess.opts.actually_rustdoc { - let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else { - unreachable!(); - }; - let hir::ItemKind::Fn(sig, _, _) = item.kind else { - // target is `Fn` - unreachable!(); - }; + let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); self.dcx().emit_err(errors::LangItemWithTargetFeature { attr_span: attr.span, diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 30a65d69c4e..8080216a252 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -155,16 +155,11 @@ impl<'tcx> CheckConstVisitor<'tcx> { // // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This // is a pretty narrow case, however. - if tcx.sess.is_nightly_build() { - for gate in missing_secondary { - // FIXME: make this translatable - #[allow(rustc::diagnostic_outside_of_impl)] - #[allow(rustc::untranslatable_diagnostic)] - err.help(format!( - "add `#![feature({gate})]` to the crate attributes to enable" - )); - } - } + tcx.disabled_nightly_features( + &mut err, + def_id.map(|id| tcx.local_def_id_to_hir_id(id)), + missing_secondary.into_iter().map(|gate| (String::new(), *gate)), + ); err.emit(); } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 2af5a54a0ca..f34e8d96f05 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -7,7 +7,6 @@ use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{sigpipe, CrateType, EntryFnType}; -use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -133,16 +132,6 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, return None; } - if main_def.is_import && !tcx.features().imported_main { - let span = main_def.span; - feature_err( - &tcx.sess, - sym::imported_main, - span, - "using an imported function as entry point `main` is experimental", - ) - .emit(); - } return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) })); } no_main_err(tcx, visitor); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 6eb03bc0f5f..b7135de08ba 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -247,7 +247,7 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Field(_) | Node::Ty(_) | Node::Crate(_) - | Node::AssocOpaqueTy(..) => {} + | Node::Synthetic => {} _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index bbb89576ef7..5b58d7f43b2 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -678,15 +678,19 @@ pub enum Constructor<Cx: PatCx> { Or, /// Wildcard pattern. Wildcard, + /// Never pattern. Only used in `WitnessPat`. An actual never pattern should be lowered as + /// `Wildcard`. + Never, /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used - /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. + /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. Only + /// used in `WitnessPat`. NonExhaustive, - /// Fake extra constructor for variants that should not be mentioned in diagnostics. - /// We use this for variants behind an unstable gate as well as - /// `#[doc(hidden)]` ones. + /// Fake extra constructor for variants that should not be mentioned in diagnostics. We use this + /// for variants behind an unstable gate as well as `#[doc(hidden)]` ones. Only used in + /// `WitnessPat`. Hidden, /// Fake extra constructor for constructors that are not seen in the matrix, as explained at the - /// top of the file. + /// top of the file. Only used for specialization. Missing, /// Fake extra constructor that indicates and empty field that is private. When we encounter one /// we skip the column entirely so we don't observe its emptiness. Only used for specialization. @@ -708,6 +712,7 @@ impl<Cx: PatCx> Clone for Constructor<Cx> { Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, + Constructor::Never => Constructor::Never, Constructor::Wildcard => Constructor::Wildcard, Constructor::NonExhaustive => Constructor::NonExhaustive, Constructor::Hidden => Constructor::Hidden, @@ -1040,10 +1045,32 @@ impl<Cx: PatCx> ConstructorSet<Cx> { // In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore // add a dummy empty constructor here, which will be ignored if the place is // `ValidOnly`. - missing_empty.push(NonExhaustive); + missing_empty.push(Never); } } SplitConstructorSet { present, missing, missing_empty } } + + /// Whether this set only contains empty constructors. + pub(crate) fn all_empty(&self) -> bool { + match self { + ConstructorSet::Bool + | ConstructorSet::Integers { .. } + | ConstructorSet::Ref + | ConstructorSet::Union + | ConstructorSet::Unlistable => false, + ConstructorSet::NoConstructors => true, + ConstructorSet::Struct { empty } => *empty, + ConstructorSet::Variants { variants, non_exhaustive } => { + !*non_exhaustive + && variants + .iter() + .all(|visibility| matches!(visibility, VariantVisibility::Empty)) + } + ConstructorSet::Slice { array_len, subtype_is_empty } => { + *subtype_is_empty && matches!(array_len, Some(1..)) + } + } + } } diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index e3667d44bc9..e7eed673c94 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -208,6 +208,7 @@ impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> { } Ok(()) } + Never => write!(f, "!"), Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => { write!(f, "_ : {:?}", pat.ty()) } @@ -311,18 +312,24 @@ impl<Cx: PatCx> WitnessPat<Cx> { pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self { Self { ctor, fields, ty } } - pub(crate) fn wildcard(ty: Cx::Ty) -> Self { - Self::new(Wildcard, Vec::new(), ty) + /// Create a wildcard pattern for this type. If the type is empty, we create a `!` pattern. + pub(crate) fn wildcard(cx: &Cx, ty: Cx::Ty) -> Self { + let is_empty = cx.ctors_for_ty(&ty).is_ok_and(|ctors| ctors.all_empty()); + let ctor = if is_empty { Never } else { Wildcard }; + Self::new(ctor, Vec::new(), ty) } /// Construct a pattern that matches everything that starts with this constructor. /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern /// `Some(_)`. pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self { + if matches!(ctor, Wildcard) { + return Self::wildcard(cx, ty); + } let fields = cx .ctor_sub_tys(&ctor, &ty) .filter(|(_, PrivateUninhabitedField(skip))| !skip) - .map(|(ty, _)| Self::wildcard(ty)) + .map(|(ty, _)| Self::wildcard(cx, ty)) .collect(); Self::new(ctor, fields, ty) } @@ -334,6 +341,14 @@ impl<Cx: PatCx> WitnessPat<Cx> { &self.ty } + pub fn is_never_pattern(&self) -> bool { + match self.ctor() { + Never => true, + Or => self.fields.iter().all(|p| p.is_never_pattern()), + _ => self.fields.iter().any(|p| p.is_never_pattern()), + } + } + pub fn iter_fields(&self) -> impl Iterator<Item = &WitnessPat<Cx>> { self.fields.iter() } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index fd51fbedeef..eedc00a5613 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -247,7 +247,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], + | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], Or => { bug!("called `Fields::wildcards` on an `Or` ctor") } @@ -275,7 +275,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Ref => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0, + | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -824,7 +824,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } } &Str(value) => PatKind::Constant { value }, - Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, + Never if self.tcx.features().never_patterns => PatKind::Never, + Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Missing { .. } => bug!( "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 837c069b599..b2b339d2521 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -22,7 +22,7 @@ use rustc_errors::{ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; @@ -44,9 +44,7 @@ type Res = def::Res<NodeId>; type IdentMap<T> = FxHashMap<Ident, T>; -use diagnostics::{ - ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind, -}; +use diagnostics::{ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime}; #[derive(Copy, Clone, Debug)] struct BindingInfo { @@ -1637,22 +1635,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - let missing_lifetime = MissingLifetime { - id: lifetime.id, - span: lifetime.ident.span, - kind: if elided { - MissingLifetimeKind::Ampersand - } else { - MissingLifetimeKind::Underscore - }, - count: 1, - }; + let kind = + if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore }; + let missing_lifetime = + MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 }; let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() { debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - let res = self.create_fresh_lifetime(lifetime.ident, binder); + let res = self.create_fresh_lifetime(lifetime.ident, binder, kind); self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } @@ -1744,13 +1736,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn create_fresh_lifetime(&mut self, ident: Ident, binder: NodeId) -> LifetimeRes { + fn create_fresh_lifetime( + &mut self, + ident: Ident, + binder: NodeId, + kind: MissingLifetimeKind, + ) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); // Leave the responsibility to create the `LocalDefId` to lowering. let param = self.r.next_node_id(); - let res = LifetimeRes::Fresh { param, binder }; + let res = LifetimeRes::Fresh { param, binder, kind }; self.record_lifetime_param(param, res); // Record the created lifetime parameter so lowering can pick it up and add it to HIR. @@ -1844,14 +1841,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }; let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span); + let kind = if segment.has_generic_args { + MissingLifetimeKind::Comma + } else { + MissingLifetimeKind::Brackets + }; let missing_lifetime = MissingLifetime { id: node_ids.start, span: elided_lifetime_span, - kind: if segment.has_generic_args { - MissingLifetimeKind::Comma - } else { - MissingLifetimeKind::Brackets - }, + kind, count: expected_lifetimes, }; let mut should_lint = true; @@ -1897,7 +1895,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Group all suggestions into the first record. let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for id in node_ids { - let res = self.create_fresh_lifetime(ident, binder); + let res = self.create_fresh_lifetime(ident, binder, kind); self.record_lifetime_res( id, res, @@ -4665,7 +4663,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } fn lint_unused_qualifications(&mut self, path: &[Segment], ns: Namespace, finalize: Finalize) { - if path.iter().any(|seg| seg.ident.span.from_expansion()) { + // Don't lint on global paths because the user explicitly wrote out the full path. + if let Some(seg) = path.first() + && seg.ident.name == kw::PathRoot + { + return; + } + + if finalize.path_span.from_expansion() + || path.iter().any(|seg| seg.ident.span.from_expansion()) + { return; } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 47f8cc56139..1b8f2fc005c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; -use rustc_hir::PrimTy; +use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_session::lint; use rustc_session::Session; use rustc_span::edit_distance::find_best_match_for_name; @@ -109,18 +109,6 @@ pub(super) struct MissingLifetime { pub count: usize, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub(super) enum MissingLifetimeKind { - /// An explicit `'_`. - Underscore, - /// An elided lifetime `&' ty`. - Ampersand, - /// An elided lifetime in brackets with written brackets. - Comma, - /// An elided lifetime with elided brackets. - Brackets, -} - /// Description of the lifetimes appearing in a function parameter. /// This is used to provide a literal explanation to the elision failure. #[derive(Clone, Debug)] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index bb822c611a1..b67b7d79d97 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -8,7 +8,7 @@ #![doc(rust_logo)] #![allow(internal_features)] #![feature(rustdoc_internals)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(const_option)] #![feature(core_intrinsics)] #![feature(generic_nonzero)] diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 42c681e4961..179fd79bef7 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -24,6 +24,9 @@ session_feature_diagnostic_for_issue = session_feature_diagnostic_help = add `#![feature({$feature})]` to the crate attributes to enable +session_feature_diagnostic_suggestion = + add `#![feature({$feature})]` to the crate attributes to enable + session_feature_suggest_upgrade_compiler = this compiler was built on {$date}; consider upgrading it if it is out of date diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e56684808bb..e6eb1a3e83c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -313,7 +313,7 @@ pub struct LocationDetail { } impl LocationDetail { - pub fn all() -> Self { + pub(crate) fn all() -> Self { Self { file: true, line: true, column: true } } } @@ -549,7 +549,7 @@ impl OutputTypes { OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone())))) } - pub fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> { + pub(crate) fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> { self.0.get(key) } @@ -662,10 +662,6 @@ impl Externs { pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> { self.0.iter() } - - pub fn len(&self) -> usize { - self.0.len() - } } impl ExternEntry { @@ -854,13 +850,13 @@ impl OutFileName { #[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)] pub struct OutputFilenames { - pub out_directory: PathBuf, + pub(crate) out_directory: PathBuf, /// Crate name. Never contains '-'. crate_stem: String, /// Typically based on `.rs` input file name. Any '-' is preserved. filestem: String, pub single_output_file: Option<OutFileName>, - pub temps_directory: Option<PathBuf>, + temps_directory: Option<PathBuf>, pub outputs: OutputTypes, } @@ -898,7 +894,7 @@ impl OutputFilenames { /// Gets the output path where a compilation artifact of the given type /// should be placed on disk. - pub fn output_path(&self, flavor: OutputType) -> PathBuf { + fn output_path(&self, flavor: OutputType) -> PathBuf { let extension = flavor.extension(); match flavor { OutputType::Metadata => { @@ -1092,7 +1088,7 @@ impl Options { || self.unstable_opts.query_dep_graph } - pub fn file_path_mapping(&self) -> FilePathMapping { + pub(crate) fn file_path_mapping(&self) -> FilePathMapping { file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts) } @@ -1173,14 +1169,14 @@ pub enum Passes { } impl Passes { - pub fn is_empty(&self) -> bool { + fn is_empty(&self) -> bool { match *self { Passes::Some(ref v) => v.is_empty(), Passes::All => false, } } - pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) { + pub(crate) fn extend(&mut self, passes: impl IntoIterator<Item = String>) { match *self { Passes::Some(ref mut v) => v.extend(passes), Passes::All => {} @@ -1206,7 +1202,7 @@ pub struct BranchProtection { pub pac_ret: Option<PacRet>, } -pub const fn default_lib_output() -> CrateType { +pub(crate) const fn default_lib_output() -> CrateType { CrateType::Rlib } @@ -1584,15 +1580,15 @@ pub fn build_target_config( } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum OptionStability { +enum OptionStability { Stable, Unstable, } pub struct RustcOptGroup { pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>, - pub name: &'static str, - pub stability: OptionStability, + name: &'static str, + stability: OptionStability, } impl RustcOptGroup { @@ -1628,8 +1624,8 @@ mod opt { use super::RustcOptGroup; - pub type R = RustcOptGroup; - pub type S = &'static str; + type R = RustcOptGroup; + type S = &'static str; fn stable<F>(name: S, f: F) -> R where @@ -1649,32 +1645,34 @@ mod opt { if a.len() > b.len() { a } else { b } } - pub fn opt_s(a: S, b: S, c: S, d: S) -> R { + pub(crate) fn opt_s(a: S, b: S, c: S, d: S) -> R { stable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) } - pub fn multi_s(a: S, b: S, c: S, d: S) -> R { + pub(crate) fn multi_s(a: S, b: S, c: S, d: S) -> R { stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) } - pub fn flag_s(a: S, b: S, c: S) -> R { + pub(crate) fn flag_s(a: S, b: S, c: S) -> R { stable(longer(a, b), move |opts| opts.optflag(a, b, c)) } - pub fn flagmulti_s(a: S, b: S, c: S) -> R { + pub(crate) fn flagmulti_s(a: S, b: S, c: S) -> R { stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) } - pub fn opt(a: S, b: S, c: S, d: S) -> R { + fn opt(a: S, b: S, c: S, d: S) -> R { unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) } - pub fn multi(a: S, b: S, c: S, d: S) -> R { + pub(crate) fn multi(a: S, b: S, c: S, d: S) -> R { unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) } } + static EDITION_STRING: LazyLock<String> = LazyLock::new(|| { format!( "Specify which edition of the compiler to use when compiling code. \ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}." ) }); + /// Returns the "short" subset of the rustc command line options, /// including metadata for each option, such as whether the option is /// part of the stable long-term interface for rustc. @@ -1864,9 +1862,9 @@ pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Col /// Possible json config files pub struct JsonConfig { pub json_rendered: HumanReadableErrorType, - pub json_artifact_notifications: bool, + json_artifact_notifications: bool, pub json_unused_externs: JsonUnusedExterns, - pub json_future_incompat: bool, + json_future_incompat: bool, } /// Report unused externs in event stream @@ -2992,7 +2990,7 @@ pub mod nightly_options { is_nightly_build(matches.opt_str("crate-name").as_deref()) } - pub fn is_nightly_build(krate: Option<&str>) -> bool { + fn is_nightly_build(krate: Option<&str>) -> bool { UnstableFeatures::from_environment(krate).is_nightly_build() } @@ -3199,7 +3197,7 @@ pub(crate) mod dep_tracking { use std::num::NonZero; use std::path::PathBuf; - pub trait DepTrackingHash { + pub(crate) trait DepTrackingHash { fn hash( &self, hasher: &mut DefaultHasher, diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index d523da1ad7e..0a855f87586 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -12,9 +12,9 @@ use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; use crate::{config::CrateType, parse::ParseSess}; -pub struct FeatureGateError { - pub span: MultiSpan, - pub explain: DiagMessage, +pub(crate) struct FeatureGateError { + pub(crate) span: MultiSpan, + pub(crate) explain: DiagMessage, } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { @@ -26,22 +26,22 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { #[derive(Subdiagnostic)] #[note(session_feature_diagnostic_for_issue)] -pub struct FeatureDiagnosticForIssue { - pub n: NonZero<u32>, +pub(crate) struct FeatureDiagnosticForIssue { + pub(crate) n: NonZero<u32>, } #[derive(Subdiagnostic)] #[note(session_feature_suggest_upgrade_compiler)] -pub struct SuggestUpgradeCompiler { +pub(crate) struct SuggestUpgradeCompiler { date: &'static str, } impl SuggestUpgradeCompiler { - pub fn ui_testing() -> Self { + pub(crate) fn ui_testing() -> Self { Self { date: "YYYY-MM-DD" } } - pub fn new() -> Option<Self> { + pub(crate) fn new() -> Option<Self> { let date = option_env!("CFG_VER_DATE")?; Some(Self { date }) @@ -50,108 +50,120 @@ impl SuggestUpgradeCompiler { #[derive(Subdiagnostic)] #[help(session_feature_diagnostic_help)] -pub struct FeatureDiagnosticHelp { +pub(crate) struct FeatureDiagnosticHelp { + pub(crate) feature: Symbol, +} + +#[derive(Subdiagnostic)] +#[suggestion( + session_feature_diagnostic_suggestion, + applicability = "maybe-incorrect", + code = "#![feature({feature})]\n" +)] +pub struct FeatureDiagnosticSuggestion { pub feature: Symbol, + #[primary_span] + pub span: Span, } #[derive(Subdiagnostic)] #[help(session_cli_feature_diagnostic_help)] -pub struct CliFeatureDiagnosticHelp { - pub feature: Symbol, +pub(crate) struct CliFeatureDiagnosticHelp { + pub(crate) feature: Symbol, } #[derive(Diagnostic)] #[diag(session_not_circumvent_feature)] -pub struct NotCircumventFeature; +pub(crate) struct NotCircumventFeature; #[derive(Diagnostic)] #[diag(session_linker_plugin_lto_windows_not_supported)] -pub struct LinkerPluginToWindowsNotSupported; +pub(crate) struct LinkerPluginToWindowsNotSupported; #[derive(Diagnostic)] #[diag(session_profile_use_file_does_not_exist)] -pub struct ProfileUseFileDoesNotExist<'a> { - pub path: &'a std::path::Path, +pub(crate) struct ProfileUseFileDoesNotExist<'a> { + pub(crate) path: &'a std::path::Path, } #[derive(Diagnostic)] #[diag(session_profile_sample_use_file_does_not_exist)] -pub struct ProfileSampleUseFileDoesNotExist<'a> { - pub path: &'a std::path::Path, +pub(crate) struct ProfileSampleUseFileDoesNotExist<'a> { + pub(crate) path: &'a std::path::Path, } #[derive(Diagnostic)] #[diag(session_target_requires_unwind_tables)] -pub struct TargetRequiresUnwindTables; +pub(crate) struct TargetRequiresUnwindTables; #[derive(Diagnostic)] #[diag(session_instrumentation_not_supported)] -pub struct InstrumentationNotSupported { - pub us: String, +pub(crate) struct InstrumentationNotSupported { + pub(crate) us: String, } #[derive(Diagnostic)] #[diag(session_sanitizer_not_supported)] -pub struct SanitizerNotSupported { - pub us: String, +pub(crate) struct SanitizerNotSupported { + pub(crate) us: String, } #[derive(Diagnostic)] #[diag(session_sanitizers_not_supported)] -pub struct SanitizersNotSupported { - pub us: String, +pub(crate) struct SanitizersNotSupported { + pub(crate) us: String, } #[derive(Diagnostic)] #[diag(session_cannot_mix_and_match_sanitizers)] -pub struct CannotMixAndMatchSanitizers { - pub first: String, - pub second: String, +pub(crate) struct CannotMixAndMatchSanitizers { + pub(crate) first: String, + pub(crate) second: String, } #[derive(Diagnostic)] #[diag(session_cannot_enable_crt_static_linux)] -pub struct CannotEnableCrtStaticLinux; +pub(crate) struct CannotEnableCrtStaticLinux; #[derive(Diagnostic)] #[diag(session_sanitizer_cfi_requires_lto)] -pub struct SanitizerCfiRequiresLto; +pub(crate) struct SanitizerCfiRequiresLto; #[derive(Diagnostic)] #[diag(session_sanitizer_cfi_requires_single_codegen_unit)] -pub struct SanitizerCfiRequiresSingleCodegenUnit; +pub(crate) struct SanitizerCfiRequiresSingleCodegenUnit; #[derive(Diagnostic)] #[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)] -pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi; +pub(crate) struct SanitizerCfiCanonicalJumpTablesRequiresCfi; #[derive(Diagnostic)] #[diag(session_sanitizer_cfi_generalize_pointers_requires_cfi)] -pub struct SanitizerCfiGeneralizePointersRequiresCfi; +pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi; #[derive(Diagnostic)] #[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)] -pub struct SanitizerCfiNormalizeIntegersRequiresCfi; +pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi; #[derive(Diagnostic)] #[diag(session_split_lto_unit_requires_lto)] -pub struct SplitLtoUnitRequiresLto; +pub(crate) struct SplitLtoUnitRequiresLto; #[derive(Diagnostic)] #[diag(session_unstable_virtual_function_elimination)] -pub struct UnstableVirtualFunctionElimination; +pub(crate) struct UnstableVirtualFunctionElimination; #[derive(Diagnostic)] #[diag(session_unsupported_dwarf_version)] -pub struct UnsupportedDwarfVersion { - pub dwarf_version: u32, +pub(crate) struct UnsupportedDwarfVersion { + pub(crate) dwarf_version: u32, } #[derive(Diagnostic)] #[diag(session_target_stack_protector_not_supported)] -pub struct StackProtectorNotSupportedForTarget<'a> { - pub stack_protector: StackProtector, - pub target_triple: &'a TargetTriple, +pub(crate) struct StackProtectorNotSupportedForTarget<'a> { + pub(crate) stack_protector: StackProtector, + pub(crate) target_triple: &'a TargetTriple, } #[derive(Diagnostic)] @@ -160,58 +172,58 @@ pub(crate) struct BranchProtectionRequiresAArch64; #[derive(Diagnostic)] #[diag(session_split_debuginfo_unstable_platform)] -pub struct SplitDebugInfoUnstablePlatform { - pub debuginfo: SplitDebuginfo, +pub(crate) struct SplitDebugInfoUnstablePlatform { + pub(crate) debuginfo: SplitDebuginfo, } #[derive(Diagnostic)] #[diag(session_file_is_not_writeable)] -pub struct FileIsNotWriteable<'a> { - pub file: &'a std::path::Path, +pub(crate) struct FileIsNotWriteable<'a> { + pub(crate) file: &'a std::path::Path, } #[derive(Diagnostic)] #[diag(session_file_write_fail)] pub(crate) struct FileWriteFail<'a> { - pub path: &'a std::path::Path, - pub err: String, + pub(crate) path: &'a std::path::Path, + pub(crate) err: String, } #[derive(Diagnostic)] #[diag(session_crate_name_does_not_match)] -pub struct CrateNameDoesNotMatch { +pub(crate) struct CrateNameDoesNotMatch { #[primary_span] - pub span: Span, - pub s: Symbol, - pub name: Symbol, + pub(crate) span: Span, + pub(crate) s: Symbol, + pub(crate) name: Symbol, } #[derive(Diagnostic)] #[diag(session_crate_name_invalid)] -pub struct CrateNameInvalid<'a> { - pub s: &'a str, +pub(crate) struct CrateNameInvalid<'a> { + pub(crate) s: &'a str, } #[derive(Diagnostic)] #[diag(session_crate_name_empty)] -pub struct CrateNameEmpty { +pub(crate) struct CrateNameEmpty { #[primary_span] - pub span: Option<Span>, + pub(crate) span: Option<Span>, } #[derive(Diagnostic)] #[diag(session_invalid_character_in_create_name)] -pub struct InvalidCharacterInCrateName { +pub(crate) struct InvalidCharacterInCrateName { #[primary_span] - pub span: Option<Span>, - pub character: char, - pub crate_name: Symbol, + pub(crate) span: Option<Span>, + pub(crate) character: char, + pub(crate) crate_name: Symbol, #[subdiagnostic] - pub crate_name_help: Option<InvalidCrateNameHelp>, + pub(crate) crate_name_help: Option<InvalidCrateNameHelp>, } #[derive(Subdiagnostic)] -pub enum InvalidCrateNameHelp { +pub(crate) enum InvalidCrateNameHelp { #[help(session_invalid_character_in_create_name_help)] AddCrateName, } @@ -220,9 +232,9 @@ pub enum InvalidCrateNameHelp { #[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")] pub struct ExprParenthesesNeeded { #[suggestion_part(code = "(")] - pub left: Span, + left: Span, #[suggestion_part(code = ")")] - pub right: Span, + right: Span, } impl ExprParenthesesNeeded { @@ -233,13 +245,13 @@ impl ExprParenthesesNeeded { #[derive(Diagnostic)] #[diag(session_skipping_const_checks)] -pub struct SkippingConstChecks { +pub(crate) struct SkippingConstChecks { #[subdiagnostic] - pub unleashed_features: Vec<UnleashedFeatureHelp>, + pub(crate) unleashed_features: Vec<UnleashedFeatureHelp>, } #[derive(Subdiagnostic)] -pub enum UnleashedFeatureHelp { +pub(crate) enum UnleashedFeatureHelp { #[help(session_unleashed_feature_help_named)] Named { #[primary_span] @@ -255,101 +267,101 @@ pub enum UnleashedFeatureHelp { #[derive(Diagnostic)] #[diag(session_invalid_literal_suffix)] -pub(crate) struct InvalidLiteralSuffix<'a> { +struct InvalidLiteralSuffix<'a> { #[primary_span] #[label] - pub span: Span, + span: Span, // FIXME(#100717) - pub kind: &'a str, - pub suffix: Symbol, + kind: &'a str, + suffix: Symbol, } #[derive(Diagnostic)] #[diag(session_invalid_int_literal_width)] #[help] -pub(crate) struct InvalidIntLiteralWidth { +struct InvalidIntLiteralWidth { #[primary_span] - pub span: Span, - pub width: String, + span: Span, + width: String, } #[derive(Diagnostic)] #[diag(session_invalid_num_literal_base_prefix)] #[note] -pub(crate) struct InvalidNumLiteralBasePrefix { +struct InvalidNumLiteralBasePrefix { #[primary_span] #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")] - pub span: Span, - pub fixed: String, + span: Span, + fixed: String, } #[derive(Diagnostic)] #[diag(session_invalid_num_literal_suffix)] #[help] -pub(crate) struct InvalidNumLiteralSuffix { +struct InvalidNumLiteralSuffix { #[primary_span] #[label] - pub span: Span, - pub suffix: String, + span: Span, + suffix: String, } #[derive(Diagnostic)] #[diag(session_invalid_float_literal_width)] #[help] -pub(crate) struct InvalidFloatLiteralWidth { +struct InvalidFloatLiteralWidth { #[primary_span] - pub span: Span, - pub width: String, + span: Span, + width: String, } #[derive(Diagnostic)] #[diag(session_invalid_float_literal_suffix)] #[help] -pub(crate) struct InvalidFloatLiteralSuffix { +struct InvalidFloatLiteralSuffix { #[primary_span] #[label] - pub span: Span, - pub suffix: String, + span: Span, + suffix: String, } #[derive(Diagnostic)] #[diag(session_int_literal_too_large)] #[note] -pub(crate) struct IntLiteralTooLarge { +struct IntLiteralTooLarge { #[primary_span] - pub span: Span, - pub limit: String, + span: Span, + limit: String, } #[derive(Diagnostic)] #[diag(session_hexadecimal_float_literal_not_supported)] -pub(crate) struct HexadecimalFloatLiteralNotSupported { +struct HexadecimalFloatLiteralNotSupported { #[primary_span] #[label(session_not_supported)] - pub span: Span, + span: Span, } #[derive(Diagnostic)] #[diag(session_octal_float_literal_not_supported)] -pub(crate) struct OctalFloatLiteralNotSupported { +struct OctalFloatLiteralNotSupported { #[primary_span] #[label(session_not_supported)] - pub span: Span, + span: Span, } #[derive(Diagnostic)] #[diag(session_binary_float_literal_not_supported)] -pub(crate) struct BinaryFloatLiteralNotSupported { +struct BinaryFloatLiteralNotSupported { #[primary_span] #[label(session_not_supported)] - pub span: Span, + span: Span, } #[derive(Diagnostic)] #[diag(session_unsupported_crate_type_for_target)] -pub struct UnsupportedCrateTypeForTarget<'a> { - pub crate_type: CrateType, - pub target_triple: &'a TargetTriple, +pub(crate) struct UnsupportedCrateTypeForTarget<'a> { + pub(crate) crate_type: CrateType, + pub(crate) target_triple: &'a TargetTriple, } pub fn report_lit_error( @@ -431,16 +443,16 @@ pub fn report_lit_error( #[derive(Diagnostic)] #[diag(session_optimization_fuel_exhausted)] -pub struct OptimisationFuelExhausted { - pub msg: String, +pub(crate) struct OptimisationFuelExhausted { + pub(crate) msg: String, } #[derive(Diagnostic)] #[diag(session_incompatible_linker_flavor)] #[note] -pub struct IncompatibleLinkerFlavor { - pub flavor: &'static str, - pub compatible_list: String, +pub(crate) struct IncompatibleLinkerFlavor { + pub(crate) flavor: &'static str, + pub(crate) compatible_list: String, } #[derive(Diagnostic)] @@ -453,6 +465,6 @@ pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; #[derive(Diagnostic)] #[diag(session_failed_to_create_profiler)] -pub struct FailedToCreateProfiler { - pub err: String, +pub(crate) struct FailedToCreateProfiler { + pub(crate) err: String, } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 398138d7e1f..5434bbe0b98 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -3,8 +3,8 @@ use crate::config::{Cfg, CheckCfg}; use crate::errors::{ - CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError, - SuggestUpgradeCompiler, + CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, + FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler, }; use crate::lint::{ builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiag, Lint, LintId, @@ -112,7 +112,7 @@ pub fn feature_err_issue( } let mut err = sess.psess.dcx.create_err(FeatureGateError { span, explain: explain.into() }); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); err } @@ -141,7 +141,7 @@ pub fn feature_warn_issue( explain: &'static str, ) { let mut err = sess.psess.dcx.struct_span_warn(span, explain); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; @@ -160,7 +160,7 @@ pub fn add_feature_diagnostics<G: EmissionGuarantee>( sess: &Session, feature: Symbol, ) { - add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false); + add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); } /// Adds the diagnostics for a feature to an existing error. @@ -175,6 +175,7 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( feature: Symbol, issue: GateIssue, feature_from_cli: bool, + inject_span: Option<Span>, ) { if let Some(n) = find_feature_issue(feature, issue) { err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n }); @@ -184,6 +185,8 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( if sess.psess.unstable_features.is_nightly_build() { if feature_from_cli { err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature }); + } else if let Some(span) = inject_span { + err.subdiagnostic(sess.dcx(), FeatureDiagnosticSuggestion { feature, span }); } else { err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature }); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 63b950a2803..8b911a41a11 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -166,9 +166,8 @@ symbols! { Break, C, CStr, - CallFuture, - CallMutFuture, CallOnceFuture, + CallRefFuture, Capture, Center, Cleanup, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 83e920e2f8e..1c62ce2d214 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -76,16 +76,10 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } - | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => { - printer.write_str("{{fn-mut-shim}}").unwrap(); - } - ty::ClosureKind::FnOnce => { - printer.write_str("{{fn-once-shim}}").unwrap(); - } - }, + ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } => { + printer.write_str("{{fn-once-shim}}").unwrap(); + } _ => {} } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f1b1b4ed2bb..6bc375512ac 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -46,12 +46,8 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), - ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } - | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => Some("fn_mut"), - ty::ClosureKind::FnOnce => Some("fn_once"), - }, + ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), _ => None, }; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 8019d2b80cd..ba359ac6de1 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,13 +9,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![cfg_attr(bootstrap, feature(exhaustive_patterns))] -#![cfg_attr(not(bootstrap), feature(min_exhaustive_patterns))] +#![feature(min_exhaustive_patterns)] #![feature(rustdoc_internals)] #![feature(assert_matches)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![feature(rustc_attrs)] #![feature(step_trait)] #![allow(internal_features)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index fd3d62d1321..e14fc62cd6f 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,7 +17,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] -#![feature(associated_type_bounds)] +#![cfg_attr(bootstrap, feature(associated_type_bounds))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(control_flow_enum)] @@ -26,7 +26,6 @@ #![feature(option_take_if)] #![feature(never_type)] #![feature(type_alias_impl_trait)] -#![cfg_attr(bootstrap, feature(min_specialization))] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 67657c81cf6..e081a9100e2 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -21,8 +21,9 @@ //! However, if `?fresh_var` ends up geteting equated to another type, we retry the //! `NormalizesTo` goal, at which point the opaque is actually defined. -use super::{EvalCtxt, GoalSource}; +use super::EvalCtxt; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::GoalSource; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty::{self, Ty}; @@ -121,10 +122,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::TermKind::Const(_) => { if let Some(alias) = term.to_alias_ty(self.tcx()) { let term = self.next_term_infer_of_kind(term); - self.add_goal( - GoalSource::Misc, - Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias, term }), - ); + self.add_normalizes_to_goal(Goal::new( + self.tcx(), + param_env, + ty::NormalizesTo { alias, term }, + )); self.try_evaluate_added_goals()?; Ok(Some(self.resolve_vars_if_possible(term))) } else { @@ -145,18 +147,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return None; } - let ty::Alias(_, alias) = *ty.kind() else { + let ty::Alias(kind, alias) = *ty.kind() else { return Some(ty); }; match self.commit_if_ok(|this| { + let tcx = this.tcx(); let normalized_ty = this.next_ty_infer(); - let normalizes_to_goal = Goal::new( - this.tcx(), - param_env, - ty::NormalizesTo { alias, term: normalized_ty.into() }, - ); - this.add_goal(GoalSource::Misc, normalizes_to_goal); + let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() }; + match kind { + ty::AliasKind::Opaque => { + // HACK: Unlike for associated types, `normalizes-to` for opaques + // is currently not treated as a function. We do not erase the + // expected term. + this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to)); + } + ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => { + this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to)) + } + } this.try_evaluate_added_goals()?; Ok(this.resolve_vars_if_possible(normalized_ty)) }) { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9c7fa5216d7..9f33dce2a6d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -128,7 +128,7 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; - /// A type is `Copy` or `Clone` if its components are `Sized`. + /// A type is `Sized` if its tail component is `Sized`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 2bfb86b592b..faf8c55c475 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -154,13 +154,25 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( bug!("unexpected type `{ty}`") } - // impl Sized for (T1, T2, .., Tn) where T1: Sized, T2: Sized, .. Tn: Sized - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), - - // impl Sized for Adt where T: Sized forall T in field types + // impl Sized for () + // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1 + ty::Tuple(tys) => Ok(tys.last().map_or_else(Vec::new, |&ty| vec![ty::Binder::dummy(ty)])), + + // impl Sized for Adt<Args...> where sized_constraint(Adt)<Args...>: Sized + // `sized_constraint(Adt)` is the deepest struct trail that can be determined + // by the definition of `Adt`, independent of the generic args. + // impl Sized for Adt<Args...> if sized_constraint(Adt) == None + // As a performance optimization, `sized_constraint(Adt)` can return `None` + // if the ADTs definition implies that it is sized by for all possible args. + // In this case, the builtin impl will have no nested subgoals. This is a + // "best effort" optimization and `sized_constraint` may return `Some`, even + // if the ADT is sized for all possible args. ty::Adt(def, args) => { - let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect()) + if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))]) + } else { + Ok(vec![]) + } } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 251b0a193f1..619435d2e8d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -9,6 +9,7 @@ //! //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html use super::{CanonicalInput, Certainty, EvalCtxt, Goal}; +use crate::solve::eval_ctxt::NestedGoals; use crate::solve::{ inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response, }; @@ -19,6 +20,7 @@ use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::resolve::EagerResolver; use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::solve::NestedNormalizationGoals; use rustc_middle::infer::canonical::Canonical; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ @@ -28,6 +30,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; use rustc_span::DUMMY_SP; +use std::assert_matches::assert_matches; use std::iter; use std::ops::Deref; @@ -93,13 +96,31 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { previous call to `try_evaluate_added_goals!`" ); - let certainty = certainty.unify_with(goals_certainty); - - let var_values = self.var_values; - let external_constraints = self.compute_external_query_constraints()?; - + // When normalizing, we've replaced the expected term with an unconstrained + // inference variable. This means that we dropped information which could + // have been important. We handle this by instead returning the nested goals + // to the caller, where they are then handled. + // + // As we return all ambiguous nested goals, we can ignore the certainty returned + // by `try_evaluate_added_goals()`. + let (certainty, normalization_nested_goals) = if self.is_normalizes_to_goal { + let NestedGoals { normalizes_to_goals, goals } = std::mem::take(&mut self.nested_goals); + if cfg!(debug_assertions) { + assert!(normalizes_to_goals.is_empty()); + if goals.is_empty() { + assert_matches!(goals_certainty, Certainty::Yes); + } + } + (certainty, NestedNormalizationGoals(goals)) + } else { + let certainty = certainty.unify_with(goals_certainty); + (certainty, NestedNormalizationGoals::empty()) + }; + + let external_constraints = + self.compute_external_query_constraints(normalization_nested_goals)?; let (var_values, mut external_constraints) = - (var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); + (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints @@ -146,6 +167,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn compute_external_query_constraints( &self, + normalization_nested_goals: NestedNormalizationGoals<'tcx>, ) -> Result<ExternalConstraintsData<'tcx>, NoSolution> { // We only check for leaks from universes which were entered inside // of the query. @@ -176,7 +198,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) }); - Ok(ExternalConstraintsData { region_constraints, opaque_types }) + Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }) } /// After calling a canonical query, we apply the constraints returned @@ -185,13 +207,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// This happens in three steps: /// - we instantiate the bound variables of the query response /// - we unify the `var_values` of the response with the `original_values` - /// - we apply the `external_constraints` returned by the query + /// - we apply the `external_constraints` returned by the query, returning + /// the `normalization_nested_goals` pub(super) fn instantiate_and_apply_query_response( &mut self, param_env: ty::ParamEnv<'tcx>, original_values: Vec<ty::GenericArg<'tcx>>, response: CanonicalResponse<'tcx>, - ) -> Certainty { + ) -> (NestedNormalizationGoals<'tcx>, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -203,11 +226,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); - let ExternalConstraintsData { region_constraints, opaque_types } = - external_constraints.deref(); + let ExternalConstraintsData { + region_constraints, + opaque_types, + normalization_nested_goals, + } = external_constraints.deref(); self.register_region_constraints(region_constraints); self.register_new_opaque_types(param_env, opaque_types); - certainty + (normalization_nested_goals.clone(), certainty) } /// This returns the canoncial variable values to instantiate the bound variables of diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs index 67b6801059a..c8f9a461adf 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs @@ -11,6 +11,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { infcx: self.infcx, variables: self.variables, var_values: self.var_values, + is_normalizes_to_goal: self.is_normalizes_to_goal, predefined_opaques_in_body: self.predefined_opaques_in_body, max_input_universe: self.max_input_universe, search_graph: self.search_graph, @@ -25,6 +26,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { infcx: _, variables: _, var_values: _, + is_normalizes_to_goal: _, predefined_opaques_in_body: _, max_input_universe: _, search_graph: _, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index a4ee0e03e65..a0fe6eca0fc 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -7,14 +7,14 @@ use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::MaybeCause; +use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::solve::inspect; use rustc_middle::traits::solve::{ - CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques, - PredefinedOpaquesData, QueryResult, + CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData, + QueryResult, }; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::{ @@ -61,6 +61,14 @@ pub struct EvalCtxt<'a, 'tcx> { /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. variables: CanonicalVarInfos<'tcx>, + /// Whether we're currently computing a `NormalizesTo` goal. Unlike other goals, + /// `NormalizesTo` goals act like functions with the expected term always being + /// fully unconstrained. This would weaken inference however, as the nested goals + /// never get the inference constraints from the actual normalized-to type. Because + /// of this we return any ambiguous nested goals from `NormalizesTo` to the caller + /// when then adds these to its own context. The caller is always an `AliasRelate` + /// goal so this never leaks out of the solver. + is_normalizes_to_goal: bool, pub(super) var_values: CanonicalVarValues<'tcx>, predefined_opaques_in_body: PredefinedOpaques<'tcx>, @@ -91,9 +99,9 @@ pub struct EvalCtxt<'a, 'tcx> { pub(super) inspect: ProofTreeBuilder<'tcx>, } -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub(super) struct NestedGoals<'tcx> { - /// This normalizes-to goal that is treated specially during the evaluation + /// These normalizes-to goals are treated specially during the evaluation /// loop. In each iteration we take the RHS of the projection, replace it with /// a fresh inference variable, and only after evaluating that goal do we /// equate the fresh inference variable with the actual RHS of the predicate. @@ -101,26 +109,24 @@ pub(super) struct NestedGoals<'tcx> { /// This is both to improve caching, and to avoid using the RHS of the /// projection predicate to influence the normalizes-to candidate we select. /// - /// This is not a 'real' nested goal. We must not forget to replace the RHS - /// with a fresh inference variable when we evaluate this goal. That can result - /// in a trait solver cycle. This would currently result in overflow but can be - /// can be unsound with more powerful coinduction in the future. - pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::NormalizesTo<'tcx>>>, + /// Forgetting to replace the RHS with a fresh inference variable when we evaluate + /// this goal results in an ICE.. + pub(super) normalizes_to_goals: Vec<Goal<'tcx, ty::NormalizesTo<'tcx>>>, /// The rest of the goals which have not yet processed or remain ambiguous. pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>, } impl<'tcx> NestedGoals<'tcx> { pub(super) fn new() -> Self { - Self { normalizes_to_hack_goal: None, goals: Vec::new() } + Self { normalizes_to_goals: Vec::new(), goals: Vec::new() } } pub(super) fn is_empty(&self) -> bool { - self.normalizes_to_hack_goal.is_none() && self.goals.is_empty() + self.normalizes_to_goals.is_empty() && self.goals.is_empty() } pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) { - assert_eq!(other.normalizes_to_hack_goal, None); + self.normalizes_to_goals.extend(other.normalizes_to_goals); self.goals.extend(other.goals) } } @@ -155,6 +161,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.search_graph.solver_mode() } + pub(super) fn set_is_normalizes_to_goal(&mut self) { + self.is_normalizes_to_goal = true; + } + /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). @@ -167,8 +177,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut search_graph = search_graph::SearchGraph::new(mode); let mut ecx = EvalCtxt { - search_graph: &mut search_graph, infcx, + search_graph: &mut search_graph, nested_goals: NestedGoals::new(), inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree), @@ -180,6 +190,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { max_input_universe: ty::UniverseIndex::ROOT, variables: ty::List::empty(), var_values: CanonicalVarValues::dummy(), + is_normalizes_to_goal: false, tainted: Ok(()), }; let result = f(&mut ecx); @@ -233,6 +244,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { infcx, variables: canonical_input.variables, var_values, + is_normalizes_to_goal: false, predefined_opaques_in_body: input.predefined_opaques_in_body, max_input_universe: canonical_input.max_universe, search_graph, @@ -319,6 +331,27 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { + let (normalization_nested_goals, has_changed, certainty) = + self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; + assert!(normalization_nested_goals.is_empty()); + Ok((has_changed, certainty)) + } + + /// Recursively evaluates `goal`, returning the nested goals in case + /// the nested goal is a `NormalizesTo` goal. + /// + /// As all other goal kinds do not return any nested goals and + /// `NormalizesTo` is only used by `AliasRelate`, all other callsites + /// should use [`EvalCtxt::evaluate_goal`] which discards that empty + /// storage. + // FIXME(-Znext-solver=coinduction): `_source` is currently unused but will + // be necessary once we implement the new coinduction approach. + fn evaluate_goal_raw( + &mut self, + goal_evaluation_kind: GoalEvaluationKind, + _source: GoalSource, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> Result<(NestedNormalizationGoals<'tcx>, bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -336,12 +369,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(response) => response, }; - let (certainty, has_changed) = self.instantiate_response_discarding_overflow( - goal.param_env, - source, - orig_values, - canonical_response, - ); + let (normalization_nested_goals, certainty, has_changed) = self + .instantiate_response_discarding_overflow( + goal.param_env, + orig_values, + canonical_response, + ); self.inspect.goal_evaluation(goal_evaluation); // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -353,47 +386,25 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Once we have decided on how to handle trait-system-refactor-initiative#75, // we should re-add an assert here. - Ok((has_changed, certainty)) + Ok((normalization_nested_goals, has_changed, certainty)) } fn instantiate_response_discarding_overflow( &mut self, param_env: ty::ParamEnv<'tcx>, - source: GoalSource, original_values: Vec<ty::GenericArg<'tcx>>, response: CanonicalResponse<'tcx>, - ) -> (Certainty, bool) { - // The old solver did not evaluate nested goals when normalizing. - // It returned the selection constraints allowing a `Projection` - // obligation to not hold in coherence while avoiding the fatal error - // from overflow. - // - // We match this behavior here by considering all constraints - // from nested goals which are not from where-bounds. We will already - // need to track which nested goals are required by impl where-bounds - // for coinductive cycles, so we simply reuse that here. - // - // While we could consider overflow constraints in more cases, this should - // not be necessary for backcompat and results in better perf. It also - // avoids a potential inconsistency which would otherwise require some - // tracking for root goals as well. See #119071 for an example. - let keep_overflow_constraints = || { - self.search_graph.current_goal_is_normalizes_to() - && source != GoalSource::ImplWhereBound - }; - - if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty - && !keep_overflow_constraints() - { - return (response.value.certainty, false); + ) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) { + if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { + return (NestedNormalizationGoals::empty(), response.value.certainty, false); } let has_changed = !response.value.var_values.is_identity_modulo_regions() || !response.value.external_constraints.opaque_types.is_empty(); - let certainty = + let (normalization_nested_goals, certainty) = self.instantiate_and_apply_query_response(param_env, original_values, response); - (certainty, has_changed) + (normalization_nested_goals, certainty, has_changed) } fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { @@ -496,7 +507,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { let tcx = self.tcx(); - let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); + let mut goals = core::mem::take(&mut self.nested_goals); self.inspect.evaluate_added_goals_loop_start(); @@ -508,7 +519,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); - if let Some(goal) = goals.normalizes_to_hack_goal.take() { + for goal in goals.normalizes_to_goals { // Replace the goal with an unconstrained infer var, so the // RHS does not affect projection candidate assembly. let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); @@ -517,11 +528,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, ); - let (_, certainty) = self.evaluate_goal( - GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }, + let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( + GoalEvaluationKind::Nested, GoalSource::Misc, unconstrained_goal, )?; + // Add the nested goals from normalization to our own nested goals. + goals.goals.extend(nested_goals); // Finally, equate the goal's RHS with the unconstrained var. // We put the nested goals from this into goals instead of @@ -536,27 +549,23 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // looking at the "has changed" return from evaluate_goal, // because we expect the `unconstrained_rhs` part of the predicate // to have changed -- that means we actually normalized successfully! - if goal.predicate.alias != self.resolve_vars_if_possible(goal.predicate.alias) { + let with_resolved_vars = self.resolve_vars_if_possible(goal); + if goal.predicate.alias != with_resolved_vars.predicate.alias { unchanged_certainty = None; } match certainty { Certainty::Yes => {} Certainty::Maybe(_) => { - // We need to resolve vars here so that we correctly - // deal with `has_changed` in the next iteration. - self.set_normalizes_to_hack_goal(self.resolve_vars_if_possible(goal)); + self.nested_goals.normalizes_to_goals.push(with_resolved_vars); unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); } } } - for (source, goal) in goals.goals.drain(..) { - let (has_changed, certainty) = self.evaluate_goal( - GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No }, - source, - goal, - )?; + for (source, goal) in goals.goals { + let (has_changed, certainty) = + self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; if has_changed { unchanged_certainty = None; } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 91fd48807a4..5b1124e8b9f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -24,6 +24,7 @@ where infcx: outer_ecx.infcx, variables: outer_ecx.variables, var_values: outer_ecx.var_values, + is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal, predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, max_input_universe: outer_ecx.max_input_universe, search_graph: outer_ecx.search_graph, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 3262d64cb7d..e0c7804b6db 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -58,12 +58,13 @@ impl<'tcx> InferCtxt<'tcx> { } let candidate = candidates.pop().unwrap(); - let certainty = ecx.instantiate_and_apply_query_response( - trait_goal.param_env, - orig_values, - candidate.result, - ); - + let (normalization_nested_goals, certainty) = ecx + .instantiate_and_apply_query_response( + trait_goal.param_env, + orig_values, + candidate.result, + ); + assert!(normalization_nested_goals.is_empty()); Ok(Some((candidate, certainty))) }); diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9e3e6a4676e..cfec2e9bbf3 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -70,7 +70,19 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { instantiated_goals.push(goal); } - for &goal in &instantiated_goals { + for goal in instantiated_goals.iter().copied() { + // We need to be careful with `NormalizesTo` goals as the + // expected term has to be replaced with an unconstrained + // inference variable. + if let Some(kind) = goal.predicate.kind().no_bound_vars() + && let ty::PredicateKind::NormalizesTo(predicate) = kind + && !predicate.alias.is_opaque(infcx.tcx) + { + // FIXME: We currently skip these goals as + // `fn evaluate_root_goal` ICEs if there are any + // `NestedNormalizationGoals`. + continue; + }; let (_, proof_tree) = infcx.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); try_visit!(visitor.visit_goal(&InspectGoal::new( diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index f7b310a7abe..4da999f2406 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -7,7 +7,7 @@ use std::mem; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ - CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack, QueryInput, QueryResult, + CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, }; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; @@ -97,9 +97,7 @@ impl<'tcx> WipGoalEvaluation<'tcx> { WipGoalEvaluationKind::Root { orig_values } => { inspect::GoalEvaluationKind::Root { orig_values } } - WipGoalEvaluationKind::Nested { is_normalizes_to_hack } => { - inspect::GoalEvaluationKind::Nested { is_normalizes_to_hack } - } + WipGoalEvaluationKind::Nested => inspect::GoalEvaluationKind::Nested, }, evaluation: self.evaluation.unwrap().finalize(), } @@ -109,7 +107,7 @@ impl<'tcx> WipGoalEvaluation<'tcx> { #[derive(Eq, PartialEq, Debug)] pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> { Root { orig_values: Vec<ty::GenericArg<'tcx>> }, - Nested { is_normalizes_to_hack: IsNormalizesToHack }, + Nested, } #[derive(Eq, PartialEq)] @@ -305,9 +303,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { solve::GoalEvaluationKind::Root => { WipGoalEvaluationKind::Root { orig_values: orig_values.to_vec() } } - solve::GoalEvaluationKind::Nested { is_normalizes_to_hack } => { - WipGoalEvaluationKind::Nested { is_normalizes_to_hack } - } + solve::GoalEvaluationKind::Nested => WipGoalEvaluationKind::Nested, }, evaluation: None, }) @@ -419,6 +415,17 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } + pub fn add_normalizes_to_goal( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + ) { + if ecx.inspect.is_noop() { + return; + } + + Self::add_goal(ecx, GoalSource::Misc, goal.with(ecx.tcx(), goal.predicate)); + } + pub fn add_goal( ecx: &mut EvalCtxt<'_, 'tcx>, source: GoalSource, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 0bf28f520a4..8294a8a67b1 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -18,8 +18,7 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack, - QueryResult, Response, + CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response, }; use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ @@ -69,7 +68,7 @@ enum SolverMode { #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum GoalEvaluationKind { Root, - Nested { is_normalizes_to_hack: IsNormalizesToHack }, + Nested, } #[extension(trait CanonicalResponseExt)] @@ -202,12 +201,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] - fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { - assert!( - self.nested_goals.normalizes_to_hack_goal.is_none(), - "attempted to set the projection eq hack goal when one already exists" - ); - self.nested_goals.normalizes_to_hack_goal = Some(goal); + fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + inspect::ProofTreeBuilder::add_normalizes_to_goal(self, goal); + self.nested_goals.normalizes_to_goals.push(goal); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs index 911462f4b9a..37d56452893 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -16,7 +16,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .no_bound_vars() .expect("const ty should not rely on other generics"), ) { - self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?; + self.instantiate_normalizes_to_term(goal, normalized_const.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs index 52d2fe1e3ec..d60490bce44 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs @@ -16,7 +16,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> QueryResult<'tcx> { let tcx = self.tcx(); let inherent = goal.predicate.alias; - let expected = goal.predicate.term.ty().expect("inherent consts are treated separately"); let impl_def_id = tcx.parent(inherent.def_id); let impl_args = self.fresh_args_for_item(impl_def_id); @@ -30,12 +29,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // Equate IAT with the RHS of the project goal let inherent_args = inherent.rebase_inherent_args_onto_impl(impl_args, tcx); - self.eq( - goal.param_env, - expected, - tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args), - ) - .expect("expected goal term to be fully unconstrained"); // Check both where clauses on the impl and IAT // @@ -51,6 +44,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .map(|(pred, _)| goal.with(tcx, pred)), ); + let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args); + self.instantiate_normalizes_to_term(goal, normalized.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index a45c1c34410..85bb6338daf 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -31,32 +31,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { let def_id = goal.predicate.def_id(); + let def_kind = self.tcx().def_kind(def_id); + match def_kind { + DefKind::OpaqueTy => return self.normalize_opaque_type(goal), + _ => self.set_is_normalizes_to_goal(), + } + + debug_assert!(self.term_is_fully_unconstrained(goal)); match self.tcx().def_kind(def_id) { DefKind::AssocTy | DefKind::AssocConst => { match self.tcx().associated_item(def_id).container { ty::AssocItemContainer::TraitContainer => { - // To only compute normalization once for each projection we only - // assemble normalization candidates if the expected term is an - // unconstrained inference variable. - // - // Why: For better cache hits, since if we have an unconstrained RHS then - // there are only as many cache keys as there are (canonicalized) alias - // types in each normalizes-to goal. This also weakens inference in a - // forwards-compatible way so we don't use the value of the RHS term to - // affect candidate assembly for projections. - // - // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal - // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for - // `U` and equate it with `u32`. This means that we don't need a separate - // projection cache in the solver, since we're piggybacking off of regular - // goal caching. - if self.term_is_fully_unconstrained(goal) { - let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) - } else { - self.set_normalizes_to_hack_goal(goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) } ty::AssocItemContainer::ImplContainer => { self.normalize_inherent_associated_type(goal) @@ -64,9 +51,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } DefKind::AnonConst => self.normalize_anon_const(goal), - DefKind::OpaqueTy => self.normalize_opaque_type(goal), DefKind::TyAlias => self.normalize_weak_type(goal), - kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)), + kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)), } } @@ -428,7 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ), - sym::CallMutFuture | sym::CallFuture => ( + sym::CallRefFuture => ( ty::AliasTy::new( tcx, goal.predicate.def_id(), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs index 9f91c02c1ab..13af5068b6c 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs @@ -15,10 +15,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> QueryResult<'tcx> { let tcx = self.tcx(); let weak_ty = goal.predicate.alias; - let expected = goal.predicate.term.ty().expect("no such thing as a const alias"); - - let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); - self.eq(goal.param_env, expected, actual)?; // Check where clauses self.add_goals( @@ -30,6 +26,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .map(|pred| goal.with(tcx, pred)), ); + let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); + self.instantiate_normalizes_to_term(goal, actual.into()); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 07a8aca85a0..a48b2f2478b 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -10,7 +10,6 @@ use rustc_index::IndexVec; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; -use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_session::Limit; use std::mem; @@ -175,15 +174,6 @@ impl<'tcx> SearchGraph<'tcx> { } } - pub(super) fn current_goal_is_normalizes_to(&self) -> bool { - self.stack.raw.last().map_or(false, |e| { - matches!( - e.input.value.goal.predicate.kind().skip_binder(), - ty::PredicateKind::NormalizesTo(..) - ) - }) - } - /// Returns the remaining depth allowed for nested goals. /// /// This is generally simply one less than the current depth. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 067ca883bd8..00d00496947 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -194,8 +194,7 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`. - // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest - // `fn foo(t: impl Trait<A: Bound>)` instead. + // FIXME: we should suggest `fn foo(t: impl Trait<A: Bound>)` instead. err.multipart_suggestion( "introduce a type parameter with a trait bound instead of using `impl Trait`", sugg, @@ -1099,8 +1098,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )) } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - self.tcx.item_bounds(def_id).instantiate(self.tcx, args).iter().find_map( - |pred| { + self.tcx + .item_super_predicates(def_id) + .instantiate(self.tcx, args) + .iter() + .find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be args[1] @@ -1114,8 +1116,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } else { None } - }, - ) + }) } ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { @@ -2954,6 +2955,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::VariableType(hir_id) => { + if let Some(typeck_results) = &self.typeck_results + && let Some(ty) = typeck_results.node_type_opt(hir_id) + && let ty::Error(_) = ty.kind() + { + err.note(format!( + "`{predicate}` isn't satisfied, but the type of this pattern is \ + `{{type error}}`", + )); + err.downgrade_to_delayed_bug(); + } match tcx.parent_hir_node(hir_id) { Node::Local(hir::Local { ty: Some(ty), .. }) => { err.span_suggestion_verbose( @@ -3200,71 +3211,69 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - // Don't print the tuple of capture types - 'print: { - if !is_upvar_tys_infer_tuple { - let ty_str = tcx.short_ty_string(ty, &mut long_ty_file); - let msg = format!("required because it appears within the type `{ty_str}`"); - match ty.kind() { - ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { - Some(ident) => err.span_note(ident.span, msg), - None => err.note(msg), - }, - ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - // If the previous type is async fn, this is the future generated by the body of an async function. - // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below). - let is_future = tcx.ty_is_opaque_future(ty); - debug!( - ?obligated_types, - ?is_future, - "note_obligation_cause_code: check for async fn" - ); - if is_future - && obligated_types.last().is_some_and(|ty| match ty.kind() { - ty::Coroutine(last_def_id, ..) => { - tcx.coroutine_is_async(*last_def_id) - } - _ => false, - }) - { - break 'print; - } - err.span_note(tcx.def_span(def_id), msg) + if !is_upvar_tys_infer_tuple { + let ty_str = tcx.short_ty_string(ty, &mut long_ty_file); + let msg = format!("required because it appears within the type `{ty_str}`"); + match ty.kind() { + ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { + Some(ident) => { + err.span_note(ident.span, msg); } - ty::CoroutineWitness(def_id, args) => { - use std::fmt::Write; - - // FIXME: this is kind of an unusual format for rustc, can we make it more clear? - // Maybe we should just remove this note altogether? - // FIXME: only print types which don't meet the trait requirement - let mut msg = - "required because it captures the following types: ".to_owned(); - for bty in tcx.coroutine_hidden_types(*def_id) { - let ty = bty.instantiate(tcx, args); - write!(msg, "`{ty}`, ").unwrap(); - } - err.note(msg.trim_end_matches(", ").to_string()) + None => { + err.note(msg); } - ty::Coroutine(def_id, _) => { - let sp = tcx.def_span(def_id); - - // Special-case this to say "async block" instead of `[static coroutine]`. - let kind = tcx.coroutine_kind(def_id).unwrap(); - err.span_note( - sp, - with_forced_trimmed_paths!(format!( - "required because it's used within this {kind:#}", - )), - ) + }, + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { + // If the previous type is async fn, this is the future generated by the body of an async function. + // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below). + let is_future = tcx.ty_is_opaque_future(ty); + debug!( + ?obligated_types, + ?is_future, + "note_obligation_cause_code: check for async fn" + ); + if is_future + && obligated_types.last().is_some_and(|ty| match ty.kind() { + ty::Coroutine(last_def_id, ..) => { + tcx.coroutine_is_async(*last_def_id) + } + _ => false, + }) + { + // See comment above; skip printing twice. + } else { + err.span_note(tcx.def_span(def_id), msg); } - ty::Closure(def_id, _) => err.span_note( + } + ty::Coroutine(def_id, _) => { + let sp = tcx.def_span(def_id); + + // Special-case this to say "async block" instead of `[static coroutine]`. + let kind = tcx.coroutine_kind(def_id).unwrap(); + err.span_note( + sp, + with_forced_trimmed_paths!(format!( + "required because it's used within this {kind:#}", + )), + ); + } + ty::CoroutineWitness(..) => { + // Skip printing coroutine-witnesses, since we'll drill into + // the bad field in another derived obligation cause. + } + ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { + err.span_note( tcx.def_span(def_id), "required because it's used within this closure", - ), - ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"), - _ => err.note(msg), - }; - } + ); + } + ty::Str => { + err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"); + } + _ => { + err.note(msg); + } + }; } obligated_types.push(ty); @@ -3510,9 +3519,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable"); - } + tcx.disabled_nightly_features( + err, + Some(tcx.local_def_id_to_hir_id(body_id)), + [(String::new(), sym::trivial_bounds)], + ); } ObligationCauseCode::OpaqueReturnType(expr_info) => { if let Some((expr_ty, expr_span)) = expr_info { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6756b5dec23..12371155303 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1726,7 +1726,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = args.coroutine_closure_sig().skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => { + sym::CallOnceFuture | sym::CallRefFuture => { if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { if !closure_kind.extends(goal_kind) { bug!("we should not be confirming if the closure kind is not met"); @@ -1787,7 +1787,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty], ), - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()], @@ -1803,7 +1803,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = bound_sig.skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); let future_output_def_id = tcx @@ -1822,7 +1822,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( obligation.predicate.def_id, [self_ty, Ty::new_tup(tcx, sig.inputs())], ), - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ @@ -1842,7 +1842,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = bound_sig.skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); let future_output_def_id = tcx @@ -1859,7 +1859,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( sym::CallOnceFuture | sym::Output => { ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]]) } - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()], diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 14f14ae6e2e..63289746f5e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -20,14 +20,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // such cases. if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) = key.value.predicate.kind().skip_binder() + && let Some(sized_def_id) = tcx.lang_items().sized_trait() + && trait_ref.def_id() == sized_def_id + && trait_ref.self_ty().is_trivially_sized(tcx) { - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - if trait_ref.def_id() == sized_def_id { - if trait_ref.self_ty().is_trivially_sized(tcx) { - return Some(()); - } - } - } + return Some(()); } if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) = diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index be71eac6948..53aadfb8a44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1617,21 +1617,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return ControlFlow::Continue(()), }; - for bound in - self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) - { - // HACK: On subsequent recursions, we only care about bounds that don't - // share the same type as `self_ty`. This is because for truly rigid - // projections, we will never be able to equate, e.g. `<T as Tr>::A` - // with `<<T as Tr>::A as Tr>::A`. - if in_parent_alias_type { - match bound.kind().skip_binder() { - ty::ClauseKind::Trait(tr) if tr.self_ty() == self_ty => continue, - ty::ClauseKind::Projection(p) if p.self_ty() == self_ty => continue, - _ => {} - } - } + // HACK: On subsequent recursions, we only care about bounds that don't + // share the same type as `self_ty`. This is because for truly rigid + // projections, we will never be able to equate, e.g. `<T as Tr>::A` + // with `<<T as Tr>::A as Tr>::A`. + let relevant_bounds = if in_parent_alias_type { + self.tcx().item_non_self_assumptions(alias_ty.def_id) + } else { + self.tcx().item_super_predicates(alias_ty.def_id) + }; + for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) { for_each(self, bound, idx)?; idx += 1; } @@ -2123,13 +2119,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ), ty::Adt(def, args) => { - let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where( - obligation - .predicate - .rebind(sized_crit.iter_instantiated(self.tcx(), args).collect()), - ) + if let Some(sized_crit) = def.sized_constraint(self.tcx()) { + // (*) binder moved here + Where( + obligation.predicate.rebind(vec![sized_crit.instantiate(self.tcx(), args)]), + ) + } else { + Where(ty::Binder::dummy(Vec::new())) + } } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index a5328baadb5..baf4de768c5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -102,6 +102,7 @@ fn fn_sig_for_fn_abi<'tcx>( ) } ty::CoroutineClosure(def_id, args) => { + let coroutine_ty = Ty::new_coroutine_closure(tcx, def_id, args); let sig = args.as_coroutine_closure().coroutine_closure_sig(); let bound_vars = tcx.mk_bound_variable_kinds_from_iter( sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), @@ -111,18 +112,24 @@ fn fn_sig_for_fn_abi<'tcx>( kind: ty::BoundRegionKind::BrEnv, }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`, // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - let mut kind = args.as_coroutine_closure().kind(); - if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def { - kind = target_kind; - } + let mut coroutine_kind = args.as_coroutine_closure().kind(); let env_ty = - tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region); + if let InstanceDef::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = + instance.def + { + coroutine_kind = ty::ClosureKind::FnOnce; + + // Implementations of `FnMut` and `Fn` for coroutine-closures + // still take their receiver by ref. + if receiver_by_ref { Ty::new_mut_ptr(tcx, coroutine_ty) } else { coroutine_ty } + } else { + tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region) + }; let sig = sig.skip_binder(); ty::Binder::bind_with_vars( @@ -132,7 +139,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx, args.as_coroutine_closure().parent_args(), tcx.coroutine_for_closure(def_id), - kind, + coroutine_kind, env_region, args.as_coroutine_closure().tupled_upvars_ty(), args.as_coroutine_closure().coroutine_captures_by_ref_ty(), @@ -161,7 +168,7 @@ fn fn_sig_for_fn_abi<'tcx>( // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def { + if let InstanceDef::CoroutineKindShim { .. } = instance.def { // Grab the parent coroutine-closure. It has the same args for the purposes // of instantiation, so this will be okay to do. let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx @@ -181,7 +188,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx, coroutine_closure_args.parent_args(), did, - target_kind, + ty::ClosureKind::FnOnce, tcx.lifetimes.re_erased, coroutine_closure_args.tupled_upvars_ty(), coroutine_closure_args.coroutine_captures_by_ref_ty(), diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 50a8eb869b9..ba75424ec0c 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,11 +1,10 @@ use rustc_data_structures::fx::FxIndexSet; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, HirId}; -use rustc_index::IndexVec; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt, TyCtxtFeed}; +use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -238,28 +237,6 @@ fn associated_types_for_impl_traits_in_associated_fn( } } -fn feed_hir(feed: &TyCtxtFeed<'_, LocalDefId>) { - feed.local_def_id_to_hir_id(HirId::make_owner(feed.def_id())); - - let node = hir::OwnerNode::AssocOpaqueTy(&hir::AssocOpaqueTy {}); - let bodies = Default::default(); - let attrs = hir::AttributeMap::EMPTY; - - let (opt_hash_including_bodies, _) = feed.tcx.hash_owner_nodes(node, &bodies, &attrs.map); - feed.opt_hir_owner_nodes(Some(feed.tcx.arena.alloc(hir::OwnerNodes { - opt_hash_including_bodies, - nodes: IndexVec::from_elem_n( - hir::ParentedNode { - parent: hir::ItemLocalId::INVALID, - node: hir::Node::AssocOpaqueTy(&hir::AssocOpaqueTy {}), - }, - 1, - ), - bodies, - }))); - feed.feed_owner_id().hir_attrs(attrs); -} - /// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated /// function from a trait, synthesize an associated type for that `impl Trait` /// that inherits properties that we infer from the method and the opaque type. @@ -281,7 +258,7 @@ fn associated_type_for_impl_trait_in_trait( let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - feed_hir(&trait_assoc_ty); + trait_assoc_ty.feed_hir(); // Copy span of the opaque. trait_assoc_ty.def_ident_span(Some(span)); @@ -335,7 +312,7 @@ fn associated_type_for_impl_trait_in_impl( let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - feed_hir(&impl_assoc_ty); + impl_assoc_ty.feed_hir(); // Copy span of the opaque. impl_assoc_ty.def_ident_span(Some(span)); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 2816bcc888b..a8f9afb87dd 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -282,7 +282,7 @@ fn resolve_associated_item<'tcx>( Some(Instance { def: ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnOnce, + receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, }, args, }) @@ -297,25 +297,20 @@ fn resolve_associated_item<'tcx>( { match *rcvr_args.type_at(0).kind() { ty::CoroutineClosure(coroutine_closure_def_id, args) => { - match (target_kind, args.as_coroutine_closure().kind()) { - (ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn) - | (ClosureKind::FnOnce, ClosureKind::FnMut) => { - // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, - // or `AsyncFnOnce` for a by-mut closure, then construct a new body that - // has the right return types. - // - // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs - // to have its input and output types fixed (`&mut self` and returning - // `i16` coroutine kind). - Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind, - }, - args, - }) - } - _ => Some(Instance::new(coroutine_closure_def_id, args)), + if target_kind == ClosureKind::FnOnce + && args.as_coroutine_closure().kind() != ClosureKind::FnOnce + { + // If we're computing `AsyncFnOnce` for a by-ref closure then + // construct a new body that has the right return types. + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + receiver_by_ref: false, + }, + args, + }) + } else { + Some(Instance::new(coroutine_closure_def_id, args)) } } ty::Closure(closure_def_id, args) => { diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index bb546cee2dd..a5ffa553c2a 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -12,7 +12,7 @@ pub(crate) fn provide(providers: &mut Providers) { macro_rules! rtry { ($e:expr) => { match $e { - e @ Representability::Infinite => return e, + e @ Representability::Infinite(_) => return e, Representability::Representable => {} } }; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2b6b91672c3..547a3cb5a8c 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,78 +1,56 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; -fn sized_constraint_for_ty<'tcx>( - tcx: TyCtxt<'tcx>, - adtdef: ty::AdtDef<'tcx>, - ty: Ty<'tcx>, -) -> Vec<Ty<'tcx>> { +#[instrument(level = "debug", skip(tcx), ret)] +fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { use rustc_type_ir::TyKind::*; - let result = match ty.kind() { - Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) - | FnPtr(_) | Array(..) | Closure(..) | CoroutineClosure(..) | Coroutine(..) | Never => { - vec![] - } - - Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => { - // these are never sized - return the target type - vec![ty] - } - - Tuple(tys) => match tys.last() { - None => vec![], - Some(&ty) => sized_constraint_for_ty(tcx, adtdef, ty), - }, - - Adt(adt, args) => { - // recursive case - let adt_tys = adt.sized_constraint(tcx); - debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); - adt_tys - .iter_instantiated(tcx, args) - .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) - .collect() - } - - Alias(..) => { - // must calculate explicitly. - // FIXME: consider special-casing always-Sized projections - vec![ty] - } - - Param(..) => { - // perf hack: if there is a `T: Sized` bound, then - // we know that `T` is Sized and do not need to check - // it on the impl. - - let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() else { return vec![ty] }; - let predicates = tcx.predicates_of(adtdef.did()).predicates; - if predicates.iter().any(|(p, _)| { - p.as_trait_clause().is_some_and(|trait_pred| { - trait_pred.def_id() == sized_trait_def_id - && trait_pred.self_ty().skip_binder() == ty - }) - }) { - vec![] - } else { - vec![ty] - } - } + match ty.kind() { + // these are always sized + Bool + | Char + | Int(..) + | Uint(..) + | Float(..) + | RawPtr(..) + | Ref(..) + | FnDef(..) + | FnPtr(..) + | Array(..) + | Closure(..) + | CoroutineClosure(..) + | Coroutine(..) + | CoroutineWitness(..) + | Never + | Dynamic(_, _, ty::DynStar) => None, + + // these are never sized + Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty), + + Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), + + // recursive case + Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| { + let ty = intermediate.instantiate(tcx, args); + sized_constraint_for_ty(tcx, ty) + }), + + // these can be sized or unsized + Param(..) | Alias(..) | Error(_) => Some(ty), Placeholder(..) | Bound(..) | Infer(..) => { - bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) + bug!("unexpected type `{ty:?}` in sized_constraint_for_ty") } - }; - debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); - result + } } fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { @@ -90,29 +68,45 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { /// /// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type -/// - a type parameter or projection whose Sizedness can't be known -/// - a tuple of type parameters or projections, if there are multiple -/// such. -/// - an Error, if a type is infinitely sized +/// - a type parameter or projection whose sizedness can't be known +#[instrument(level = "debug", skip(tcx), ret)] fn adt_sized_constraint<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> ty::EarlyBinder<&'tcx ty::List<Ty<'tcx>>> { +) -> Option<ty::EarlyBinder<Ty<'tcx>>> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite) { - return ty::EarlyBinder::bind(tcx.mk_type_list(&[Ty::new_misc_error(tcx)])); + if let ty::Representability::Infinite(_) = tcx.representability(def_id) { + return None; } } let def = tcx.adt_def(def_id); - let result = - tcx.mk_type_list_from_iter(def.variants().iter().filter_map(|v| v.tail_opt()).flat_map( - |f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).instantiate_identity()), - )); + if !def.is_struct() { + bug!("`adt_sized_constraint` called on non-struct type: {def:?}"); + } + + let tail_def = def.non_enum_variant().tail_opt()?; + let tail_ty = tcx.type_of(tail_def.did).instantiate_identity(); - debug!("adt_sized_constraint: {:?} => {:?}", def, result); + let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?; + if constraint_ty.references_error() { + return None; + } + + // perf hack: if there is a `constraint_ty: Sized` bound, then we know + // that the type is sized and do not need to check it on the impl. + let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let predicates = tcx.predicates_of(def.did()).predicates; + if predicates.iter().any(|(p, _)| { + p.as_trait_clause().is_some_and(|trait_pred| { + trait_pred.def_id() == sized_trait_def_id + && trait_pred.self_ty().skip_binder() == constraint_ty + }) + }) { + return None; + } - ty::EarlyBinder::bind(result) + Some(ty::EarlyBinder::bind(constraint_ty)) } /// See `ParamEnv` struct definition for details. diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index b38ef2ad84d..cd199222d90 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -85,7 +85,7 @@ bitflags! { | TypeFlags::HAS_TY_INHERENT.bits() | TypeFlags::HAS_CT_PROJECTION.bits(); - /// Is an error type/const reachable? + /// Is an error type/lifetime/const reachable? const HAS_ERROR = 1 << 15; /// Does this have any region that "appears free" in the type? diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index a0759f7df7f..112f617fe16 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -148,19 +148,20 @@ pub enum PredicateKind<I: Interner> { /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. Ambiguous, - /// The alias normalizes to `term`. Unlike `Projection`, this always fails if the alias - /// cannot be normalized in the current context. + /// This should only be used inside of the new solver for `AliasRelate` and expects + /// the `term` to be an unconstrained inference variable. /// - /// `Projection(<T as Trait>::Assoc, ?x)` results in `?x == <T as Trait>::Assoc` while - /// `NormalizesTo(<T as Trait>::Assoc, ?x)` results in `NoSolution`. - /// - /// Only used in the new solver. + /// The alias normalizes to `term`. Unlike `Projection`, this always fails if the + /// alias cannot be normalized in the current context. For the rigid alias + /// `T as Trait>::Assoc`, `Projection(<T as Trait>::Assoc, ?x)` constrains `?x` + /// to `<T as Trait>::Assoc` while `NormalizesTo(<T as Trait>::Assoc, ?x)` + /// results in `NoSolution`. NormalizesTo(I::NormalizesTo), /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother. /// - /// Only used for new solver + /// Only used for new solver. AliasRelate(I::Term, I::Term, AliasRelationDirection), } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index cf13f066cbf..2e8481df56d 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -223,23 +223,27 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data { - ReEarlyParam(data) => write!(f, "ReEarlyParam({data:?})"), + ReEarlyParam(data) => write!(f, "{data:?}"), ReBound(binder_id, bound_region) => { - write!(f, "ReBound({binder_id:?}, {bound_region:?})") + write!(f, "'")?; + crate::debug_bound_var(f, *binder_id, bound_region) } ReLateParam(fr) => write!(f, "{fr:?}"), - ReStatic => f.write_str("ReStatic"), + ReStatic => f.write_str("'static"), ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)), - RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"), + RePlaceholder(placeholder) => write!(f, "{placeholder:?}"), - ReErased => f.write_str("ReErased"), + // Use `'{erased}` as the output instead of `'erased` so that its more obviously distinct from + // a `ReEarlyParam` named `'erased`. Technically that would print as `'erased/#IDX` so this is + // not strictly necessary but *shrug* + ReErased => f.write_str("'{erased}"), - ReError(_) => f.write_str("ReError"), + ReError(_) => f.write_str("'{region error}"), } } } diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index c780042ff26..66457933438 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -57,11 +57,11 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> { let mut buf = [0u8; std::mem::size_of::<u128>()]; match MachineInfo::target_endianess() { Endian::Little => { - bytes.read(&mut buf)?; + bytes.read_exact(&mut buf[..bytes.len()])?; Ok(u128::from_le_bytes(buf)) } Endian::Big => { - bytes.read(&mut buf[16 - bytes.len()..])?; + bytes.read_exact(&mut buf[16 - bytes.len()..])?; Ok(u128::from_be_bytes(buf)) } } @@ -72,11 +72,11 @@ pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> { let mut buf = [0u8; std::mem::size_of::<i128>()]; match MachineInfo::target_endianess() { Endian::Little => { - bytes.read(&mut buf)?; + bytes.read_exact(&mut buf[..bytes.len()])?; Ok(i128::from_le_bytes(buf)) } Endian::Big => { - bytes.read(&mut buf[16 - bytes.len()..])?; + bytes.read_exact(&mut buf[16 - bytes.len()..])?; Ok(i128::from_be_bytes(buf)) } } |
