diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 6d323b03cdaa3..df04128135b89 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> { impl<'tcx> OutlivesConstraintSet<'tcx> { pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { - debug!( - "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", - constraint.sup, constraint.sub, constraint.locations - ); + debug!("OutlivesConstraintSet::push({:?})", constraint); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting return; diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 3b58da11e84a0..1c01e78abd422 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; -use crate::region_infer::BlameConstraint; +use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, WriteKind, @@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> { span: Span, region_name: RegionName, opt_place_desc: Option, + extra_info: Vec, }, Unexplained, } @@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ref region_name, ref opt_place_desc, from_closure: _, + ref extra_info, } => { region_name.highlight_region_name(err); @@ -268,6 +270,14 @@ impl<'tcx> BorrowExplanation<'tcx> { ); }; + for extra in extra_info { + match extra { + ExtraConstraintInfo::PlaceholderFromPredicate(span) => { + err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + } + } + } + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); } _ => {} @@ -309,16 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, borrow_region: RegionVid, outlived_region: RegionVid, - ) -> (ConstraintCategory<'tcx>, bool, Span, Option) { - let BlameConstraint { category, from_closure, cause, variance_info: _ } = self - .regioncx - .best_blame_constraint(borrow_region, NllRegionVariableOrigin::FreeRegion, |r| { - self.regioncx.provides_universal_region(r, borrow_region, outlived_region) - }); + ) -> (ConstraintCategory<'tcx>, bool, Span, Option, Vec) { + let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint( + borrow_region, + NllRegionVariableOrigin::FreeRegion, + |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), + ); + let BlameConstraint { category, from_closure, cause, .. } = blame_constraint; let outlived_fr_name = self.give_region_a_name(outlived_region); - (category, from_closure, cause.span, outlived_fr_name) + (category, from_closure, cause.span, outlived_fr_name, extra_info) } /// Returns structured explanation for *why* the borrow contains the @@ -390,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None => { if let Some(region) = self.to_error_region_vid(borrow_region_vid) { - let (category, from_closure, span, region_name) = + let (category, from_closure, span, region_name, extra_info) = self.free_region_constraint_info(borrow_region_vid, region); if let Some(region_name) = region_name { let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref()); @@ -400,6 +411,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span, region_name, opt_place_desc, + extra_info, } } else { debug!("Could not generate a region name"); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e7681222fc1f0..34be2874fcb73 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -31,7 +31,7 @@ use crate::session_diagnostics::{ }; use super::{OutlivesSuggestionBuilder, RegionName}; -use crate::region_infer::BlameConstraint; +use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ nll::ConstraintDescription, region_infer::{values::RegionElement, TypeTest}, @@ -354,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let BlameConstraint { category, cause, variance_info, from_closure: _ } = + let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); + let BlameConstraint { category, cause, variance_info, .. } = blame_constraint; debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); @@ -466,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + for extra in extra_info { + match extra { + ExtraConstraintInfo::PlaceholderFromPredicate(span) => { + diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + } + } + } + self.buffer_error(diag); } @@ -557,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// LL | ref_obj(x) /// | ^^^^^^^^^^ `x` escapes the function body here /// ``` + #[instrument(level = "debug", skip(self))] fn report_escaping_data_error( &self, errci: &ErrorConstraintInfo<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 79a3a247c48a5..244e6e3422d83 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -245,6 +245,11 @@ enum Trace<'tcx> { NotVisited, } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ExtraConstraintInfo { + PlaceholderFromPredicate(Span), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -1818,10 +1823,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { - let BlameConstraint { category, cause, .. } = - self.best_blame_constraint(fr1, fr1_origin, |r| { - self.provides_universal_region(r, fr1, fr2) - }); + let BlameConstraint { category, cause, .. } = self + .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) + .0; (category, cause) } @@ -2010,7 +2014,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, - ) -> BlameConstraint<'tcx> { + ) -> (BlameConstraint<'tcx>, Vec) { // Find all paths let (path, target_region) = self.find_constraint_paths_between_regions(from_region, target_test).unwrap(); @@ -2026,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::>() ); + let mut extra_info = vec![]; + for constraint in path.iter() { + let outlived = constraint.sub; + let Some(origin) = self.var_infos.get(outlived) else { continue; }; + let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; }; + debug!(?constraint, ?p); + let ConstraintCategory::Predicate(span) = constraint.category else { continue; }; + extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span)); + // We only want to point to one + break; + } + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. // Instead, we use it to produce an improved `ObligationCauseCode`. // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` @@ -2073,6 +2089,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_closure, cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code), variance_info: constraint.variance_info, + outlives_constraint: *constraint, } }) .collect(); @@ -2174,7 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let best_choice = if blame_source { range.rev().find(find_region) } else { range.find(find_region) }; - debug!(?best_choice, ?blame_source); + debug!(?best_choice, ?blame_source, ?extra_info); if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { @@ -2183,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { // The return expression is being influenced by the return type being // impl Trait, point at the return type and not the return expr. - return next.clone(); + return (next.clone(), extra_info); } } @@ -2203,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - return categorized_path[i].clone(); + return (categorized_path[i].clone(), extra_info); } // If that search fails, that is.. unusual. Maybe everything @@ -2213,7 +2230,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); debug!("sorted_path={:#?}", categorized_path); - categorized_path.remove(0) + (categorized_path.remove(0), extra_info) } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { @@ -2295,7 +2312,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", region, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate( + region.into(), + outlived_region, + )), + ConstraintCategory::BoringNoLocation, + ) } ClosureOutlivesSubject::Ty(ty) => { @@ -2305,7 +2328,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx outlives_requirement={:?}", ty, outlived_region, outlives_requirement, ); - ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)) + ( + ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)), + ConstraintCategory::BoringNoLocation, + ) } } }) @@ -2319,4 +2345,5 @@ pub struct BlameConstraint<'tcx> { pub from_closure: bool, pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub outlives_constraint: OutlivesConstraint<'tcx>, } diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 29195b3922fcd..9271a2f4dc718 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// constraints should occur within this method so that those /// constraints can be properly localized!** #[instrument(skip(self, op), level = "trace")] - pub(super) fn fully_perform_op( + pub(super) fn fully_perform_op( &mut self, locations: Locations, category: ConstraintCategory<'tcx>, @@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; + debug!(?output, ?constraints); + if let Some(data) = constraints { self.push_region_constraints(locations, category, data); } @@ -102,6 +104,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } + #[instrument(level = "debug", skip(self))] pub(super) fn normalize_and_prove_instantiated_predicates( &mut self, // Keep this parameter for now, in case we start using @@ -116,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .zip(instantiated_predicates.spans.into_iter()) { debug!(?predicate); - let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); + let category = ConstraintCategory::Predicate(span); + let predicate = self.normalize_with_category(predicate, locations, category); + self.prove_predicate(predicate, locations, category); } } @@ -153,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }) } - #[instrument(skip(self), level = "debug")] pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T + where + T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, + { + self.normalize_with_category(value, location, ConstraintCategory::Boring) + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn normalize_with_category( + &mut self, + value: T, + location: impl NormalizeLocation, + category: ConstraintCategory<'tcx>, + ) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { let param_env = self.param_env; self.fully_perform_op( location.to_locations(), - ConstraintCategory::Boring, + category, param_env.and(type_op::normalize::Normalize::new(value)), ) .unwrap_or_else(|NoSolution| { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 9fab7ad914a84..71eae0583cb48 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { + fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. @@ -98,15 +98,18 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // region constraints like `for<'a> 'a: 'b`. At some point // when we move to universes, we will, and this assertion // will start to fail. - let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", query_constraint,); - }); + let ty::OutlivesPredicate(k1, r2) = + query_constraint.0.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", query_constraint,); + }); + + let constraint_category = query_constraint.1; match k1.unpack() { GenericArgKind::Lifetime(r1) => { let r1_vid = self.to_region_vid(r1); let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid); + self.add_outlives(r1_vid, r2_vid, constraint_category); } GenericArgKind::Type(t1) => { @@ -121,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { Some(implicit_region_bound), param_env, ) - .type_must_outlive(origin, t1, r2); + .type_must_outlive(origin, t1, r2, constraint_category); } GenericArgKind::Const(_) => { @@ -168,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { + fn add_outlives( + &mut self, + sup: ty::RegionVid, + sub: ty::RegionVid, + category: ConstraintCategory<'tcx>, + ) { + let category = match self.category { + ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category, + _ => self.category, + }; self.constraints.outlives_constraints.push(OutlivesConstraint { locations: self.locations, - category: self.category, + category, span: self.span, sub, sup, @@ -191,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' _origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + constraint_category: ConstraintCategory<'tcx>, ) { let b = self.to_region_vid(b); let a = self.to_region_vid(a); - self.add_outlives(b, a); + self.add_outlives(b, a, constraint_category); } fn push_verify( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 373411e1b7827..3713ec3f5d825 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -312,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + debug!(?constant, ?location, "visit_constant"); + self.super_constant(constant, location); let ty = self.sanitize_type(constant, constant.literal.ty()); @@ -1815,6 +1817,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { + debug!(?op, ?location, "check_operand"); + if let Operand::Constant(constant) = op { let maybe_uneval = match constant.literal { ConstantKind::Val(..) | ConstantKind::Ty(_) => None, @@ -2593,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .enumerate() .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = - constraint.no_bound_vars().unwrap_or_else(|| { + constraint.0.no_bound_vars().unwrap_or_else(|| { bug!("query_constraint {:?} contained bound vars", constraint,); }); diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 2899b8304bc14..65371a285911e 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -110,6 +110,7 @@ infer_relate_param_bound = ...so that the type `{$name}` will meet its required infer_relate_param_bound_2 = ...that is required by this bound infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait +infer_ascribe_user_type_prove_predicate = ...so that the where clause holds infer_nothing = {""} diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 6dfb6b11b1646..a774b52c8a592 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -338,10 +338,9 @@ impl Diagnostic { // The lint index inside the attribute is manually transferred here. let lint_index = expectation_id.get_lint_index(); expectation_id.set_lint_index(None); - let mut stable_id = unstable_to_stable + let mut stable_id = *unstable_to_stable .get(&expectation_id) - .expect("each unstable `LintExpectationId` must have a matching stable id") - .normalize(); + .expect("each unstable `LintExpectationId` must have a matching stable id"); stable_id.set_lint_index(lint_index); *expectation_id = stable_id; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6f969bfcc53f0..a7b01feeb386e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1171,7 +1171,7 @@ impl HandlerInner { if let Some(expectation_id) = diagnostic.level.get_expectation_id() { self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id.normalize()); + self.fulfilled_expectations.insert(expectation_id); } if matches!(diagnostic.level, Warning(_)) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 64c759f73d410..56e8348987951 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -22,6 +22,7 @@ use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::arena::ArenaAllocatable; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; @@ -129,7 +130,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( tcx, - region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), region_constraints, ) }); @@ -248,6 +251,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // the original values `v_o` that was canonicalized into a // variable... + let constraint_category = cause.to_constraint_category(); + for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { @@ -263,12 +268,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. if v_o != v_r { - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r))); - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o))); + output_query_region_constraints.outlives.push(( + ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)), + constraint_category, + )); + output_query_region_constraints.outlives.push(( + ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)), + constraint_category, + )); } } @@ -314,7 +321,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Screen out `'a: 'a` cases -- we skip the binder here but // only compare the inner values to one another, so they are still at // consistent binding levels. - let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder(); if k1 != r2.into() { Some(r_c) } else { None } }), ); @@ -559,7 +566,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Obligation<'tcx, ty::Predicate<'tcx>> { - let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder(); let atom = match k1.unpack() { GenericArgKind::Lifetime(r1) => { @@ -574,7 +581,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { span_bug!(cause.span, "unexpected const outlives {:?}", predicate); } }; - let predicate = predicate.rebind(atom).to_predicate(self.tcx); + let predicate = predicate.0.rebind(atom).to_predicate(self.tcx); Obligation::new(cause, param_env, predicate) } @@ -625,7 +632,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// creates query region constraints. pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, - outlives_obligations: impl Iterator, ty::Region<'tcx>)>, + outlives_obligations: impl Iterator, ty::Region<'tcx>, ConstraintCategory<'tcx>)>, region_constraints: &RegionConstraintData<'tcx>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys, givens, member_constraints } = @@ -638,26 +645,31 @@ pub fn make_query_region_constraints<'tcx>( let outlives: Vec<_> = constraints .iter() - .map(|(k, _)| match *k { - // Swap regions because we are going from sub (<=) to outlives - // (>=). - Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( - tcx.mk_region(ty::ReVar(v2)).into(), - tcx.mk_region(ty::ReVar(v1)), - ), - Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) - } - Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) - } - Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), + .map(|(k, origin)| { + // no bound vars in the code above + let constraint = ty::Binder::dummy(match *k { + // Swap regions because we are going from sub (<=) to outlives + // (>=). + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + tcx.mk_region(ty::ReVar(v2)).into(), + tcx.mk_region(ty::ReVar(v1)), + ), + Constraint::VarSubReg(v1, r2) => { + ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) + } + Constraint::RegSubVar(r1, v2) => { + ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) + } + Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), + }); + (constraint, origin.to_constraint_category()) }) - .map(ty::Binder::dummy) // no bound vars in the code above .chain( outlives_obligations - .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r)) - .map(ty::Binder::dummy), // no bound vars in the code above + // no bound vars in the code above + .map(|(ty, r, constraint_category)| { + (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category) + }), ) .collect(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index cffdf56bb6d48..adaa47c014023 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -77,6 +77,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, &parent); } + infer::AscribeUserTypeProvePredicate(span) => { + RegionOriginNote::Plain { + span, + msg: fluent::infer::ascribe_user_type_prove_predicate, + } + .add_to_diagnostic(err); + } } } @@ -356,6 +363,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } + infer::AscribeUserTypeProvePredicate(span) => { + let mut err = + struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); + note_and_explain_region( + self.tcx, + &mut err, + "lifetime instantiated with ", + sup, + "", + None, + ); + note_and_explain_region( + self.tcx, + &mut err, + "but lifetime must outlive ", + sub, + "", + None, + ); + err + } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index eb20c089dc712..3abed12217ccd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -408,7 +409,11 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl method against /// the containing trait. - CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId }, + CompareImplItemObligation { + span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + }, /// Checking that the bounds of a trait's associated type hold for a given impl CheckAssociatedTypeBounds { @@ -416,12 +421,24 @@ pub enum SubregionOrigin<'tcx> { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, }, + + AscribeUserTypeProvePredicate(Span), } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(SubregionOrigin<'_>, 32); +impl<'tcx> SubregionOrigin<'tcx> { + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { + match self { + Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), + Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), + _ => ConstraintCategory::BoringNoLocation, + } + } +} + /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -1988,6 +2005,7 @@ impl<'tcx> SubregionOrigin<'tcx> { DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, + AscribeUserTypeProvePredicate(span) => span, CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -2020,6 +2038,10 @@ impl<'tcx> SubregionOrigin<'tcx> { parent: Box::new(default()), }, + traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) + } + _ => default(), } } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 872886da36261..9922b156ebf96 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> { } /// Builder of OutlivesEnvironment. +#[derive(Debug)] struct OutlivesEnvironmentBuilder<'tcx> { param_env: ty::ParamEnv<'tcx>, region_relation: TransitiveRelationBuilder>, @@ -109,6 +110,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { #[inline] + #[instrument(level = "debug")] fn build(self) -> OutlivesEnvironment<'tcx> { OutlivesEnvironment { param_env: self.param_env, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 74c8bd88d275d..5bd1774f6b1ec 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -69,6 +69,7 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable}; use smallvec::smallvec; @@ -163,7 +164,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let outlives = &mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env); - outlives.type_must_outlive(origin, sup_type, sub_region); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); } } @@ -207,6 +209,7 @@ pub trait TypeOutlivesDelegate<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + constraint_category: ConstraintCategory<'tcx>, ); fn push_verify( @@ -255,12 +258,13 @@ where origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, region: ty::Region<'tcx>, + category: ConstraintCategory<'tcx>, ) { assert!(!ty.has_escaping_bound_vars()); let mut components = smallvec![]; push_outlives_components(self.tcx, ty, &mut components); - self.components_must_outlive(origin, &components, region); + self.components_must_outlive(origin, &components, region, category); } fn components_must_outlive( @@ -268,12 +272,13 @@ where origin: infer::SubregionOrigin<'tcx>, components: &[Component<'tcx>], region: ty::Region<'tcx>, + category: ConstraintCategory<'tcx>, ) { for component in components.iter() { let origin = origin.clone(); match component { Component::Region(region1) => { - self.delegate.push_sub_region_constraint(origin, region, *region1); + self.delegate.push_sub_region_constraint(origin, region, *region1, category); } Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); @@ -282,7 +287,7 @@ where self.projection_must_outlive(origin, region, *projection_ty); } Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, &subcomponents, region); + self.components_must_outlive(origin, &subcomponents, region, category); } Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error @@ -389,13 +394,19 @@ where if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); + let constraint = origin.to_constraint_category(); for k in projection_ty.substs { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint(origin.clone(), region, lt); + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); } GenericArgKind::Type(ty) => { - self.type_must_outlive(origin.clone(), ty, region); + self.type_must_outlive(origin.clone(), ty, region, constraint); } GenericArgKind::Const(_) => { // Const parameters don't impose constraints. @@ -433,7 +444,8 @@ where let unique_bound = trait_bounds[0]; debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound); debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.delegate.push_sub_region_constraint(origin, region, unique_bound); + let category = origin.to_constraint_category(); + self.delegate.push_sub_region_constraint(origin, region, unique_bound, category); return; } @@ -455,6 +467,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + _constraint_category: ConstraintCategory<'tcx>, ) { self.sub_regions(origin, a, b) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 34506c84cb8c7..7ca6ec5d96234 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -560,7 +560,7 @@ pub struct LateContext<'tcx> { /// Context for lint checking of the AST, after expansion, before lowering to HIR. pub struct EarlyContext<'a> { - pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>, + pub builder: LintLevelsBuilder<'a>, pub buffered: LintBuffer, } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 45f54cfed2d59..96ecd79a69cfb 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -59,7 +59,6 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { F: FnOnce(&mut Self), { let is_crate_node = id == ast::CRATE_NODE_ID; - debug!(?id); let push = self.context.builder.push(attrs, is_crate_node, None); self.check_id(id); diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index b9a3d52ca9b19..699e81543188f 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -16,10 +16,8 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { return; } - let lint_expectations = tcx.lint_expectations(()); let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids(); - - tracing::debug!(?lint_expectations, ?fulfilled_expectations); + let lint_expectations = &tcx.lint_levels(()).lint_expectations; for (id, expectation) in lint_expectations { // This check will always be true, since `lint_expectations` only diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a9ba2ad1d101d..1e16ac51e9e5d 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -6,11 +6,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::{intravisit, HirId}; -use rustc_index::vec::IndexVec; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource, - ShallowLintLevelMap, + struct_lint_level, LevelAndSource, LintExpectation, LintLevelMap, LintLevelSets, + LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -28,292 +27,47 @@ use crate::errors::{ UnknownToolInScopedLint, }; -/// Collection of lint levels for the whole crate. -/// This is used by AST-based lints, which do not -/// wait until we have built HIR to be emitted. -#[derive(Debug)] -struct LintLevelSets { - /// Linked list of specifications. - list: IndexVec, -} - -rustc_index::newtype_index! { - struct LintStackIndex { - ENCODABLE = custom, // we don't need encoding - const COMMAND_LINE = 0, - } -} - -/// Specifications found at this position in the stack. This map only represents the lints -/// found for one set of attributes (like `shallow_lint_levels_on` does). -/// -/// We store the level specifications as a linked list. -/// Each `LintSet` represents a set of attributes on the same AST node. -/// The `parent` forms a linked list that matches the AST tree. -/// This way, walking the linked list is equivalent to walking the AST bottom-up -/// to find the specifications for a given lint. -#[derive(Debug)] -struct LintSet { - // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which - // flag. - specs: FxHashMap, - parent: LintStackIndex, -} - -impl LintLevelSets { - fn new() -> Self { - LintLevelSets { list: IndexVec::new() } - } - - fn get_lint_level( - &self, - lint: &'static Lint, - idx: LintStackIndex, - aux: Option<&FxHashMap>, - sess: &Session, - ) -> LevelAndSource { - let lint = LintId::of(lint); - let (level, mut src) = self.raw_lint_id_level(lint, idx, aux); - let level = reveal_actual_level(level, &mut src, sess, lint, |id| { - self.raw_lint_id_level(id, idx, aux) - }); - (level, src) - } - - fn raw_lint_id_level( - &self, - id: LintId, - mut idx: LintStackIndex, - aux: Option<&FxHashMap>, - ) -> (Option, LintLevelSource) { - if let Some(specs) = aux { - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } - } - loop { - let LintSet { ref specs, parent } = self.list[idx]; - if let Some(&(level, src)) = specs.get(&id) { - return (Some(level), src); - } - if idx == COMMAND_LINE { - return (None, LintLevelSource::Default); - } - idx = parent; - } - } -} - -fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> { +fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { let store = unerased_lint_store(tcx); + let levels = + LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools); + let mut builder = LintLevelMapBuilder { levels, tcx }; + let krate = tcx.hir().krate(); - let mut builder = LintLevelsBuilder { - sess: tcx.sess, - provider: QueryMapExpectationsWrapper { - tcx, - cur: hir::CRATE_HIR_ID, - specs: ShallowLintLevelMap::default(), - expectations: Vec::new(), - unstable_to_stable_ids: FxHashMap::default(), - }, - warn_about_weird_lints: false, - store, - registered_tools: &tcx.resolutions(()).registered_tools, - }; - - builder.add_command_line(); - builder.add_id(hir::CRATE_HIR_ID); - tcx.hir().walk_toplevel_module(&mut builder); - - tcx.sess.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids); + builder.levels.id_to_set.reserve(krate.owners.len() + 1); - builder.provider.expectations -} + let push = + builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID)); -fn shallow_lint_levels_on(tcx: TyCtxt<'_>, hir_id: HirId) -> ShallowLintLevelMap { - let store = unerased_lint_store(tcx); - - let mut levels = LintLevelsBuilder { - sess: tcx.sess, - provider: LintLevelQueryMap { tcx, cur: hir_id, specs: ShallowLintLevelMap::default() }, - warn_about_weird_lints: false, - store, - registered_tools: &tcx.resolutions(()).registered_tools, - }; - - let is_crate = hir::CRATE_HIR_ID == hir_id; - if is_crate { - levels.add_command_line(); - } - debug!(?hir_id); - levels.add(tcx.hir().attrs(hir_id), is_crate, Some(hir_id)); + builder.levels.register_id(hir::CRATE_HIR_ID); + tcx.hir().walk_toplevel_module(&mut builder); + builder.levels.pop(push); - levels.provider.specs + builder.levels.update_unstable_expectation_ids(); + builder.levels.build_map() } -pub struct TopDown { +pub struct LintLevelsBuilder<'s> { + sess: &'s Session, + lint_expectations: Vec<(LintExpectationId, LintExpectation)>, + /// Each expectation has a stable and an unstable identifier. This map + /// is used to map from unstable to stable [`LintExpectationId`]s. + expectation_id_map: FxHashMap, sets: LintLevelSets, + id_to_set: FxHashMap, cur: LintStackIndex, -} - -pub trait LintLevelsProvider { - fn current_specs(&self) -> &FxHashMap; - fn current_specs_mut(&mut self) -> &mut FxHashMap; - fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource; - fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {} -} - -impl LintLevelsProvider for TopDown { - fn current_specs(&self) -> &FxHashMap { - &self.sets.list[self.cur].specs - } - - fn current_specs_mut(&mut self) -> &mut FxHashMap { - &mut self.sets.list[self.cur].specs - } - - fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource { - self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), sess) - } -} - -struct LintLevelQueryMap<'tcx> { - tcx: TyCtxt<'tcx>, - cur: HirId, - specs: ShallowLintLevelMap, -} - -impl LintLevelsProvider for LintLevelQueryMap<'_> { - fn current_specs(&self) -> &FxHashMap { - &self.specs.specs - } - fn current_specs_mut(&mut self) -> &mut FxHashMap { - &mut self.specs.specs - } - fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { - self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) - } -} - -struct QueryMapExpectationsWrapper<'tcx> { - tcx: TyCtxt<'tcx>, - cur: HirId, - specs: ShallowLintLevelMap, - expectations: Vec<(LintExpectationId, LintExpectation)>, - unstable_to_stable_ids: FxHashMap, -} - -impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { - fn current_specs(&self) -> &FxHashMap { - &self.specs.specs - } - fn current_specs_mut(&mut self) -> &mut FxHashMap { - self.specs.specs.clear(); - &mut self.specs.specs - } - fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { - self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) - } - fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) { - let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id else { bug!("unstable expectation id should already be mapped") }; - let key = LintExpectationId::Unstable { attr_id, lint_index: None }; - - if !self.unstable_to_stable_ids.contains_key(&key) { - self.unstable_to_stable_ids.insert( - key, - LintExpectationId::Stable { hir_id, attr_index, lint_index: None, attr_id: None }, - ); - } - - self.expectations.push((id.normalize(), expectation)); - } -} - -impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { - fn add_id(&mut self, hir_id: HirId) { - self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id)); - } -} - -impl<'tcx> intravisit::Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.provider.tcx.hir() - } - - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - self.add_id(param.hir_id); - intravisit::walk_param(self, param); - } - - fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - self.add_id(it.hir_id()); - intravisit::walk_item(self, it); - } - - fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { - self.add_id(it.hir_id()); - intravisit::walk_foreign_item(self, it); - } - - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { - // We will call `add_id` when we walk - // the `StmtKind`. The outer statement itself doesn't - // define the lint levels. - intravisit::walk_stmt(self, e); - } - - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { - self.add_id(e.hir_id); - intravisit::walk_expr(self, e); - } - - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { - self.add_id(s.hir_id); - intravisit::walk_field_def(self, s); - } - - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { - self.add_id(v.id); - intravisit::walk_variant(self, v); - } - - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - self.add_id(l.hir_id); - intravisit::walk_local(self, l); - } - - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { - self.add_id(a.hir_id); - intravisit::walk_arm(self, a); - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - self.add_id(trait_item.hir_id()); - intravisit::walk_trait_item(self, trait_item); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - self.add_id(impl_item.hir_id()); - intravisit::walk_impl_item(self, impl_item); - } -} - -pub struct LintLevelsBuilder<'s, P> { - sess: &'s Session, - provider: P, warn_about_weird_lints: bool, store: &'s LintStore, registered_tools: &'s RegisteredTools, } -pub(crate) struct BuilderPush { +pub struct BuilderPush { prev: LintStackIndex, + pub changed: bool, } -impl<'s> LintLevelsBuilder<'s, TopDown> { - pub(crate) fn new( +impl<'s> LintLevelsBuilder<'s> { + pub fn new( sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore, @@ -321,66 +75,20 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { ) -> Self { let mut builder = LintLevelsBuilder { sess, - provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE }, + lint_expectations: Default::default(), + expectation_id_map: Default::default(), + sets: LintLevelSets::new(), + cur: COMMAND_LINE, + id_to_set: Default::default(), warn_about_weird_lints, store, registered_tools, }; - builder.process_command_line(); - assert_eq!(builder.provider.sets.list.len(), 1); + builder.process_command_line(sess, store); + assert_eq!(builder.sets.list.len(), 1); builder } - fn process_command_line(&mut self) { - self.provider.cur = self - .provider - .sets - .list - .push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE }); - self.add_command_line(); - } - - /// Pushes a list of AST lint attributes onto this context. - /// - /// This function will return a `BuilderPush` object which should be passed - /// to `pop` when this scope for the attributes provided is exited. - /// - /// This function will perform a number of tasks: - /// - /// * It'll validate all lint-related attributes in `attrs` - /// * It'll mark all lint-related attributes as used - /// * Lint levels will be updated based on the attributes provided - /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to - /// `#[allow]` - /// - /// Don't forget to call `pop`! - pub(crate) fn push( - &mut self, - attrs: &[ast::Attribute], - is_crate_node: bool, - source_hir_id: Option, - ) -> BuilderPush { - let prev = self.provider.cur; - self.provider.cur = - self.provider.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); - - self.add(attrs, is_crate_node, source_hir_id); - - if self.provider.current_specs().is_empty() { - self.provider.sets.list.pop(); - self.provider.cur = prev; - } - - BuilderPush { prev } - } - - /// Called after `push` when the scope of a set of attributes are exited. - pub(crate) fn pop(&mut self, push: BuilderPush) { - self.provider.cur = push.prev; - } -} - -impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { pub(crate) fn sess(&self) -> &Session { self.sess } @@ -390,20 +98,24 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } fn current_specs(&self) -> &FxHashMap { - self.provider.current_specs() + &self.sets.list[self.cur].specs } fn current_specs_mut(&mut self) -> &mut FxHashMap { - self.provider.current_specs_mut() + &mut self.sets.list[self.cur].specs } - fn add_command_line(&mut self) { - for &(ref lint_name, level) in &self.sess.opts.lint_opts { - self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools); + fn process_command_line(&mut self, sess: &Session, store: &LintStore) { + self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); + + self.cur = + self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE }); + for &(ref lint_name, level) in &sess.opts.lint_opts { + store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools); let orig_level = level; let lint_flag_val = Symbol::intern(lint_name); - let Ok(ids) = self.store.find_lints(&lint_name) else { + let Ok(ids) = store.find_lints(&lint_name) else { // errors handled in check_lint_name_cmdline above continue }; @@ -426,11 +138,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful /// (e.g. if a forbid was already inserted on the same scope), then emits a /// diagnostic with no change to `specs`. - fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) { - let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess); - if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id { - *id = id.normalize(); - } + fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) { + let (old_level, old_src) = + self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess); // Setting to a non-forbid level is an error if the lint previously had // a forbid level. Note that this is not necessarily true even with a // `#[forbid(..)]` attribute present, as that is overridden by `--cap-lints`. @@ -448,7 +158,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let id_name = id.lint.name_lower(); let fcw_warning = match old_src { LintLevelSource::Default => false, - LintLevelSource::Node { name, .. } => self.store.is_lint_group(name), + LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), }; debug!( @@ -468,8 +178,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { id.to_string() )); } - LintLevelSource::Node { span, reason, .. } => { - diag.span_label(span, "`forbid` level set here"); + LintLevelSource::Node(_, forbid_source_span, reason) => { + diag.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { diag.note(rationale.as_str()); } @@ -489,8 +199,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { LintLevelSource::Default => { OverruledAttributeSub::DefaultSource { id: id.to_string() } } - LintLevelSource::Node { span, reason, .. } => { - OverruledAttributeSub::NodeSource { span, reason } + LintLevelSource::Node(_, forbid_source_span, reason) => { + OverruledAttributeSub::NodeSource { + span: forbid_source_span, + reason, + } } LintLevelSource::CommandLine(_, _) => { OverruledAttributeSub::CommandLineSource @@ -543,7 +256,29 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { }; } - fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option) { + /// Pushes a list of AST lint attributes onto this context. + /// + /// This function will return a `BuilderPush` object which should be passed + /// to `pop` when this scope for the attributes provided is exited. + /// + /// This function will perform a number of tasks: + /// + /// * It'll validate all lint-related attributes in `attrs` + /// * It'll mark all lint-related attributes as used + /// * Lint levels will be updated based on the attributes provided + /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to + /// `#[allow]` + /// + /// Don't forget to call `pop`! + pub(crate) fn push( + &mut self, + attrs: &[ast::Attribute], + is_crate_node: bool, + source_hir_id: Option, + ) -> BuilderPush { + let prev = self.cur; + self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev }); + let sess = self.sess; for (attr_index, attr) in attrs.iter().enumerate() { if attr.has_name(sym::automatically_derived) { @@ -558,17 +293,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { - let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id - else { bug!("stable id Level::from_attr") }; - - let stable_id = LintExpectationId::Stable { - hir_id, - attr_index: attr_index.try_into().unwrap(), - lint_index, - // we pass the previous unstable attr_id such that we can trace the ast id when building a map - // to go from unstable to stable id. - attr_id: Some(attr_id), - }; + let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index); Level::Expect(stable_id) } @@ -683,7 +408,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS), _ => false, }; - self.provider.push_expectation( + self.lint_expectations.push(( expect_id, LintExpectation::new( reason, @@ -691,19 +416,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { is_unfulfilled_lint_expectations, tool_name, ), - ); + )); } - let src = LintLevelSource::Node { - name: meta_item - .path - .segments - .last() - .expect("empty lint name") - .ident - .name, - span: sp, + let src = LintLevelSource::Node( + meta_item.path.segments.last().expect("empty lint name").ident.name, + sp, reason, - }; + ); for &id in *ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); @@ -716,26 +435,31 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { Ok(ids) => { let complete_name = &format!("{}::{}", tool_ident.unwrap().name, name); - let src = LintLevelSource::Node { - name: Symbol::intern(complete_name), - span: sp, + let src = LintLevelSource::Node( + Symbol::intern(complete_name), + sp, reason, - }; + ); for &id in ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); } } if let Level::Expect(expect_id) = level { - self.provider.push_expectation( + self.lint_expectations.push(( expect_id, LintExpectation::new(reason, sp, false, tool_name), - ); + )); } } Err((Some(ids), ref new_lint_name)) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (lvl, src) = self.provider.get_lint_level(lint, &sess); + let (lvl, src) = self.sets.get_lint_level( + lint, + self.cur, + Some(self.current_specs()), + &sess, + ); struct_lint_level( self.sess, lint, @@ -759,19 +483,19 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { }, ); - let src = LintLevelSource::Node { - name: Symbol::intern(&new_lint_name), - span: sp, + let src = LintLevelSource::Node( + Symbol::intern(&new_lint_name), + sp, reason, - }; + ); for id in ids { self.insert_spec(*id, (level, src)); } if let Level::Expect(expect_id) = level { - self.provider.push_expectation( + self.lint_expectations.push(( expect_id, LintExpectation::new(reason, sp, false, tool_name), - ); + )); } } Err((None, _)) => { @@ -797,7 +521,12 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { CheckLintNameResult::Warning(msg, renamed) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess); + let (renamed_lint_level, src) = self.sets.get_lint_level( + lint, + self.cur, + Some(self.current_specs()), + &sess, + ); struct_lint_level( self.sess, lint, @@ -820,7 +549,12 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } CheckLintNameResult::NoLint(suggestion) => { let lint = builtin::UNKNOWN_LINTS; - let (level, src) = self.provider.get_lint_level(lint, self.sess); + let (level, src) = self.sets.get_lint_level( + lint, + self.cur, + Some(self.current_specs()), + self.sess, + ); struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| { let name = if let Some(tool_ident) = tool_ident { format!("{}::{}", tool_ident.name, name) @@ -849,21 +583,17 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { if let CheckLintNameResult::Ok(ids) = self.store.check_lint_name(&new_name, None, self.registered_tools) { - let src = LintLevelSource::Node { - name: Symbol::intern(&new_name), - span: sp, - reason, - }; + let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason); for &id in ids { if self.check_gated_lint(id, attr.span) { self.insert_spec(id, (level, src)); } } if let Level::Expect(expect_id) = level { - self.provider.push_expectation( + self.lint_expectations.push(( expect_id, LintExpectation::new(reason, sp, false, tool_name), - ); + )); } } else { panic!("renamed lint does not exist: {}", new_name); @@ -878,12 +608,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; } - let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } = *src else { + let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else { continue }; let lint = builtin::UNUSED_ATTRIBUTES; - let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess); + let (lint_level, lint_src) = + self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess); struct_lint_level( self.sess, lint, @@ -903,13 +634,32 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { break; } } + + if self.current_specs().is_empty() { + self.sets.list.pop(); + self.cur = prev; + } + + BuilderPush { prev, changed: prev != self.cur } + } + + fn create_stable_id( + &mut self, + unstable_id: LintExpectationId, + hir_id: HirId, + attr_index: usize, + ) -> LintExpectationId { + let stable_id = + LintExpectationId::Stable { hir_id, attr_index: attr_index as u16, lint_index: None }; + + self.expectation_id_map.insert(unstable_id, stable_id); + + stable_id } /// Checks if the lint is gated on a feature that is not enabled. /// /// Returns `true` if the lint's feature is enabled. - // FIXME only emit this once for each attribute, instead of repeating it 4 times for - // pre-expansion lints, post-expansion lints, `shallow_lint_levels_on` and `lint_expectations`. fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool { if let Some(feature) = lint_id.lint.feature_gate { if !self.sess.features_untracked().enabled(feature) { @@ -928,14 +678,19 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { true } + /// Called after `push` when the scope of a set of attributes are exited. + pub fn pop(&mut self, push: BuilderPush) { + self.cur = push.prev; + } + /// Find the lint level for a lint. - pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource { - self.provider.get_lint_level(lint, self.sess) + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) { + self.sets.get_lint_level(lint, self.cur, None, self.sess) } /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. - pub(crate) fn struct_lint( + pub fn struct_lint( &self, lint: &'static Lint, span: Option, @@ -944,8 +699,141 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, span, decorate) } + + /// Registers the ID provided with the current set of lints stored in + /// this context. + pub fn register_id(&mut self, id: HirId) { + self.id_to_set.insert(id, self.cur); + } + + fn update_unstable_expectation_ids(&self) { + self.sess.diagnostic().update_unstable_expectation_id(&self.expectation_id_map); + } + + pub fn build_map(self) -> LintLevelMap { + LintLevelMap { + sets: self.sets, + id_to_set: self.id_to_set, + lint_expectations: self.lint_expectations, + } + } +} + +struct LintLevelMapBuilder<'tcx> { + levels: LintLevelsBuilder<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl LintLevelMapBuilder<'_> { + fn with_lint_attrs(&mut self, id: hir::HirId, f: F) + where + F: FnOnce(&mut Self), + { + let is_crate_hir = id == hir::CRATE_HIR_ID; + let attrs = self.tcx.hir().attrs(id); + let push = self.levels.push(attrs, is_crate_hir, Some(id)); + + if push.changed { + self.levels.register_id(id); + } + f(self); + self.levels.pop(push); + } +} + +impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + self.with_lint_attrs(param.hir_id, |builder| { + intravisit::walk_param(builder, param); + }); + } + + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + self.with_lint_attrs(it.hir_id(), |builder| { + intravisit::walk_item(builder, it); + }); + } + + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + self.with_lint_attrs(it.hir_id(), |builder| { + intravisit::walk_foreign_item(builder, it); + }) + } + + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + // We will call `with_lint_attrs` when we walk + // the `StmtKind`. The outer statement itself doesn't + // define the lint levels. + intravisit::walk_stmt(self, e); + } + + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + self.with_lint_attrs(e.hir_id, |builder| { + intravisit::walk_expr(builder, e); + }) + } + + fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_expr_field(builder, field); + }) + } + + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + self.with_lint_attrs(s.hir_id, |builder| { + intravisit::walk_field_def(builder, s); + }) + } + + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + self.with_lint_attrs(v.id, |builder| { + intravisit::walk_variant(builder, v); + }) + } + + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + self.with_lint_attrs(l.hir_id, |builder| { + intravisit::walk_local(builder, l); + }) + } + + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + self.with_lint_attrs(a.hir_id, |builder| { + intravisit::walk_arm(builder, a); + }) + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + self.with_lint_attrs(trait_item.hir_id(), |builder| { + intravisit::walk_trait_item(builder, trait_item); + }); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + self.with_lint_attrs(impl_item.hir_id(), |builder| { + intravisit::walk_impl_item(builder, impl_item); + }); + } + + fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { + self.with_lint_attrs(field.hir_id, |builder| { + intravisit::walk_pat_field(builder, field); + }) + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + self.with_lint_attrs(p.hir_id, |builder| { + intravisit::walk_generic_param(builder, p); + }); + } } -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers }; +pub fn provide(providers: &mut Providers) { + providers.lint_levels = lint_levels; } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c760e435699c6..752a751f6bcf5 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -35,7 +35,6 @@ #![feature(iter_order_by)] #![feature(let_chains)] #![cfg_attr(bootstrap, feature(let_else))] -#![feature(min_specialization)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cbe7afc8e5558..11b2d057a0769 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -92,7 +92,7 @@ pub enum LintExpectationId { /// stable and can be cached. The additional index ensures that nodes with /// several expectations can correctly match diagnostics to the individual /// expectation. - Stable { hir_id: HirId, attr_index: u16, lint_index: Option, attr_id: Option }, + Stable { hir_id: HirId, attr_index: u16, lint_index: Option }, } impl LintExpectationId { @@ -116,31 +116,13 @@ impl LintExpectationId { *lint_index = new_lint_index } - - /// Prepares the id for hashing. Removes references to the ast. - /// Should only be called when the id is stable. - pub fn normalize(self) -> Self { - match self { - Self::Stable { hir_id, attr_index, lint_index, .. } => { - Self::Stable { hir_id, attr_index, lint_index, attr_id: None } - } - Self::Unstable { .. } => { - unreachable!("`normalize` called when `ExpectationId` is unstable") - } - } - } } impl HashStable for LintExpectationId { #[inline] fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { match self { - LintExpectationId::Stable { - hir_id, - attr_index, - lint_index: Some(lint_index), - attr_id: _, - } => { + LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { hir_id.hash_stable(hcx, hasher); attr_index.hash_stable(hcx, hasher); lint_index.hash_stable(hcx, hasher); @@ -160,12 +142,9 @@ impl ToStableHashKey for LintExpectation #[inline] fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { match self { - LintExpectationId::Stable { - hir_id, - attr_index, - lint_index: Some(lint_index), - attr_id: _, - } => (*hir_id, *attr_index, *lint_index), + LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { + (*hir_id, *attr_index, *lint_index) + } _ => { unreachable!("HashStable should only be called for a filled `LintExpectationId`") } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index eded3b3eedc6c..1fa0c6bababe4 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -62,7 +62,7 @@ use crate::ty::TyCtxt; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::definitions::DefPathHash; -use rustc_hir::{HirId, ItemLocalId}; +use rustc_hir::HirId; use rustc_query_system::dep_graph::FingerprintStyle; use rustc_span::symbol::Symbol; use std::hash::Hash; @@ -280,7 +280,7 @@ impl DepNodeExt for DepNode { let kind = dep_kind_from_label_string(label)?; match kind.fingerprint_style(tcx) { - FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()), + FingerprintStyle::Opaque => Err(()), FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), FingerprintStyle::DefPathHash => { Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) @@ -408,7 +408,7 @@ impl<'tcx> DepNodeParams> for (DefId, DefId) { impl<'tcx> DepNodeParams> for HirId { #[inline(always)] fn fingerprint_style() -> FingerprintStyle { - FingerprintStyle::HirId + FingerprintStyle::Opaque } // We actually would not need to specialize the implementation of this @@ -417,36 +417,10 @@ impl<'tcx> DepNodeParams> for HirId { #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; - let def_path_hash = tcx.def_path_hash(owner.to_def_id()); - Fingerprint::new( - // `owner` is local, so is completely defined by the local hash - def_path_hash.local_hash(), - local_id.as_u32().into(), - ) - } - #[inline(always)] - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - let HirId { owner, local_id } = *self; - format!("{}.{}", tcx.def_path_str(owner.to_def_id()), local_id.as_u32()) - } + let def_path_hash = tcx.def_path_hash(owner.to_def_id()); + let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); - #[inline(always)] - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - if dep_node.kind.fingerprint_style(tcx) == FingerprintStyle::HirId { - let (local_hash, local_id) = Fingerprint::from(dep_node.hash).as_value(); - let def_path_hash = DefPathHash::new(tcx.sess.local_stable_crate_id(), local_hash); - let owner = tcx - .def_path_hash_to_def_id(def_path_hash, &mut || { - panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash) - }) - .expect_local(); - let local_id = local_id - .try_into() - .unwrap_or_else(|_| panic!("local id should be u32, found {:?}", local_id)); - Some(HirId { owner, local_id: ItemLocalId::from_u32(local_id) }) - } else { - None - } + def_path_hash.0.combine(local_id) } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 6873785ace739..d3cf519b633c7 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -22,6 +22,7 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::MemberConstraint; +use crate::mir::ConstraintCategory; use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_index::vec::IndexVec; @@ -301,8 +302,10 @@ impl<'tcx, V> Canonical<'tcx, V> { } } -pub type QueryOutlivesConstraint<'tcx> = - ty::Binder<'tcx, ty::OutlivesPredicate, Region<'tcx>>>; +pub type QueryOutlivesConstraint<'tcx> = ( + ty::Binder<'tcx, ty::OutlivesPredicate, Region<'tcx>>>, + ConstraintCategory<'tcx>, +); TrivialTypeTraversalAndLiftImpls! { for <'tcx> { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 4cb5ef7917774..2f45222de4728 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,19 +1,20 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan}; use rustc_hir::HirId; +use rustc_index::vec::IndexVec; +use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, - FutureIncompatibilityReason, Level, Lint, LintId, + FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, }; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind}; use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; -use crate::ty::TyCtxt; - /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] pub enum LintLevelSource { @@ -22,12 +23,7 @@ pub enum LintLevelSource { Default, /// Lint level was set by an attribute. - Node { - name: Symbol, - span: Span, - /// RFC 2383 reason - reason: Option, - }, + Node(Symbol, Span, Option /* RFC 2383 reason */), /// Lint level was set by a command-line flag. /// The provided `Level` is the level specified on the command line. @@ -39,7 +35,7 @@ impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { LintLevelSource::Default => symbol::kw::Default, - LintLevelSource::Node { name, .. } => name, + LintLevelSource::Node(name, _, _) => name, LintLevelSource::CommandLine(name, _) => name, } } @@ -47,7 +43,7 @@ impl LintLevelSource { pub fn span(&self) -> Span { match *self { LintLevelSource::Default => DUMMY_SP, - LintLevelSource::Node { span, .. } => span, + LintLevelSource::Node(_, span, _) => span, LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } @@ -56,115 +52,145 @@ impl LintLevelSource { /// A tuple of a lint level and its source. pub type LevelAndSource = (Level, LintLevelSource); -/// Return type for the `shallow_lint_levels_on` query. -/// -/// This map represents the set of allowed lints and allowance levels given -/// by the attributes for *a single HirId*. -#[derive(Default, Debug, HashStable)] -pub struct ShallowLintLevelMap { +#[derive(Debug, HashStable)] +pub struct LintLevelSets { + pub list: IndexVec, + pub lint_cap: Level, +} + +rustc_index::newtype_index! { + #[derive(HashStable)] + pub struct LintStackIndex { + const COMMAND_LINE = 0, + } +} + +#[derive(Debug, HashStable)] +pub struct LintSet { + // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which + // flag. pub specs: FxHashMap, + + pub parent: LintStackIndex, } -/// From an initial level and source, verify the effect of special annotations: -/// `warnings` lint level and lint caps. -/// -/// The return of this function is suitable for diagnostics. -pub fn reveal_actual_level( - level: Option, - src: &mut LintLevelSource, - sess: &Session, - lint: LintId, - probe_for_lint_level: impl FnOnce(LintId) -> (Option, LintLevelSource), -) -> Level { - // If `level` is none then we actually assume the default level for this lint. - let mut level = level.unwrap_or_else(|| lint.lint.default_level(sess.edition())); - - // If we're about to issue a warning, check at the last minute for any - // directives against the warnings "lint". If, for example, there's an - // `allow(warnings)` in scope then we want to respect that instead. - // - // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically - // triggers in cases (like #80988) where you have `forbid(warnings)`, - // and so if we turned that into an error, it'd defeat the purpose of the - // future compatibility warning. - if level == Level::Warn && lint != LintId::of(FORBIDDEN_LINT_GROUPS) { - let (warnings_level, warnings_src) = probe_for_lint_level(LintId::of(builtin::WARNINGS)); - if let Some(configured_warning_level) = warnings_level { - if configured_warning_level != Level::Warn { - level = configured_warning_level; - *src = warnings_src; +impl LintLevelSets { + pub fn new() -> Self { + LintLevelSets { list: IndexVec::new(), lint_cap: Level::Forbid } + } + + pub fn get_lint_level( + &self, + lint: &'static Lint, + idx: LintStackIndex, + aux: Option<&FxHashMap>, + sess: &Session, + ) -> LevelAndSource { + let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); + + // If `level` is none then we actually assume the default level for this + // lint. + let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition())); + + // If we're about to issue a warning, check at the last minute for any + // directives against the warnings "lint". If, for example, there's an + // `allow(warnings)` in scope then we want to respect that instead. + // + // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically + // triggers in cases (like #80988) where you have `forbid(warnings)`, + // and so if we turned that into an error, it'd defeat the purpose of the + // future compatibility warning. + if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) { + let (warnings_level, warnings_src) = + self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); + if let Some(configured_warning_level) = warnings_level { + if configured_warning_level != Level::Warn { + level = configured_warning_level; + src = warnings_src; + } } } - } - // Ensure that we never exceed the `--cap-lints` argument unless the source is a --force-warn - level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { - level - } else { - cmp::min(level, sess.opts.lint_cap.unwrap_or(Level::Forbid)) - }; + // Ensure that we never exceed the `--cap-lints` argument + // unless the source is a --force-warn + level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { + level + } else { + cmp::min(level, self.lint_cap) + }; + + if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) { + // Ensure that we never exceed driver level. + level = cmp::min(*driver_level, level); + } - if let Some(driver_level) = sess.driver_lint_caps.get(&lint) { - // Ensure that we never exceed driver level. - level = cmp::min(*driver_level, level); + (level, src) } - level -} - -impl ShallowLintLevelMap { - /// Perform a deep probe in the HIR tree looking for the actual level for the lint. - /// This lint level is not usable for diagnostics, it needs to be corrected by - /// `reveal_actual_level` beforehand. - fn probe_for_lint_level( + pub fn get_lint_id_level( &self, - tcx: TyCtxt<'_>, id: LintId, - start: HirId, + mut idx: LintStackIndex, + aux: Option<&FxHashMap>, ) -> (Option, LintLevelSource) { - if let Some(&(level, src)) = self.specs.get(&id) { - return (Some(level), src); + if let Some(specs) = aux { + if let Some(&(level, src)) = specs.get(&id) { + return (Some(level), src); + } } - - for (parent, _) in tcx.hir().parent_iter(start) { - let specs = tcx.shallow_lint_levels_on(parent); - if let Some(&(level, src)) = specs.specs.get(&id) { + loop { + let LintSet { ref specs, parent } = self.list[idx]; + if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } + if idx == COMMAND_LINE { + return (None, LintLevelSource::Default); + } + idx = parent; } - (None, LintLevelSource::Default) } +} + +#[derive(Debug)] +pub struct LintLevelMap { + /// This is a collection of lint expectations as described in RFC 2383, that + /// can be fulfilled during this compilation session. This means that at least + /// one expected lint is currently registered in the lint store. + /// + /// The [`LintExpectationId`] is stored as a part of the [`Expect`](Level::Expect) + /// lint level. + pub lint_expectations: Vec<(LintExpectationId, LintExpectation)>, + pub sets: LintLevelSets, + pub id_to_set: FxHashMap, +} - /// Fetch and return the user-visible lint level for the given lint at the given HirId. - pub fn lint_level_id_at_node( +impl LintLevelMap { + /// If the `id` was previously registered with `register_id` when building + /// this `LintLevelMap` this returns the corresponding lint level and source + /// of the lint level for the lint provided. + /// + /// If the `id` was not previously registered, returns `None`. If `None` is + /// returned then the parent of `id` should be acquired and this function + /// should be called again. + pub fn level_and_source( &self, - tcx: TyCtxt<'_>, - lint: LintId, + lint: &'static Lint, id: HirId, - ) -> (Level, LintLevelSource) { - let (level, mut src) = self.probe_for_lint_level(tcx, lint, id); - let level = reveal_actual_level(level, &mut src, tcx.sess, lint, |lint| { - self.probe_for_lint_level(tcx, lint, id) - }); - debug!(?id, ?level, ?src); - (level, src) + session: &Session, + ) -> Option { + self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session)) } } -impl TyCtxt<'_> { - /// Fetch and return the user-visible lint level for the given lint at the given HirId. - pub fn lint_level_at_node(self, lint: &'static Lint, id: HirId) -> (Level, LintLevelSource) { - self.shallow_lint_levels_on(id).lint_level_id_at_node(self, LintId::of(lint), id) - } +impl<'a> HashStable> for LintLevelMap { + #[inline] + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let LintLevelMap { ref sets, ref id_to_set, ref lint_expectations } = *self; - /// Walks upwards from `id` to find a node which might change lint levels with attributes. - /// It stops at `bound` and just returns it if reached. - pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { - let hir = self.hir(); - while id != bound && self.shallow_lint_levels_on(id).specs.is_empty() { - id = hir.get_parent_node(id) - } - id + id_to_set.hash_stable(hcx, hasher); + lint_expectations.hash_stable(hcx, hasher); + + hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher)) } } @@ -235,11 +261,11 @@ pub fn explain_lint_level_source( )); } } - LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(rationale.as_str()); } - err.span_note_once(span, "the lint level is defined here"); + err.span_note_once(src, "the lint level is defined here"); if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note_once(&format!( diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 594c14a642ded..d89efe2b3f024 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -327,7 +327,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] +#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, @@ -369,7 +369,7 @@ pub enum ConstraintCategory<'tcx> { } #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ReturnConstraint { Normal, ClosureUpvar(Field), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 53c254119f436..4b336ea62a99f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -274,14 +274,10 @@ rustc_queries! { separate_provide_extern } - query shallow_lint_levels_on(key: HirId) -> rustc_middle::lint::ShallowLintLevelMap { + query lint_levels(_: ()) -> LintLevelMap { arena_cache - desc { |tcx| "looking up lint levels for `{}`", key } - } - - query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> { - arena_cache - desc { "computing `#[expect]`ed lints in this crate" } + eval_always + desc { "computing the lint levels for items in this crate" } } query parent_module_from_def_id(key: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a95e6a61854cf..68a7af0b8c8d7 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -10,6 +10,7 @@ mod structural_impls; pub mod util; use crate::infer::canonical::Canonical; +use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; @@ -183,6 +184,16 @@ impl<'tcx> ObligationCause<'tcx> { variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into(); self } + + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { + match self.code() { + MatchImpl(cause, _) => cause.to_constraint_category(), + AscribeUserTypeProvePredicate(predicate_span) => { + ConstraintCategory::Predicate(*predicate_span) + } + _ => ConstraintCategory::BoringNoLocation, + } + } } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] @@ -418,6 +429,8 @@ pub enum ObligationCauseCode<'tcx> { is_lit: bool, output_ty: Option>, }, + + AscribeUserTypeProvePredicate(Span), } /// The 'location' at which we try to perform HIR-based wf checking. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4a9fbc5511c1d..0b497fa4afd33 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,7 +4,7 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKind, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::struct_lint_level; +use crate::lint::{struct_lint_level, LintLevelSource}; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; use crate::middle::stability; @@ -53,7 +53,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{CrateType, OutputFilenames}; use rustc_session::cstore::CrateStoreDyn; -use rustc_session::lint::Lint; +use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; use rustc_span::def_id::{DefPathHash, StableCrateId}; @@ -2812,6 +2812,44 @@ impl<'tcx> TyCtxt<'tcx> { iter.intern_with(|xs| self.intern_bound_variable_kinds(xs)) } + /// Walks upwards from `id` to find a node which might change lint levels with attributes. + /// It stops at `bound` and just returns it if reached. + pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { + let hir = self.hir(); + loop { + if id == bound { + return bound; + } + + if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { + return id; + } + let next = hir.get_parent_node(id); + if next == id { + bug!("lint traversal reached the root of the crate"); + } + id = next; + } + } + + pub fn lint_level_at_node( + self, + lint: &'static Lint, + mut id: hir::HirId, + ) -> (Level, LintLevelSource) { + let sets = self.lint_levels(()); + loop { + if let Some(pair) = sets.level_and_source(lint, id, self.sess) { + return pair; + } + let next = self.hir().get_parent_node(id); + if next == id { + bug!("lint traversal reached the root of the crate"); + } + id = next; + } + } + /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, /// typically generated by `#[derive(LintDiagnostic)]`). pub fn emit_spanned_lint( diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 36ea7946e9ae4..a300a8df23d28 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -1,6 +1,6 @@ use crate::dep_graph; use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintExpectation; +use crate::lint::LintLevelMap; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; @@ -44,14 +44,12 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; -use rustc_hir::hir_id::HirId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; -use rustc_session::lint::LintExpectationId; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f5fd1f6ffafce..84d6a8b975547 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -272,7 +272,10 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { type Lifted = Option; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self?).map(Some) + Some(match self { + Some(x) => Some(tcx.lift(x)?), + None => None, + }) } } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 7ab7870c4642f..784583d94ad74 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, UserTypeProjections::none(), &mut |this, _, _, _, node, span, _, _| { - this.storage_live_binding(block, node, span, OutsideGuard, false); + this.storage_live_binding(block, node, span, OutsideGuard, true); }, ); let failure = unpack!( diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 6ed5f1fc0d348..224a1b80fe24c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -75,7 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.source_info(then_expr.span) }; let (then_block, else_block) = - this.in_if_then_scope(condition_scope, |this| { + this.in_if_then_scope(condition_scope, then_expr.span, |this| { let then_blk = unpack!(this.then_else_break( block, &this.thir[cond], @@ -108,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Let { expr, ref pat } => { let scope = this.local_scope(); - let (true_block, false_block) = this.in_if_then_scope(scope, |this| { + let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| { this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span) }); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index e0727725f68d5..93f382cc65c3d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -371,6 +371,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(arm.span), Some(arm.scope), Some(match_scope), + false, ); if let Some(source_scope) = scope { @@ -416,6 +417,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span: Option, arm_scope: Option, match_scope: Option, + storages_alive: bool, ) -> BasicBlock { if candidate.subcandidates.is_empty() { // Avoid generating another `BasicBlock` when we only have one @@ -429,6 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span, match_scope, true, + storages_alive, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -466,6 +469,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span, match_scope, schedule_drops, + storages_alive, ); if arm_scope.is_none() { schedule_drops = false; @@ -641,6 +645,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + false, ) .unit() } @@ -1813,6 +1818,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + false, ); post_guard_block.unit() @@ -1836,6 +1842,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arm_span: Option, match_scope: Option, schedule_drops: bool, + storages_alive: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1971,7 +1978,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut guard_span = rustc_span::DUMMY_SP; let (post_guard_block, otherwise_post_guard_block) = - self.in_if_then_scope(match_scope, |this| match *guard { + self.in_if_then_scope(match_scope, guard_span, |this| match *guard { Guard::If(e) => { let e = &this.thir[e]; guard_span = e.span; @@ -2051,7 +2058,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } assert!(schedule_drops, "patterns with guards must schedule drops"); - self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings); + self.bind_matched_candidate_for_arm_body( + post_guard_block, + true, + by_value_bindings, + storages_alive, + ); post_guard_block } else { @@ -2065,6 +2077,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .flat_map(|(bindings, _)| bindings) .chain(&candidate.bindings), + storages_alive, ); block } @@ -2154,6 +2167,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, schedule_drops: bool, bindings: impl IntoIterator>, + storages_alive: bool, ) where 'tcx: 'b, { @@ -2163,13 +2177,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = self.storage_live_binding( - block, - binding.var_id, - binding.span, - OutsideGuard, - schedule_drops, - ); + let local = if storages_alive { + // Here storages are already alive, probably because this is a binding + // from let-else. + // We just need to schedule drop for the value. + self.var_local_id(binding.var_id, OutsideGuard).into() + } else { + self.storage_live_binding( + block, + binding.var_id, + binding.span, + OutsideGuard, + schedule_drops, + ) + }; if schedule_drops { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } @@ -2278,7 +2299,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern: &Pat<'tcx>, ) -> BlockAnd { let else_block_span = self.thir[else_block].span; - let (matching, failure) = self.in_if_then_scope(*let_else_scope, |this| { + let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| { let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); @@ -2300,6 +2321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + true, ); // This block is for the failure case let failure = this.bind_pattern( @@ -2311,6 +2333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, None, None, + true, ); this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span)); matching.unit() diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b2fd9f25bdde7..ff66ca5959202 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -466,9 +466,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); - let break_block = self.build_exit_tree(breakable_scope.break_drops, None); + let break_block = + self.build_exit_tree(breakable_scope.break_drops, region_scope, span, None); if let Some(drops) = breakable_scope.continue_drops { - self.build_exit_tree(drops, loop_block); + self.build_exit_tree(drops, region_scope, span, loop_block); } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, @@ -510,6 +511,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn in_if_then_scope( &mut self, region_scope: region::Scope, + span: Span, f: F, ) -> (BasicBlock, BasicBlock) where @@ -524,7 +526,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(if_then_scope.region_scope == region_scope); let else_block = self - .build_exit_tree(if_then_scope.else_drops, None) + .build_exit_tree(if_then_scope.else_drops, region_scope, span, None) .map_or_else(|| self.cfg.start_new_block(), |else_block_and| unpack!(else_block_and)); (then_block, else_block) @@ -997,10 +999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns the [DropIdx] for the innermost drop if the function unwound at /// this point. The `DropIdx` will be created if it doesn't already exist. fn diverge_cleanup(&mut self) -> DropIdx { - let is_generator = self.generator_kind.is_some(); - let (uncached_scope, mut cached_drop) = self - .scopes - .scopes + // It is okay to use dummy span because the getting scope index on the topmost scope + // must always succeed. + self.diverge_cleanup_target(self.scopes.topmost(), DUMMY_SP) + } + + /// This is similar to [diverge_cleanup](Self::diverge_cleanup) except its target is set to + /// some ancestor scope instead of the current scope. + /// It is possible to unwind to some ancestor scope if some drop panics as + /// the program breaks out of a if-then scope. + fn diverge_cleanup_target(&mut self, target_scope: region::Scope, span: Span) -> DropIdx { + let target = self.scopes.scope_index(target_scope, span); + let (uncached_scope, mut cached_drop) = self.scopes.scopes[..=target] .iter() .enumerate() .rev() @@ -1009,7 +1019,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .unwrap_or((0, ROOT_NODE)); - for scope in &mut self.scopes.scopes[uncached_scope..] { + if uncached_scope > target { + return cached_drop; + } + + let is_generator = self.generator_kind.is_some(); + for scope in &mut self.scopes.scopes[uncached_scope..=target] { for drop in &scope.drops { if is_generator || drop.kind == DropKind::Value { cached_drop = self.scopes.unwind_drops.add_drop(*drop, cached_drop); @@ -1222,21 +1237,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { fn build_exit_tree( &mut self, mut drops: DropTree, + else_scope: region::Scope, + span: Span, continue_block: Option, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); blocks[ROOT_NODE] = continue_block; drops.build_mir::(&mut self.cfg, &mut blocks); + let is_generator = self.generator_kind.is_some(); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = self.diverge_cleanup(); + let unwind_target = self.diverge_cleanup_target(else_scope, span); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { DropKind::Storage => { - if self.generator_kind.is_some() { + if is_generator { let unwind_drop = self .scopes .unwind_drops diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 53f33a7a0bad2..7a2a15a84a358 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -1066,32 +1066,32 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { let source_info = terminator.source_info; self.source_info = Some(source_info); self.super_terminator(terminator, location); + // Do NOT early return in this function, it does some crucial fixup of the state at the end! match &mut terminator.kind { TerminatorKind::Assert { expected, ref mut cond, .. } => { if let Some(ref value) = self.eval_operand(&cond) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(*expected); - let Ok(value_const) = self.ecx.read_scalar(&value) else { - // FIXME should be used use_ecx rather than a local match... but we have - // quite a few of these read_scalar/read_immediate that need fixing. - return - }; - if expected != value_const { - // Poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - Self::remove_const(&mut self.ecx, place.local); + // FIXME should be used use_ecx rather than a local match... but we have + // quite a few of these read_scalar/read_immediate that need fixing. + if let Ok(value_const) = self.ecx.read_scalar(&value) { + if expected != value_const { + // Poison all places this operand references so that further code + // doesn't use the invalid value + match cond { + Operand::Move(ref place) | Operand::Copy(ref place) => { + Self::remove_const(&mut self.ecx, place.local); + } + Operand::Constant(_) => {} + } + } else { + if self.should_const_prop(value) { + *cond = self.operand_from_scalar( + value_const, + self.tcx.types.bool, + source_info.span, + ); } - Operand::Constant(_) => {} - } - } else { - if self.should_const_prop(value) { - *cond = self.operand_from_scalar( - value_const, - self.tcx.types.bool, - source_info.span, - ); } } } diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 31de83ee1418d..49175e97f4171 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,7 +1,6 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::hir_id::HirId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; use rustc_middle::traits; @@ -544,19 +543,3 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { DUMMY_SP } } - -impl Key for HirId { - #[inline(always)] - fn query_crate_is_local(&self) -> bool { - true - } - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.hir().span(*self) - } - - #[inline(always)] - fn key_as_def_id(&self) -> Option { - None - } -} diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 6f3bd7762165c..342d95ca490ea 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -67,8 +67,6 @@ impl HasDepContext for T { pub enum FingerprintStyle { /// The fingerprint is actually a DefPathHash. DefPathHash, - /// The fingerprint is actually a HirId. - HirId, /// Query key was `()` or equivalent, so fingerprint is just zero. Unit, /// Some opaque hash. @@ -79,9 +77,7 @@ impl FingerprintStyle { #[inline] pub fn reconstructible(self) -> bool { match self { - FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => { - true - } + FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true, FingerprintStyle::Opaque => false, } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c3c9b0b561782..3c276a9ada97b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -173,7 +173,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { span, span_label: match res { Res::Def(kind, def_id) if kind == DefKind::TyParam => { - self.def_span(def_id).map(|span| (span, "found this type pararmeter")) + self.def_span(def_id).map(|span| (span, "found this type parameter")) } _ => None, }, 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 973cddbd179aa..13d9c160038f2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2256,7 +2256,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::QuestionMark | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse - | ObligationCauseCode::BinOp { .. } => {} + | ObligationCauseCode::BinOp { .. } + | ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index a4b540182280b..3008dfcadde9e 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -46,7 +46,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { /// Note that this may cause outlives obligations to be injected /// into the inference context with this body-id. /// - `ty`, the type that we are supposed to assume is WF. - #[instrument(level = "debug", skip(self, param_env, body_id))] + #[instrument(level = "debug", skip(self, param_env, body_id), ret)] fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, @@ -71,6 +71,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { let TypeOpOutput { output, constraints, .. } = result; if let Some(constraints) = constraints { + debug!(?constraints); // Instantiation may have produced new inference variables and constraints on those // variables. Process these constraints. let mut fulfill_cx = >::new(self.tcx); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 17afd325f03a2..40acabf622a54 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -48,10 +48,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { T: TypeFoldable<'tcx>, { debug!( - "normalize::<{}>(value={:?}, param_env={:?})", + "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})", std::any::type_name::(), value, self.param_env, + self.cause, ); if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index f6e196e31414c..18988861add13 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -23,7 +23,7 @@ impl CustomTypeOp { } } -impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp +impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp where F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible>, G: Fn() -> String, @@ -89,8 +89,8 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx.tcx, region_obligations .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())) + .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 578e1d00cf9ef..8a79165702ca3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -26,7 +26,7 @@ pub use rustc_middle::traits::query::type_op::*; /// extract out the resulting region constraints (or an error if it /// cannot be completed). pub trait TypeOp<'tcx>: Sized + fmt::Debug { - type Output; + type Output: fmt::Debug; type ErrorInfo; /// Processes the operation and all resulting obligations, diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index e3e78f70b15ef..691b79f10533d 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>( let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); let mut wf_args = vec![ty.into()]; - let mut implied_bounds = vec![]; + let mut outlives_bounds: Vec, ty::Region<'tcx>>> = + vec![]; let mut fulfill_cx = >::new(tcx); @@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>( // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) + // + // FIXME(@lcnr): It's not really "always fine", having fewer implied + // bounds can be backward incompatible, e.g. #101951 was caused by + // us not dealing with inference vars in `TypeOutlives` predicates. let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) .unwrap_or_default(); - // N.B., all of these predicates *ought* to be easily proven - // true. In fact, their correctness is (mostly) implied by - // other parts of the program. However, in #42552, we had - // an annoying scenario where: - // - // - Some `T::Foo` gets normalized, resulting in a - // variable `_1` and a `T: Trait` constraint - // (not sure why it couldn't immediately get - // solved). This result of `_1` got cached. - // - These obligations were dropped on the floor here, - // rather than being registered. - // - Then later we would get a request to normalize - // `T::Foo` which would result in `_1` being used from - // the cache, but hence without the `T: Trait` - // constraint. As a result, `_1` never gets resolved, - // and we get an ICE (in dropck). - // - // Therefore, we register any predicates involving - // inference variables. We restrict ourselves to those - // involving inference variables both for efficiency and - // to avoids duplicate errors that otherwise show up. + // While these predicates should all be implied by other parts of + // the program, they are still relevant as they may constrain + // inference variables, which is necessary to add the correct + // implied bounds in some cases, mostly when dealing with projections. fulfill_cx.register_predicate_obligations( infcx, obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(), @@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>( // From the full set of obligations, just filter down to the // region relationships. - implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { + outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| { assert!(!obligation.has_escaping_bound_vars()); match obligation.predicate.kind().no_bound_vars() { - None => vec![], + None => None, Some(pred) => match pred { ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) @@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![], + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); - vec![] + None } ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - vec![OutlivesBound::RegionSubRegion(r_b, r_a)] + Some(ty::OutlivesPredicate(r_a.into(), r_b)) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) + Some(ty::OutlivesPredicate(ty_a.into(), r_b)) } }, } @@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>( // Ensure that those obligations that we had to solve // get solved *here*. match fulfill_cx.select_all_or_error(infcx).as_slice() { - [] => Ok(implied_bounds), - _ => Err(NoSolution), + [] => (), + _ => return Err(NoSolution), } + + // We lazily compute the outlives components as + // `select_all_or_error` constrains inference variables. + let implied_bounds = outlives_bounds + .into_iter() + .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + ty::GenericArgKind::Type(ty_a) => { + let ty_a = infcx.resolve_vars_if_possible(ty_a); + let mut components = smallvec![]; + push_outlives_components(tcx, ty_a, &mut components); + implied_bounds_from_components(r_b, components) + } + ty::GenericArgKind::Const(_) => unreachable!(), + }) + .collect(); + + Ok(implied_bounds) } /// When we have an implied bound that `T: 'a`, we can further break diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 60e9b88107dd6..1bb6506b3678c 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngineExt as _; +use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ @@ -22,6 +22,7 @@ use rustc_trait_selection::traits::query::type_op::subtype::Subtype; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; use std::fmt; +use std::iter::zip; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -61,28 +62,32 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( mir_ty, def_id, user_substs ); - let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx }; - cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?; + let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx }; + cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?; Ok(()) } struct AscribeUserTypeCx<'me, 'tcx> { infcx: &'me InferCtxt<'me, 'tcx>, param_env: ParamEnv<'tcx>, + span: Span, fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { fn normalize(&mut self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID)) + } + + fn normalize_with_cause(&mut self, value: T, cause: ObligationCause<'tcx>) -> T where T: TypeFoldable<'tcx>, { self.infcx - .partially_normalize_associated_types_in( - ObligationCause::misc(DUMMY_SP, hir::CRATE_HIR_ID), - self.param_env, - value, - ) + .partially_normalize_associated_types_in(cause, self.param_env, value) .into_value_registering_obligations(self.infcx, self.fulfill_cx) } @@ -91,18 +96,13 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { T: ToTrace<'tcx>, { self.infcx - .at(&ObligationCause::dummy(), self.param_env) + .at(&ObligationCause::dummy_with_span(self.span), self.param_env) .relate(a, variance, b)? .into_value_registering_obligations(self.infcx, self.fulfill_cx); Ok(()) } - fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; + fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) { self.fulfill_cx.register_predicate_obligation( self.infcx, Obligation::new(cause, self.param_env, predicate), @@ -126,7 +126,6 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>, - span: Option, ) -> Result<(), NoSolution> { let UserSubsts { user_self_ty, substs } = user_substs; let tcx = self.tcx(); @@ -145,10 +144,22 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // outlives" error messages. let instantiated_predicates = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); + + let cause = ObligationCause::dummy_with_span(self.span); + debug!(?instantiated_predicates); - for instantiated_predicate in instantiated_predicates.predicates { - let instantiated_predicate = self.normalize(instantiated_predicate); - self.prove_predicate(instantiated_predicate, span); + for (instantiated_predicate, predicate_span) in + zip(instantiated_predicates.predicates, instantiated_predicates.spans) + { + let span = if self.span == DUMMY_SP { predicate_span } else { self.span }; + let cause = ObligationCause::new( + span, + hir::CRATE_HIR_ID, + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), + ); + let instantiated_predicate = + self.normalize_with_cause(instantiated_predicate, cause.clone()); + self.prove_predicate(instantiated_predicate, cause); } if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { @@ -161,7 +172,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) .to_predicate(self.tcx()), - span, + cause.clone(), ); } @@ -178,7 +189,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { // which...could happen with normalization... self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), - span, + cause, ); Ok(()) } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 6d2ba7c1c950b..4bf9562e23645 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -601,7 +601,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs } else { - self.create_substs_for_ast_path( + let (args, _) = self.create_substs_for_ast_path( span, item_def_id, parent_substs, @@ -609,8 +609,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.args(), item_segment.infer_args, None, - ) - .0 + ); + + let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args()); + if let Some(b) = assoc_bindings.first() { + Self::prohibit_assoc_ty_binding(self.tcx(), b.span); + } + + args } } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 0c6d8f26f1d63..59d591acdc445 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -140,6 +140,7 @@ pub(crate) fn compare_impl_method<'tcx>( /// /// Finally we register each of these predicates as an obligation and check that /// they hold. +#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))] fn compare_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &AssocItem, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index bc644c694a078..27b3da8ab3dfa 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -10,6 +10,7 @@ use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -663,7 +664,7 @@ fn ty_known_to_outlive<'tcx>( resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| { let origin = infer::RelateParamBound(DUMMY_SP, ty, None); let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env); - outlives.type_must_outlive(origin, ty, region); + outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation); }) } @@ -681,7 +682,12 @@ fn region_known_to_outlive<'tcx>( use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; let origin = infer::RelateRegionParamBound(DUMMY_SP); // `region_a: region_b` -> `region_b <= region_a` - infcx.push_sub_region_constraint(origin, region_b, region_a); + infcx.push_sub_region_constraint( + origin, + region_b, + region_a, + ConstraintCategory::BoringNoLocation, + ); }) } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 70e259b46bf20..a1d1f125f785c 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -333,7 +333,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { find_opaque_ty_constraints_for_tait(tcx, def_id) } // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => { + ItemKind::OpaqueTy(OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), + in_trait, + .. + }) => { if in_trait { span_bug!(item.span, "impl-trait in trait has no default") } else { @@ -378,7 +383,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure{..}, .. }) => tcx.typeck(def_id).node_type(hir_id), + Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => { + tcx.typeck(def_id).node_type(hir_id) + } Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { // We defer to `type_of` of the corresponding parameter @@ -410,40 +417,91 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, + | hir::InlineAsmOperand::SymFn { anon_const } => { + anon_const.hir_id == hir_id + } _ => false, }) => { tcx.typeck(def_id).node_type(hir_id) } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx - .adt_def(tcx.hir().get_parent_item(hir_id)) - .repr() - .discr_type() - .to_ty(tcx), + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) + } - Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) - if let Node::TraitRef(trait_ref) = tcx.hir().get( - tcx.hir().get_parent_node(binding_id) - ) => + Node::TypeBinding( + binding @ &TypeBinding { + hir_id: binding_id, + kind: TypeBindingKind::Equality { term: Term::Const(ref e) }, + .. + }, + ) if let Node::TraitRef(trait_ref) = + tcx.hir().get(tcx.hir().get_parent_node(binding_id)) + && e.hir_id == hir_id => { - let Some(trait_def_id) = trait_ref.trait_def_id() else { - return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); - }; - let assoc_items = tcx.associated_items(trait_def_id); - let assoc_item = assoc_items.find_by_name_and_kind( - tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), - ); - if let Some(assoc_item) = assoc_item { - tcx.type_of(assoc_item.def_id) - } else { - // FIXME(associated_const_equality): add a useful error message here. - tcx.ty_error_with_message( - DUMMY_SP, - "Could not find associated const on trait", - ) - } + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); + }; + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, + binding.ident, + ty::AssocKind::Const, + def_id.to_def_id(), + ); + if let Some(assoc_item) = assoc_item { + tcx.type_of(assoc_item.def_id) + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message( + DUMMY_SP, + "Could not find associated const on trait", + ) + } + } + + Node::TypeBinding( + binding @ &TypeBinding { hir_id: binding_id, gen_args, ref kind, .. }, + ) if let Node::TraitRef(trait_ref) = + tcx.hir().get(tcx.hir().get_parent_node(binding_id)) + && let Some((idx, _)) = + gen_args.args.iter().enumerate().find(|(_, arg)| { + if let GenericArg::Const(ct) = arg { + ct.value.hir_id == hir_id + } else { + false + } + }) => + { + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); + }; + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, + binding.ident, + match kind { + // I think `` type bindings requires that `A` is a type + TypeBindingKind::Constraint { .. } + | TypeBindingKind::Equality { term: Term::Ty(..) } => { + ty::AssocKind::Type + } + TypeBindingKind::Equality { term: Term::Const(..) } => { + ty::AssocKind::Const + } + }, + def_id.to_def_id(), + ); + if let Some(assoc_item) = assoc_item { + tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id) + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message( + DUMMY_SP, + "Could not find associated const on trait", + ) + } } Node::GenericParam(&GenericParam { @@ -452,8 +510,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .. }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)), - x => - tcx.ty_error_with_message( + x => tcx.ty_error_with_message( DUMMY_SP, &format!("unexpected const parent in type_of(): {x:?}"), ), diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 63715a6b86b97..5e5399acc1b0f 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -215,8 +215,6 @@ impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> { } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] -impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {} -#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 40885417308b8..a6fe07873d7ee 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -137,9 +137,11 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(target_os = "macos")] mod imp { - use crate::io; + use crate::fs::File; + use crate::io::Read; + use crate::sys::os::errno; use crate::sys::weak::weak; use libc::{c_int, c_void, size_t}; @@ -153,7 +155,7 @@ mod imp { for s in v.chunks_mut(256) { let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) }; if ret == -1 { - panic!("unexpected getentropy error: {}", io::Error::last_os_error()); + panic!("unexpected getentropy error: {}", errno()); } } true @@ -161,64 +163,14 @@ mod imp { .unwrap_or(false) } - #[cfg(target_os = "macos")] - fn fallback_fill_bytes(v: &mut [u8]) { - use crate::fs::File; - use crate::io::Read; - - let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); - file.read_exact(v).expect("failed to read /dev/urandom") - } - - // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with - // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded - // from `/dev/random` and which runs on its own thread accessed via GCD. - // - // This is very heavyweight compared to the alternatives, but they may not be usable: - // - `getentropy` was added in iOS 10, but we support a minimum of iOS 7 - // - `/dev/urandom` is not accessible inside the iOS app sandbox. - // - // Therefore `SecRandomCopyBytes` is only used on older iOS versions where no - // better options are present. - #[cfg(target_os = "ios")] - fn fallback_fill_bytes(v: &mut [u8]) { - use crate::ptr; - - enum SecRandom {} - - #[allow(non_upper_case_globals)] - const kSecRandomDefault: *const SecRandom = ptr::null(); - - extern "C" { - fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int; - } - - let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); - } - } - - // All supported versions of watchOS (>= 5) have support for `getentropy`. - #[cfg(target_os = "watchos")] - #[cold] - fn fallback_fill_bytes(_: &mut [u8]) { - unreachable!() - } - pub fn fill_bytes(v: &mut [u8]) { if getentropy_fill_bytes(v) { return; } - // Older macOS versions (< 10.12) don't support `getentropy`. Fallback to - // reading from `/dev/urandom` on these systems. - // - // Older iOS versions (< 10) don't support it either. Fallback to - // `SecRandomCopyBytes` on these systems. On watchOS, this is unreachable - // because the minimum supported version is 5 while `getentropy` became accessible - // in 3. - fallback_fill_bytes(v) + // for older macos which doesn't support getentropy + let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); + file.read_exact(v).expect("failed to read /dev/urandom") } } @@ -237,6 +189,36 @@ mod imp { } } +// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with +// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded +// from `/dev/random` and which runs on its own thread accessed via GCD. +// This seems needlessly heavyweight for the purposes of generating two u64s +// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is +// only used on iOS where direct access to `/dev/urandom` is blocked by the +// sandbox. +#[cfg(any(target_os = "ios", target_os = "watchos"))] +mod imp { + use crate::io; + use crate::ptr; + use libc::{c_int, size_t}; + + enum SecRandom {} + + #[allow(non_upper_case_globals)] + const kSecRandomDefault: *const SecRandom = ptr::null(); + + extern "C" { + fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int; + } + + pub fn fill_bytes(v: &mut [u8]) { + let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) }; + if ret == -1 { + panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); + } + } +} + #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] mod imp { use crate::ptr; diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index f7ab6bf93fb7e..c13e83f6c8612 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -436,43 +436,6 @@ impl Step for StdLink { let libdir = builder.sysroot_libdir(target_compiler, target); let hostdir = builder.sysroot_libdir(target_compiler, compiler.host); add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); - - if compiler.stage == 0 { - // special handling for stage0, to make `rustup toolchain link` and `x dist --stage 0` - // work for stage0-sysroot - - // copy bin files from stage0/bin to stage0-sysroot/bin - let sysroot = builder.out.join(&compiler.host.triple).join("stage0-sysroot"); - - let host = compiler.host.triple; - let stage0_bin_dir = builder.out.join(&host).join("stage0/bin"); - let sysroot_bin_dir = sysroot.join("bin"); - t!(fs::create_dir_all(&sysroot_bin_dir)); - builder.cp_r(&stage0_bin_dir, &sysroot_bin_dir); - - // copy all *.so files from stage0/lib to stage0-sysroot/lib - let stage0_lib_dir = builder.out.join(&host).join("stage0/lib"); - if let Ok(files) = fs::read_dir(&stage0_lib_dir) { - for file in files { - let file = t!(file); - let path = file.path(); - if path.is_file() && is_dylib(&file.file_name().into_string().unwrap()) { - builder.copy(&path, &sysroot.join("lib").join(path.file_name().unwrap())); - } - } - } - - // copy codegen-backends from stage0 - let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler); - t!(fs::create_dir_all(&sysroot_codegen_backends)); - let stage0_codegen_backends = builder - .out - .join(&host) - .join("stage0/lib/rustlib") - .join(&host) - .join("codegen-backends"); - builder.cp_r(&stage0_codegen_backends, &sysroot_codegen_backends); - } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3995c9fdb01b2..bb35970eb1ba5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -241,6 +241,51 @@ pre.rust a, color: var(--main-color); } +.content span.enum, .content a.enum, +.content span.struct, .content a.struct, +.content span.union, .content a.union, +.content span.primitive, .content a.primitive, +.content span.type, .content a.type, +.content span.foreigntype, .content a.foreigntype { + color: var(--type-link-color); +} + +.content span.trait, .content a.trait, +.content span.traitalias, .content a.traitalias { + color: var(--trait-link-color); +} + +.content span.associatedtype, .content a.associatedtype, +.content span.constant, .content a.constant, +.content span.static, .content a.static { + color: var(--assoc-item-link-color); +} + +.content span.fn, .content a.fn, +.content .fnname, +.content span.method, .content a.method, +.content span.tymethod, .content a.tymethod { + color: var(--function-link-color); +} + +.content span.attr, .content a.attr, +.content span.derive, .content a.derive, +.content span.macro, .content a.macro { + color: var(--macro-link-color); +} + +.content span.mod, .content a.mod, .block a.current.mod { + color: var(--mod-link-color); +} + +.content span.keyword, .content a.keyword { + color: var(--keyword-link-color); +} + +a { + color: var(--link-color); +} + ol, ul { padding-left: 24px; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index c292a8a7ef70b..e7a898e9fa62c 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -27,6 +27,14 @@ Original by Dempfi (https://github.com/dempfi/ayu) --codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-color: rgba(255, 142, 0, .6); + --type-link-color: #ffa0a5; + --trait-link-color: #39afd7; + --assoc-item-link-color: #39afd7; + --function-link-color: #fdd687; + --macro-link-color: #a37acc; + --keyword-link-color: #39afd7; + --mod-link-color: #39afd7; + --link-color: #39afd7; } .slider { @@ -111,44 +119,12 @@ pre, .rustdoc.source .example-wrap { .content .item-info::before { color: #ccc; } -.content span.foreigntype, .content a.foreigntype { color: #ffa0a5; } -.content span.union, .content a.union { color: #ffa0a5; } -.content span.constant, .content a.constant, -.content span.static, .content a.static { color: #39AFD7; } -.content span.primitive, .content a.primitive { color: #ffa0a5; } -.content span.traitalias, .content a.traitalias { color: #39AFD7; } -.content span.keyword, .content a.keyword { color: #39AFD7; } -.content span.mod, .content a.mod { - color: #39AFD7; -} -.content span.struct, .content a.struct { - color: #ffa0a5; -} -.content span.enum, .content a.enum { - color: #ffa0a5; -} -.content span.trait, .content a.trait { - color: #39AFD7; -} -.content span.type, .content a.type { color: #39AFD7; } -.content span.associatedtype, .content a.associatedtype { color: #39AFD7; } -.content span.fn, .content a.fn, -.content .fnname { color: #fdd687; } -.content span.attr, .content a.attr, .content span.derive, -.content a.derive, .content span.macro, .content a.macro { - color: #a37acc; -} - .sidebar a { color: #53b1db; } .sidebar a.current.type { color: #53b1db; } pre.rust .comment { color: #788797; } pre.rust .doccomment { color: #a1ac88; } -a { - color: #39AFD7; -} - .sidebar h2 a, .sidebar h3 a { color: white; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 68542d3305ca0..07a1ed8b7db74 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -22,6 +22,14 @@ --codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-color: rgba(255, 142, 0, .6); + --type-link-color: #2dbfb8; + --trait-link-color: #b78cf2; + --assoc-item-link-color: #d2991d; + --function-link-color: #2bab63; + --macro-link-color: #09bd00; + --keyword-link-color: #d2991d; + --mod-link-color: #d2991d; + --link-color: #d2991d; } .slider { @@ -83,25 +91,6 @@ a.result-keyword:focus { background-color: #884719; } .content .item-info::before { color: #ccc; } -.content span.enum, .content a.enum { color: #2dbfb8; } -.content span.struct, .content a.struct { color: #2dbfb8; } -.content span.type, .content a.type { color: #2dbfb8; } -.content span.associatedtype, .content a.associatedtype { color: #D2991D; } -.content span.foreigntype, .content a.foreigntype { color: #2dbfb8; } -.content span.attr, .content a.attr, -.content span.derive, .content a.derive, -.content span.macro, .content a.macro { color: #09bd00; } -.content span.union, .content a.union { color: #2dbfb8; } -.content span.constant, .content a.constant, -.content span.static, .content a.static { color: #D2991D; } -.content span.primitive, .content a.primitive { color: #2dbfb8; } -.content span.mod, .content a.mod { color: #D2991D; } -.content span.trait, .content a.trait { color: #b78cf2; } -.content span.traitalias, .content a.traitalias { color: #b78cf2; } -.content span.fn, .content a.fn, -.content .fnname { color: #2BAB63; } -.content span.keyword, .content a.keyword { color: #D2991D; } - .sidebar a { color: #fdbf35; } .sidebar a.current.enum { color: #12ece2; } .sidebar a.current.struct { color: #12ece2; } @@ -122,10 +111,6 @@ a.result-keyword:focus { background-color: #884719; } pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } -a { - color: #D2991D; -} - body.source .example-wrap pre.rust a { background: #333; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 0b7d1600e7aa4..64335f6292801 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -22,6 +22,14 @@ --codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-color: rgba(255, 142, 0, .6); + --type-link-color: #ad378a; + --trait-link-color: #6e4fc9; + --assoc-item-link-color: #3873ad; + --function-link-color: #ad7c37; + --macro-link-color: #068000; + --keyword-link-color: #3873ad; + --mod-link-color: #3873ad; + --link-color: #3873ad; } .slider { @@ -82,25 +90,6 @@ a.result-keyword:focus { background-color: #afc6e4; } .content .item-info::before { color: #ccc; } -.content span.enum, .content a.enum { color: #AD378A; } -.content span.struct, .content a.struct { color: #AD378A; } -.content span.type, .content a.type { color: #AD378A; } -.content span.associatedtype, .content a.associatedtype { color: #3873AD; } -.content span.foreigntype, .content a.foreigntype { color: #3873AD; } -.content span.attr, .content a.attr, -.content span.derive, .content a.derive, -.content span.macro, .content a.macro { color: #068000; } -.content span.union, .content a.union { color: #AD378A; } -.content span.constant, .content a.constant, -.content span.static, .content a.static { color: #3873AD; } -.content span.primitive, .content a.primitive { color: #AD378A; } -.content span.mod, .content a.mod { color: #3873AD; } -.content span.trait, .content a.trait { color: #6E4FC9; } -.content span.traitalias, .content a.traitalias { color: #5137AD; } -.content span.fn, .content a.fn, -.content .fnname { color: #AD7C37; } -.content span.keyword, .content a.keyword { color: #3873AD; } - .sidebar a { color: #356da4; } .sidebar a.current.enum { color: #a63283; } .sidebar a.current.struct { color: #a63283; } @@ -118,10 +107,6 @@ a.result-keyword:focus { background-color: #afc6e4; } .sidebar a.current.fn { color: #a67736; } .sidebar a.current.keyword { color: #356da4; } -a { - color: #3873AD; -} - body.source .example-wrap pre.rust a { background: #eee; } diff --git a/src/test/mir-opt/issue-101867.rs b/src/test/mir-opt/issue-101867.rs new file mode 100644 index 0000000000000..931396e2171f0 --- /dev/null +++ b/src/test/mir-opt/issue-101867.rs @@ -0,0 +1,9 @@ +#![cfg_attr(bootstrap, feature(let_else))] + +// EMIT_MIR issue_101867.main.mir_map.0.mir +fn main() { + let x: Option = Some(1); + let Some(y) = x else { + panic!(); + }; +} diff --git a/src/test/mir-opt/issue-101973.rs b/src/test/mir-opt/issue-101973.rs new file mode 100644 index 0000000000000..216659a235ef7 --- /dev/null +++ b/src/test/mir-opt/issue-101973.rs @@ -0,0 +1,20 @@ +// compile-flags: -O -C debug-assertions=on +// This needs inlining followed by ConstProp to reproduce, so we cannot use "unit-test". + +#[inline] +pub fn imm8(x: u32) -> u32 { + let mut out = 0u32; + out |= (x >> 0) & 0xff; + out +} + +// EMIT_MIR issue_101973.inner.ConstProp.diff +#[inline(never)] +pub fn inner(fields: u32) -> i64 { + imm8(fields).rotate_right(((fields >> 8) & 0xf) << 1) as i32 as i64 +} + +fn main() { + let val = inner(0xe32cf20f); + assert_eq!(val as u64, 0xfffffffff0000000); +} diff --git a/src/test/mir-opt/issue_101867.main.mir_map.0.mir b/src/test/mir-opt/issue_101867.main.mir_map.0.mir new file mode 100644 index 0000000000000..98501ac8c9d84 --- /dev/null +++ b/src/test/mir-opt/issue_101867.main.mir_map.0.mir @@ -0,0 +1,75 @@ +// MIR for `main` 0 mir_map + +| User Type Annotations +| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue-101867.rs:+0:11: +0:11 + let _1: std::option::Option as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-101867.rs:+1:9: +1:10 + let mut _2: !; // in scope 0 at $DIR/issue-101867.rs:+2:26: +4:6 + let _3: (); // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL + let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL + let mut _6: isize; // in scope 0 at $DIR/issue-101867.rs:+2:9: +2:16 + scope 1 { + debug x => _1; // in scope 1 at $DIR/issue-101867.rs:+1:9: +1:10 + let _5: u8; // in scope 1 at $DIR/issue-101867.rs:+2:14: +2:15 + scope 2 { + debug y => _5; // in scope 2 at $DIR/issue-101867.rs:+2:14: +2:15 + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10 + _1 = Option::::Some(const 1_u8); // scope 0 at $DIR/issue-101867.rs:+1:25: +1:32 + FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10 + AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-101867.rs:+1:12: +1:22 + StorageLive(_5); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15 + FakeRead(ForMatchedPlace(None), _1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20 + _6 = discriminant(_1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20 + switchInt(move _6) -> [1_isize: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16 + } + + bb1: { + StorageLive(_3); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + StorageLive(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + _4 = begin_panic::<&str>(const "explicit panic") -> bb7; // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/panic.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value() } + // mir::Constant + // + span: $SRC_DIR/std/src/panic.rs:LL:COL + // + literal: Const { ty: &str, val: Value(Slice(..)) } + } + + bb2: { + StorageDead(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL + StorageDead(_3); // scope 1 at $DIR/issue-101867.rs:+3:16: +3:17 + unreachable; // scope 1 at $DIR/issue-101867.rs:+2:26: +4:6 + } + + bb3: { + goto -> bb6; // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20 + } + + bb4: { + falseEdge -> [real: bb5, imaginary: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16 + } + + bb5: { + _5 = ((_1 as Some).0: u8); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15 + _0 = const (); // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2 + StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2 + StorageDead(_1); // scope 0 at $DIR/issue-101867.rs:+5:1: +5:2 + return; // scope 0 at $DIR/issue-101867.rs:+5:2: +5:2 + } + + bb6: { + StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2 + goto -> bb1; // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2 + } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/issue-101867.rs:+0:1: +5:2 + } +} diff --git a/src/test/mir-opt/issue_101973.inner.ConstProp.diff b/src/test/mir-opt/issue_101973.inner.ConstProp.diff new file mode 100644 index 0000000000000..89733a9a2cb7c --- /dev/null +++ b/src/test/mir-opt/issue_101973.inner.ConstProp.diff @@ -0,0 +1,100 @@ +- // MIR for `inner` before ConstProp ++ // MIR for `inner` after ConstProp + + fn inner(_1: u32) -> i64 { + debug fields => _1; // in scope 0 at $DIR/issue-101973.rs:+0:14: +0:20 + let mut _0: i64; // return place in scope 0 at $DIR/issue-101973.rs:+0:30: +0:33 + let mut _2: i32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:65 + let mut _3: u32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:58 + let mut _4: u32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:17 + let mut _5: u32; // in scope 0 at $DIR/issue-101973.rs:+1:10: +1:16 + let mut _6: u32; // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + let mut _7: u32; // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:52 + let mut _8: u32; // in scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + let mut _9: u32; // in scope 0 at $DIR/issue-101973.rs:+1:33: +1:39 + let mut _10: (u32, bool); // in scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + let mut _11: (u32, bool); // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + scope 1 (inlined imm8) { // at $DIR/issue-101973.rs:14:5: 14:17 + debug x => _5; // in scope 1 at $DIR/issue-101973.rs:5:13: 5:14 + let mut _12: u32; // in scope 1 at $DIR/issue-101973.rs:7:12: 7:27 + let mut _13: u32; // in scope 1 at $DIR/issue-101973.rs:7:12: 7:20 + let mut _14: u32; // in scope 1 at $DIR/issue-101973.rs:7:13: 7:14 + let mut _15: (u32, bool); // in scope 1 at $DIR/issue-101973.rs:7:12: 7:20 + scope 2 { + debug out => _4; // in scope 2 at $DIR/issue-101973.rs:6:9: 6:16 + } + } + scope 3 (inlined core::num::::rotate_right) { // at $DIR/issue-101973.rs:14:5: 14:58 + debug self => _4; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + debug n => _6; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + let mut _16: u32; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + let mut _17: u32; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:65 + StorageLive(_3); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:58 + StorageLive(_4); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:17 + StorageLive(_5); // scope 0 at $DIR/issue-101973.rs:+1:10: +1:16 + _5 = _1; // scope 0 at $DIR/issue-101973.rs:+1:10: +1:16 + _4 = const 0_u32; // scope 1 at $DIR/issue-101973.rs:6:19: 6:23 + StorageLive(_12); // scope 2 at $DIR/issue-101973.rs:7:12: 7:27 + StorageLive(_13); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20 + StorageLive(_14); // scope 2 at $DIR/issue-101973.rs:7:13: 7:14 + _14 = _5; // scope 2 at $DIR/issue-101973.rs:7:13: 7:14 + _15 = CheckedShr(_14, const 0_i32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20 + assert(!move (_15.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue-101973.rs:7:12: 7:20 + } + + bb1: { + _8 = move (_10.0: u32); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + StorageDead(_9); // scope 0 at $DIR/issue-101973.rs:+1:44: +1:45 + _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:52 + StorageDead(_8); // scope 0 at $DIR/issue-101973.rs:+1:51: +1:52 + _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + assert(!move (_11.1: bool), "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + } + + bb2: { + _6 = move (_11.0: u32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + StorageDead(_7); // scope 0 at $DIR/issue-101973.rs:+1:56: +1:57 + StorageLive(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _16 = _4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + StorageLive(_17); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _17 = _6; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _3 = rotate_right::(move _16, move _17) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::}, val: Value() } + } + + bb3: { + _13 = move (_15.0: u32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20 + StorageDead(_14); // scope 2 at $DIR/issue-101973.rs:7:19: 7:20 + _12 = BitAnd(move _13, const 255_u32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:27 + StorageDead(_13); // scope 2 at $DIR/issue-101973.rs:7:26: 7:27 + _4 = BitOr(_4, move _12); // scope 2 at $DIR/issue-101973.rs:7:5: 7:27 + StorageDead(_12); // scope 2 at $DIR/issue-101973.rs:7:26: 7:27 + StorageDead(_5); // scope 0 at $DIR/issue-101973.rs:+1:16: +1:17 + StorageLive(_6); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57 + StorageLive(_7); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:52 + StorageLive(_8); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + StorageLive(_9); // scope 0 at $DIR/issue-101973.rs:+1:33: +1:39 + _9 = _1; // scope 0 at $DIR/issue-101973.rs:+1:33: +1:39 + _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45 + } + + bb4: { + StorageDead(_17); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + StorageDead(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + StorageDead(_6); // scope 0 at $DIR/issue-101973.rs:+1:57: +1:58 + StorageDead(_4); // scope 0 at $DIR/issue-101973.rs:+1:57: +1:58 + _2 = move _3 as i32 (Misc); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:65 + StorageDead(_3); // scope 0 at $DIR/issue-101973.rs:+1:64: +1:65 + _0 = move _2 as i64 (Misc); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:72 + StorageDead(_2); // scope 0 at $DIR/issue-101973.rs:+1:71: +1:72 + return; // scope 0 at $DIR/issue-101973.rs:+2:2: +2:2 + } + } + diff --git a/src/test/rustdoc-gui/links-color.goml b/src/test/rustdoc-gui/links-color.goml new file mode 100644 index 0000000000000..69c5b4a6733a8 --- /dev/null +++ b/src/test/rustdoc-gui/links-color.goml @@ -0,0 +1,85 @@ +// This test checks links colors. +goto: file://|DOC_PATH|/test_docs/index.html + +// This is needed so that the text color is computed. +show-text: true + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: (".item-table .mod", {"color": "rgb(57, 175, 215)"}, ALL) +assert-css: (".item-table .macro", {"color": "rgb(163, 122, 204)"}, ALL) +assert-css: (".item-table .struct", {"color": "rgb(255, 160, 165)"}, ALL) +assert-css: (".item-table .enum", {"color": "rgb(255, 160, 165)"}, ALL) +assert-css: (".item-table .trait", {"color": "rgb(57, 175, 215)"}, ALL) +assert-css: (".item-table .fn", {"color": "rgb(253, 214, 135)"}, ALL) +assert-css: (".item-table .type", {"color": "rgb(255, 160, 165)"}, ALL) +assert-css: (".item-table .union", {"color": "rgb(255, 160, 165)"}, ALL) +assert-css: (".item-table .keyword", {"color": "rgb(57, 175, 215)"}, ALL) + +assert-css: ( + ".sidebar-elems a:not(.current)", + {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)", "font-weight": "400"}, + ALL, +) +assert-css: ( + ".sidebar-elems a.current", + {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)", "font-weight": "500"}, + ALL, +) + + +// Dark theme +local-storage: {"rustdoc-theme": "dark"} +reload: + +assert-css: (".item-table .mod", {"color": "rgb(210, 153, 29)"}, ALL) +assert-css: (".item-table .macro", {"color": "rgb(9, 189, 0)"}, ALL) +assert-css: (".item-table .struct", {"color": "rgb(45, 191, 184)"}, ALL) +assert-css: (".item-table .enum", {"color": "rgb(45, 191, 184)"}, ALL) +assert-css: (".item-table .trait", {"color": "rgb(183, 140, 242)"}, ALL) +assert-css: (".item-table .fn", {"color": "rgb(43, 171, 99)"}, ALL) +assert-css: (".item-table .type", {"color": "rgb(45, 191, 184)"}, ALL) +assert-css: (".item-table .union", {"color": "rgb(45, 191, 184)"}, ALL) +assert-css: (".item-table .keyword", {"color": "rgb(210, 153, 29)"}, ALL) + +assert-css: ( + ".sidebar-elems a:not(.current)", + {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)", "font-weight": "400"}, + ALL, +) +assert-css: ( + ".sidebar-elems a.current", + {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)", "font-weight": "500"}, + ALL, +) + + +// Light theme +local-storage: {"rustdoc-theme": "light"} +reload: + +assert-css: (".item-table .mod", {"color": "rgb(56, 115, 173)"}, ALL) +assert-css: (".item-table .macro", {"color": "rgb(6, 128, 0)"}, ALL) +assert-css: (".item-table .struct", {"color": "rgb(173, 55, 138)"}, ALL) +assert-css: (".item-table .enum", {"color": "rgb(173, 55, 138)"}, ALL) +assert-css: (".item-table .trait", {"color": "rgb(110, 79, 201)"}, ALL) +assert-css: (".item-table .fn", {"color": "rgb(173, 124, 55)"}, ALL) +assert-css: (".item-table .type", {"color": "rgb(173, 55, 138)"}, ALL) +assert-css: (".item-table .union", {"color": "rgb(173, 55, 138)"}, ALL) +assert-css: (".item-table .keyword", {"color": "rgb(56, 115, 173)"}, ALL) + +assert-css: ( + ".sidebar-elems a:not(.current)", + {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)", "font-weight": "400"}, + ALL, +) +assert-css: ( + ".sidebar-elems a.current", + {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)", "font-weight": "500"}, + ALL, +) diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml index 5e328133e62a1..c4b5fdf53dd6b 100644 --- a/src/test/rustdoc-gui/search-result-color.goml +++ b/src/test/rustdoc-gui/search-result-color.goml @@ -7,7 +7,6 @@ show-text: true // Ayu theme local-storage: { "rustdoc-theme": "ayu", - "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false", } reload: @@ -23,16 +22,66 @@ assert-css: ( {"color": "rgb(0, 150, 207)"}, ) -// Checking the color for "keyword". +// Checking the color of "keyword" text. assert-css: ( "//*[@class='result-name']//*[text()='(keyword)']", {"color": "rgb(120, 135, 151)"}, ) +// Checking the color of "keyword". +assert-css: ( + ".result-name .keyword", + {"color": "rgb(57, 175, 215)"}, + ALL, +) +// Check the color of "struct". +assert-css: ( + ".result-name .struct", + {"color": "rgb(255, 160, 165)"}, + ALL, +) +// Check the color of "associated type". +assert-css: ( + ".result-name .associatedtype", + {"color": "rgb(57, 175, 215)"}, + ALL, +) +// Check the color of "type method". +assert-css: ( + ".result-name .tymethod", + {"color": "rgb(253, 214, 135)"}, + ALL, +) +// Check the color of "method". +assert-css: ( + ".result-name .method", + {"color": "rgb(253, 214, 135)"}, + ALL, +) +// Check the color of "struct field". +assert-css: ( + ".result-name .structfield", + {"color": "rgb(0, 150, 207)"}, + ALL, +) +// Check the color of "macro". +assert-css: ( + ".result-name .macro", + {"color": "rgb(163, 122, 204)"}, + ALL, +) +// Check the color of "fn". +assert-css: ( + ".result-name .fn", + {"color": "rgb(253, 214, 135)"}, + ALL, +) + // Checking the `` container. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", {"color": "rgb(0, 150, 207)", "background-color": "rgba(0, 0, 0, 0)"}, + ALL, ) // Checking color and background on hover. @@ -49,7 +98,6 @@ assert-css: ( // Dark theme local-storage: { "rustdoc-theme": "dark", - "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false", } reload: @@ -71,6 +119,55 @@ assert-css: ( {"color": "rgb(221, 221, 221)"}, ) +// Checking the color of "keyword". +assert-css: ( + ".result-name .keyword", + {"color": "rgb(210, 153, 29)"}, + ALL, +) +// Check the color of "struct". +assert-css: ( + ".result-name .struct", + {"color": "rgb(45, 191, 184)"}, + ALL, +) +// Check the color of "associated type". +assert-css: ( + ".result-name .associatedtype", + {"color": "rgb(210, 153, 29)"}, + ALL, +) +// Check the color of "type method". +assert-css: ( + ".result-name .tymethod", + {"color": "rgb(43, 171, 99)"}, + ALL, +) +// Check the color of "method". +assert-css: ( + ".result-name .method", + {"color": "rgb(43, 171, 99)"}, + ALL, +) +// Check the color of "struct field". +assert-css: ( + ".result-name .structfield", + {"color": "rgb(221, 221, 221)"}, + ALL, +) +// Check the color of "macro". +assert-css: ( + ".result-name .macro", + {"color": "rgb(9, 189, 0)"}, + ALL, +) +// Check the color of "fn". +assert-css: ( + ".result-name .fn", + {"color": "rgb(43, 171, 99)"}, + ALL, +) + // Checking the `` container. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", @@ -109,6 +206,55 @@ assert-css: ( {"color": "rgb(0, 0, 0)"}, ) +// Checking the color of "keyword". +assert-css: ( + ".result-name .keyword", + {"color": "rgb(56, 115, 173)"}, + ALL, +) +// Check the color of "struct". +assert-css: ( + ".result-name .struct", + {"color": "rgb(173, 55, 138)"}, + ALL, +) +// Check the color of "associated type". +assert-css: ( + ".result-name .associatedtype", + {"color": "rgb(56, 115, 173)"}, + ALL, +) +// Check the color of "type method". +assert-css: ( + ".result-name .tymethod", + {"color": "rgb(173, 124, 55)"}, + ALL, +) +// Check the color of "method". +assert-css: ( + ".result-name .method", + {"color": "rgb(173, 124, 55)"}, + ALL, +) +// Check the color of "struct field". +assert-css: ( + ".result-name .structfield", + {"color": "rgb(0, 0, 0)"}, + ALL, +) +// Check the color of "macro". +assert-css: ( + ".result-name .macro", + {"color": "rgb(6, 128, 0)"}, + ALL, +) +// Check the color of "fn". +assert-css: ( + ".result-name .fn", + {"color": "rgb(173, 124, 55)"}, + ALL, +) + // Checking the `` container. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", @@ -132,7 +278,6 @@ goto: file://|DOC_PATH|/test_docs/index.html // this test is running on. local-storage: { "rustdoc-theme": "dark", - "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false", } // If the text isn't displayed, the browser doesn't compute color style correctly... diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 5a151ed7b687a..24aecc70d65e0 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -38,11 +38,14 @@ pub trait Trait { #[deprecated = "Whatever [`Foo`](#tadam)"] fn foo() {} + fn fooo(); } impl Trait for Foo { type X = u32; const Y: u32 = 0; + + fn fooo() {} } impl implementors::Whatever for Foo { diff --git a/src/test/ui/associated-consts/issue-102335-const.rs b/src/test/ui/associated-consts/issue-102335-const.rs new file mode 100644 index 0000000000000..f60cb92da7f6b --- /dev/null +++ b/src/test/ui/associated-consts/issue-102335-const.rs @@ -0,0 +1,12 @@ +#![feature(associated_const_equality)] + +trait T { + type A: S = 34>; + //~^ ERROR associated type bindings are not allowed here +} + +trait S { + const C: i32; +} + +fn main() {} diff --git a/src/test/ui/associated-consts/issue-102335-const.stderr b/src/test/ui/associated-consts/issue-102335-const.stderr new file mode 100644 index 0000000000000..531d15c5900c5 --- /dev/null +++ b/src/test/ui/associated-consts/issue-102335-const.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-const.rs:4:17 + | +LL | type A: S = 34>; + | ^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.rs b/src/test/ui/associated-type-bounds/issue-102335-ty.rs new file mode 100644 index 0000000000000..363df73c1ffd7 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-102335-ty.rs @@ -0,0 +1,12 @@ +trait T { + type A: S = ()>; + //~^ ERROR associated type bindings are not allowed here +} + +trait Q {} + +trait S { + type C: Q; +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/issue-102335-ty.stderr b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr new file mode 100644 index 0000000000000..8777b2965153a --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-102335-ty.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-ty.rs:2:17 + | +LL | type A: S = ()>; + | ^^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr index 5ad457d547a69..c3e2f8e1646f1 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr @@ -4,7 +4,7 @@ error[E0423]: expected value, found type parameter `T` LL | impl Bar for [u8; T] {} | - ^ not a value | | - | found this type pararmeter + | found this type parameter error[E0599]: the function or associated item `foo` exists for struct `Foo<_>`, but its trait bounds were not satisfied --> $DIR/issue-69654.rs:17:10 diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs index 23457b8e0625c..9b646060adfd9 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs @@ -3,11 +3,9 @@ #![deny(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` -//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` #![allow(non_exhaustive_omitted_patterns)] //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` -//~| WARNING unknown lint: `non_exhaustive_omitted_patterns` fn main() { enum Foo { @@ -19,8 +17,6 @@ fn main() { //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` - //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` - //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` match Foo::A { Foo::A => {} Foo::B => {} @@ -35,5 +31,4 @@ fn main() { } //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns` //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` - //~| WARNING unknown lint: `non_exhaustive_omitted_patterns` } diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index 29023858e4f3e..3de08e215dada 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -10,7 +10,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:33:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1 | LL | #![allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5 | LL | #[allow(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | #[allow(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:33:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9 | LL | #[warn(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,13 +100,13 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable error[E0004]: non-exhaustive patterns: `Foo::C` not covered - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:24:11 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11 | LL | match Foo::A { | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:14:15 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15 | LL | enum Foo { | --- @@ -119,56 +119,6 @@ LL ~ Foo::B => {} LL + Foo::C => todo!() | -warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1 - | -LL | #![deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `non_exhaustive_omitted_patterns` lint is unstable - = note: see issue #89554 for more information - = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable - -warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1 - | -LL | #![allow(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `non_exhaustive_omitted_patterns` lint is unstable - = note: see issue #89554 for more information - = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable - -warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 - | -LL | #[allow(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `non_exhaustive_omitted_patterns` lint is unstable - = note: see issue #89554 for more information - = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable - -warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:17:5 - | -LL | #[allow(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `non_exhaustive_omitted_patterns` lint is unstable - = note: see issue #89554 for more information - = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable - -warning: unknown lint: `non_exhaustive_omitted_patterns` - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:33:9 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `non_exhaustive_omitted_patterns` lint is unstable - = note: see issue #89554 for more information - = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable - -error: aborting due to previous error; 15 warnings emitted +error: aborting due to previous error; 10 warnings emitted For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs new file mode 100644 index 0000000000000..719d1bd5a4c7d --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs @@ -0,0 +1,35 @@ +// check-fail +// known-bug + +// This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for +// all 'a where I::Item<'a> is WF", but really means "for all 'a possible" + +use std::fmt::Debug; + +pub trait LendingIterator { + type Item<'this> + where + Self: 'this; +} + +pub struct WindowsMut<'x> { + slice: &'x (), +} + +impl<'y> LendingIterator for WindowsMut<'y> { + type Item<'this> = &'this mut () where 'y: 'this; +} + +fn print_items(_iter: I) +where + I: LendingIterator, + for<'a> I::Item<'a>: Debug, +{ +} + +fn main() { + let slice = &mut (); + //~^ temporary value dropped while borrowed + let windows = WindowsMut { slice }; + print_items::>(windows); +} diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr new file mode 100644 index 0000000000000..414999881d470 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -0,0 +1,20 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/hrtb-implied-1.rs:31:22 + | +LL | let slice = &mut (); + | ^^ creates a temporary which is freed while still in use +... +LL | print_items::>(windows); + | -------------------------------------- argument requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-implied-1.rs:26:26 + | +LL | for<'a> I::Item<'a>: Debug, + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs b/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs new file mode 100644 index 0000000000000..8e6c5348e71ca --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs @@ -0,0 +1,40 @@ +// check-fail +// known-bug + +// This gives us problems because `for<'a> I::Item<'a>: Debug` should mean "for +// all 'a where I::Item<'a> is WF", but really means "for all 'a possible" + +trait LendingIterator: Sized { + type Item<'a> + where + Self: 'a; + fn next(&mut self) -> Self::Item<'_>; +} +fn fails(iter: &mut I, f: F) -> bool +where + F: FnMut(I::Item<'_>), +{ + let mut iter2 = Eat(iter, f); + let _next = iter2.next(); + //~^ borrowed data escapes + true +} +impl LendingIterator for &mut I { + type Item<'a> = I::Item<'a> where Self:'a; + fn next(&mut self) -> Self::Item<'_> { + (**self).next() + } +} + +struct Eat(I, F); +impl Iterator for Eat +where + F: FnMut(I::Item<'_>), +{ + type Item = (); + fn next(&mut self) -> Option { + None + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.stderr b/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.stderr new file mode 100644 index 0000000000000..1ee270398de4d --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-2.stderr @@ -0,0 +1,22 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/hrtb-implied-2.rs:18:17 + | +LL | fn fails(iter: &mut I, f: F) -> bool + | ---- - let's call the lifetime of this reference `'1` + | | + | `iter` is a reference that is only valid in the function body +... +LL | let _next = iter2.next(); + | ^^^^^^^^^^^^ + | | + | `iter` escapes the function body here + | argument requires that `'1` must outlive `'static` + | + = note: requirement occurs because of a mutable reference to `Eat<&mut I, F>` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance + = note: due to current limitations in the borrow checker, this implies a `'static` lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs b/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs new file mode 100644 index 0000000000000..bc9e6c8aea85e --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs @@ -0,0 +1,23 @@ +trait LendingIterator { + type Item<'a> + where + Self: 'a; +} + +impl LendingIterator for &str { + type Item<'a> = () where Self:'a; +} + +fn trivial_bound(_: I) +where + I: LendingIterator, + for<'a> I::Item<'a>: Sized, +{ +} + +fn fails(iter: &str) { + trivial_bound(iter); + //~^ borrowed data escapes +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.stderr b/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.stderr new file mode 100644 index 0000000000000..c67e02437cd8d --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/hrtb-implied-3.stderr @@ -0,0 +1,22 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/hrtb-implied-3.rs:19:5 + | +LL | fn fails(iter: &str) { + | ---- - let's call the lifetime of this reference `'1` + | | + | `iter` is a reference that is only valid in the function body +LL | trivial_bound(iter); + | ^^^^^^^^^^^^^^^^^^^ + | | + | `iter` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-implied-3.rs:14:26 + | +LL | for<'a> I::Item<'a>: Sized, + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/generic-associated-types/issue-102333.rs b/src/test/ui/generic-associated-types/issue-102333.rs new file mode 100644 index 0000000000000..6c72563322f55 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-102333.rs @@ -0,0 +1,15 @@ +// check-pass + +trait A { + type T: B = ()>; +} + +trait B { + type U; +} + +fn f() { + let _: <::T as B>::U<1i32> = (); +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.rs b/src/test/ui/generic-associated-types/issue-102335-gat.rs new file mode 100644 index 0000000000000..a7255fdcbf5e1 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-102335-gat.rs @@ -0,0 +1,12 @@ +trait T { + type A: S = ()>; + //~^ ERROR associated type bindings are not allowed here +} + +trait Q {} + +trait S { + type C: Q; +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-102335-gat.stderr b/src/test/ui/generic-associated-types/issue-102335-gat.stderr new file mode 100644 index 0000000000000..7a7900a1e656a --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-102335-gat.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-102335-gat.rs:2:21 + | +LL | type A: S = ()>; + | ^^^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/generic-associated-types/trait-objects.extended.stderr b/src/test/ui/generic-associated-types/trait-objects.extended.stderr index 086177cc106dc..45b64d2b02483 100644 --- a/src/test/ui/generic-associated-types/trait-objects.extended.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.extended.stderr @@ -11,6 +11,8 @@ LL | x.size_hint().0 | | | `x` escapes the function body here | argument requires that `'1` must outlive `'static` + | + = note: due to current limitations in the borrow checker, this implies a `'static` lifetime error: aborting due to previous error diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr index b4312091edb27..31e11e1283516 100644 --- a/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr +++ b/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr @@ -14,6 +14,12 @@ LL | fn give_some<'a>() { | -- lifetime `'a` defined here LL | want_hrtb::<&'a u32>() | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-just-for-static.rs:9:15 + | +LL | where T : for<'a> Foo<&'a isize> + | ^^^^^^^^^^^^^^^^^^^^^^ error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr index 1461e7fd2ddd7..5e75a4cc8afa5 100644 --- a/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr +++ b/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr @@ -46,6 +46,12 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) ... LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-perfect-forwarding.rs:37:8 + | +LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, + | ^^^^^^^^^^^^^^^^^^^^^^ error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 diff --git a/src/test/ui/implied-bounds/issue-101951.rs b/src/test/ui/implied-bounds/issue-101951.rs new file mode 100644 index 0000000000000..108fef8a15fb3 --- /dev/null +++ b/src/test/ui/implied-bounds/issue-101951.rs @@ -0,0 +1,50 @@ +// Taken directly from that issue. +// +// This test detected that we didn't correctly resolve +// inference variables when computing implied bounds. +// +// check-pass +pub trait BuilderFn<'a> { + type Output; +} + +impl<'a, F, Out> BuilderFn<'a> for F +where + F: FnOnce(&'a mut ()) -> Out, +{ + type Output = Out; +} + +pub trait ConstructionFirm { + type Builder: for<'a> BuilderFn<'a>; +} + +pub trait Campus +where + T: ConstructionFirm, +{ + fn add_building( + &mut self, + building: &mut <::Builder as BuilderFn<'_>>::Output, + ); +} + +struct ArchitectsInc {} + +impl ConstructionFirm for ArchitectsInc { + type Builder = fn(&mut ()) -> PrettyCondo<'_>; +} + +struct PrettyCondo<'a> { + _marker: &'a mut (), +} + +struct CondoEstate {} + +impl Campus for CondoEstate { + fn add_building(&mut self, _building: &mut PrettyCondo<'_>) { + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-26217.stderr b/src/test/ui/issues/issue-26217.stderr index c7601caacdca3..73c772205c3da 100644 --- a/src/test/ui/issues/issue-26217.stderr +++ b/src/test/ui/issues/issue-26217.stderr @@ -5,6 +5,12 @@ LL | fn bar<'a>() { | -- lifetime `'a` defined here LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-26217.rs:1:30 + | +LL | fn foo() where for<'a> T: 'a {} + | ^^ error: aborting due to previous error diff --git a/src/test/ui/let-else/const-fn.rs b/src/test/ui/let-else/const-fn.rs new file mode 100644 index 0000000000000..336b0b4b72ad5 --- /dev/null +++ b/src/test/ui/let-else/const-fn.rs @@ -0,0 +1,19 @@ +// run-pass +// issue #101932 + +#![cfg_attr(bootstrap, feature(let_else))] + +const fn foo(a: Option) -> i32 { + let Some(a) = a else { + return 42 + }; + + a + 1 +} + +fn main() { + const A: i32 = foo(None); + const B: i32 = foo(Some(1)); + + println!("{} {}", A, B); +} diff --git a/src/test/ui/let-else/issue-102317.rs b/src/test/ui/let-else/issue-102317.rs new file mode 100644 index 0000000000000..7369b4938eed4 --- /dev/null +++ b/src/test/ui/let-else/issue-102317.rs @@ -0,0 +1,20 @@ +// issue #102317 +// build-pass +// compile-flags: --edition 2021 -C opt-level=3 -Zvalidate-mir + +struct SegmentJob; + +impl Drop for SegmentJob { + fn drop(&mut self) {} +} + +pub async fn run() -> Result<(), ()> { + let jobs = Vec::::new(); + let Some(_job) = jobs.into_iter().next() else { + return Ok(()) + }; + + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index ad11f72a31d37..08e4be2c0c352 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -2,7 +2,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `T` --> $DIR/lexical-scopes.rs:3:13 | LL | fn f() { - | - found this type pararmeter + | - found this type parameter LL | let t = T { i: 0 }; | ^ not a struct, variant or union type diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr index 5942fa8aeb4f0..06befcbb5117e 100644 --- a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr @@ -1,3 +1,11 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/force_warn_expected_lints_fulfilled.rs:10:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: requested on the command line with `--force-warn while-true` + warning: unused variable: `x` --> $DIR/force_warn_expected_lints_fulfilled.rs:20:9 | @@ -28,13 +36,5 @@ LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*"; | = note: requested on the command line with `--force-warn unused-mut` -warning: denote infinite loops with `loop { ... }` - --> $DIR/force_warn_expected_lints_fulfilled.rs:10:5 - | -LL | while true { - | ^^^^^^^^^^ help: use `loop` - | - = note: requested on the command line with `--force-warn while-true` - warning: 5 warnings emitted diff --git a/src/test/ui/mir/issue-99852.rs b/src/test/ui/mir/issue-99852.rs new file mode 100644 index 0000000000000..1c675788ee933 --- /dev/null +++ b/src/test/ui/mir/issue-99852.rs @@ -0,0 +1,24 @@ +// check-pass +// compile-flags: -Z validate-mir +#![feature(let_chains)] + +fn lambda() -> U +where + T: Default, + U: Default, +{ + let foo: Result = Ok(T::default()); + let baz: U = U::default(); + + if let Ok(foo) = foo && let Ok(bar) = transform(foo) { + bar + } else { + baz + } +} + +fn transform(input: T) -> Result { + todo!() +} + +fn main() {} diff --git a/src/test/ui/nll/local-outlives-static-via-hrtb.stderr b/src/test/ui/nll/local-outlives-static-via-hrtb.stderr index 61009da49ffed..f5c10f3ddea0e 100644 --- a/src/test/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/src/test/ui/nll/local-outlives-static-via-hrtb.stderr @@ -9,6 +9,12 @@ LL | assert_static_via_hrtb(&local); LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/local-outlives-static-via-hrtb.rs:15:53 + | +LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} + | ^^^^^^^^^^^^ error[E0597]: `local` does not live long enough --> $DIR/local-outlives-static-via-hrtb.rs:25:45 @@ -20,6 +26,12 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); | argument requires that `local` is borrowed for `'static` LL | } | - `local` dropped here while still borrowed + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/local-outlives-static-via-hrtb.rs:19:20 + | +LL | for<'a> &'a T: Reference, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/type-test-universe.stderr b/src/test/ui/nll/type-test-universe.stderr index 242486c360a80..31e17d64b8caf 100644 --- a/src/test/ui/nll/type-test-universe.stderr +++ b/src/test/ui/nll/type-test-universe.stderr @@ -11,6 +11,12 @@ LL | fn test2<'a>() { | -- lifetime `'a` defined here LL | outlives_forall::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/type-test-universe.rs:6:16 + | +LL | for<'u> T: 'u, + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr index d9c404e94acb4..af9f4612ab342 100644 --- a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr +++ b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr @@ -2,7 +2,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `Baz` --> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13 | LL | impl Foo for Bar { - | --- found this type pararmeter + | --- found this type parameter ... LL | Baz { num } => num, | ^^^ not a struct, variant or union type diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr index ea9c4c82c3610..d8fddc8007f50 100644 --- a/src/test/ui/span/issue-35987.stderr +++ b/src/test/ui/span/issue-35987.stderr @@ -4,7 +4,7 @@ error[E0404]: expected trait, found type parameter `Add` LL | impl Add for Foo { | --- ^^^ not a trait | | - | found this type pararmeter + | found this type parameter | help: consider importing this trait instead | diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs index dd52b3150551a..02b5fb61894e9 100644 --- a/src/test/ui/suggestions/issue-85347.rs +++ b/src/test/ui/suggestions/issue-85347.rs @@ -2,6 +2,7 @@ use std::ops::Deref; trait Foo { type Bar<'a>: Deref::Bar>; //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + //~| ERROR associated type bindings are not allowed here //~| HELP add missing } diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr index de853de27e40e..17c1b7dc4cce9 100644 --- a/src/test/ui/suggestions/issue-85347.stderr +++ b/src/test/ui/suggestions/issue-85347.stderr @@ -14,6 +14,13 @@ help: add missing lifetime argument LL | type Bar<'a>: Deref::Bar<'a, Target = Self>>; | +++ -error: aborting due to previous error +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-85347.rs:3:46 + | +LL | type Bar<'a>: Deref::Bar>; + | ^^^^^^^^^^^^^ associated type not allowed here + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0229. +For more information about an error, try `rustc --explain E0107`.