Auto merge of #102676 - cuviper:beta-next, r=cuviper
[beta] backports * Avoid duplicating StorageLive in let-else #101894 * Re-add HRTB implied static bug note #101924 * Revert "Copy stage0 binaries into stage0-sysroot" #101942 * implied_bounds: deal with inference vars #102016 * fix ConstProp handling of written_only_inside_own_block_locals #102045 * Fix wrongly refactored Lift impl #102088 * Fix a typo “pararmeter” in error message #102119 * Deny associated type bindings within associated type bindings #102338 * Continue migration of CSS themes #101934 * Fix search result colors #102369 * Fix unwind drop glue for if-then scopes #102394 * Revert "Use getentropy when possible on all Apple platforms" #102693 * Fix associated type bindings with anon const in GAT position #102336 * Revert perf-regression 101620 #102064 * `EscapeAscii` is not an `ExactSizeIterator` #99880
This commit is contained in:
commit
da7ffa2d1d
95 changed files with 1976 additions and 1084 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
extra_info: Vec<ExtraConstraintInfo>,
|
||||
},
|
||||
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<RegionName>) {
|
||||
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<RegionName>, Vec<ExtraConstraintInfo>) {
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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<ExtraConstraintInfo>) {
|
||||
// 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::<Vec<_>>()
|
||||
);
|
||||
|
||||
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>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<R, Op>(
|
||||
pub(super) fn fully_perform_op<R: fmt::Debug, 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<T>(&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<T>(
|
||||
&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| {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {""}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
|
|
|
|||
|
|
@ -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<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
|
||||
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> {
|
|||
}
|
||||
|
||||
/// Builder of OutlivesEnvironment.
|
||||
#[derive(Debug)]
|
||||
struct OutlivesEnvironmentBuilder<'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_relation: TransitiveRelationBuilder<Region<'tcx>>,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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<LintStackIndex, LintSet>,
|
||||
}
|
||||
|
||||
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<LintId, LevelAndSource>,
|
||||
parent: LintStackIndex,
|
||||
}
|
||||
|
||||
impl LintLevelSets {
|
||||
fn new() -> Self {
|
||||
LintLevelSets { list: IndexVec::new() }
|
||||
}
|
||||
|
||||
fn get_lint_level(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
idx: LintStackIndex,
|
||||
aux: Option<&FxHashMap<LintId, LevelAndSource>>,
|
||||
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<LintId, LevelAndSource>>,
|
||||
) -> (Option<Level>, 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.levels.id_to_set.reserve(krate.owners.len() + 1);
|
||||
|
||||
builder.add_command_line();
|
||||
builder.add_id(hir::CRATE_HIR_ID);
|
||||
let push =
|
||||
builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID));
|
||||
|
||||
builder.levels.register_id(hir::CRATE_HIR_ID);
|
||||
tcx.hir().walk_toplevel_module(&mut builder);
|
||||
builder.levels.pop(push);
|
||||
|
||||
tcx.sess.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
|
||||
|
||||
builder.provider.expectations
|
||||
builder.levels.update_unstable_expectation_ids();
|
||||
builder.levels.build_map()
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
levels.provider.specs
|
||||
}
|
||||
|
||||
pub struct TopDown {
|
||||
sets: LintLevelSets,
|
||||
cur: LintStackIndex,
|
||||
}
|
||||
|
||||
pub trait LintLevelsProvider {
|
||||
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource>;
|
||||
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource>;
|
||||
fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource;
|
||||
fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {}
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for TopDown {
|
||||
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
|
||||
&self.sets.list[self.cur].specs
|
||||
}
|
||||
|
||||
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
|
||||
&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<LintId, LevelAndSource> {
|
||||
&self.specs.specs
|
||||
}
|
||||
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
|
||||
&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<LintExpectationId, LintExpectationId>,
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
|
||||
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
|
||||
&self.specs.specs
|
||||
}
|
||||
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
|
||||
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> {
|
||||
pub struct LintLevelsBuilder<'s> {
|
||||
sess: &'s Session,
|
||||
provider: P,
|
||||
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<LintExpectationId, LintExpectationId>,
|
||||
sets: LintLevelSets,
|
||||
id_to_set: FxHashMap<HirId, LintStackIndex>,
|
||||
cur: LintStackIndex,
|
||||
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<HirId>,
|
||||
) -> 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<LintId, LevelAndSource> {
|
||||
self.provider.current_specs()
|
||||
&self.sets.list[self.cur].specs
|
||||
}
|
||||
|
||||
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
|
||||
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<HirId>) {
|
||||
/// 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<HirId>,
|
||||
) -> 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<MultiSpan>,
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers };
|
||||
struct LintLevelMapBuilder<'tcx> {
|
||||
levels: LintLevelsBuilder<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl LintLevelMapBuilder<'_> {
|
||||
fn with_lint_attrs<F>(&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 fn provide(providers: &mut Providers) {
|
||||
providers.lint_levels = lint_levels;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
||||
|
|
|
|||
|
|
@ -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<u16>, attr_id: Option<AttrId> },
|
||||
Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
|
||||
}
|
||||
|
||||
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<HCX: rustc_hir::HashStableContext> HashStable<HCX> 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<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> 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`")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TyCtxt<'tcx>> for (DefId, DefId) {
|
|||
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> 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<TyCtxt<'tcx>> 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(),
|
||||
)
|
||||
}
|
||||
let local_id = Fingerprint::from_smaller_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())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<GenericArg<'tcx>, Region<'tcx>>>;
|
||||
pub type QueryOutlivesConstraint<'tcx> = (
|
||||
ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
|
||||
ConstraintCategory<'tcx>,
|
||||
);
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
for <'tcx> {
|
||||
|
|
|
|||
|
|
@ -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<Symbol>,
|
||||
},
|
||||
Node(Symbol, Span, Option<Symbol> /* 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 {
|
||||
pub specs: FxHashMap<LintId, LevelAndSource>,
|
||||
#[derive(Debug, HashStable)]
|
||||
pub struct LintLevelSets {
|
||||
pub list: IndexVec<LintStackIndex, LintSet>,
|
||||
pub lint_cap: Level,
|
||||
}
|
||||
|
||||
/// 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<Level>,
|
||||
src: &mut LintLevelSource,
|
||||
sess: &Session,
|
||||
lint: LintId,
|
||||
probe_for_lint_level: impl FnOnce(LintId) -> (Option<Level>, 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()));
|
||||
rustc_index::newtype_index! {
|
||||
#[derive(HashStable)]
|
||||
pub struct LintStackIndex {
|
||||
const COMMAND_LINE = 0,
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
#[derive(Debug, HashStable)]
|
||||
pub struct LintSet {
|
||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
||||
// flag.
|
||||
pub specs: FxHashMap<LintId, LevelAndSource>,
|
||||
|
||||
pub parent: LintStackIndex,
|
||||
}
|
||||
|
||||
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<LintId, LevelAndSource>>,
|
||||
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(&lint) {
|
||||
// Ensure that we never exceed driver level.
|
||||
level = cmp::min(*driver_level, level);
|
||||
}
|
||||
|
||||
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(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
id: LintId,
|
||||
start: HirId,
|
||||
) -> (Option<Level>, LintLevelSource) {
|
||||
if let Some(&(level, src)) = self.specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
(level, src)
|
||||
}
|
||||
|
||||
pub fn get_lint_id_level(
|
||||
&self,
|
||||
id: LintId,
|
||||
mut idx: LintStackIndex,
|
||||
aux: Option<&FxHashMap<LintId, LevelAndSource>>,
|
||||
) -> (Option<Level>, LintLevelSource) {
|
||||
if let Some(specs) = aux {
|
||||
if let Some(&(level, src)) = specs.get(&id) {
|
||||
return (Some(level), src);
|
||||
}
|
||||
}
|
||||
(None, LintLevelSource::Default)
|
||||
}
|
||||
|
||||
/// Fetch and return the user-visible lint level for the given lint at the given HirId.
|
||||
pub fn lint_level_id_at_node(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
lint: LintId,
|
||||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
#[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<HirId, LintStackIndex>,
|
||||
}
|
||||
|
||||
/// 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
|
||||
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,
|
||||
lint: &'static Lint,
|
||||
id: HirId,
|
||||
session: &Session,
|
||||
) -> Option<LevelAndSource> {
|
||||
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> 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;
|
||||
|
||||
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!(
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Ty<'tcx>>,
|
||||
},
|
||||
|
||||
AscribeUserTypeProvePredicate(Span),
|
||||
}
|
||||
|
||||
/// The 'location' at which we try to perform HIR-based wf checking.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<T> {
|
||||
type Lifted = Option<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(self?).map(Some)
|
||||
Some(match self {
|
||||
Some(x) => Some(tcx.lift(x)?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Span>,
|
||||
arm_scope: Option<region::Scope>,
|
||||
match_scope: Option<region::Scope>,
|
||||
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<Span>,
|
||||
match_scope: Option<region::Scope>,
|
||||
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<Item = &'b Binding<'tcx>>,
|
||||
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<BasicBlock> {
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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<F>(
|
||||
&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<BasicBlock>,
|
||||
) -> Option<BlockAnd<()>> {
|
||||
let mut blocks = IndexVec::from_elem(None, &drops.drops);
|
||||
blocks[ROOT_NODE] = continue_block;
|
||||
|
||||
drops.build_mir::<ExitScopes>(&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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DefId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,8 +67,6 @@ impl<T: DepContext> 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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = <dyn TraitEngine<'tcx>>::new(self.tcx);
|
||||
|
|
|
|||
|
|
@ -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::<T>(),
|
||||
value,
|
||||
self.param_env,
|
||||
self.cause,
|
||||
);
|
||||
if !needs_normalization(&value, self.param_env.reveal()) {
|
||||
return Ok(Normalized { value, obligations: vec![] });
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl<F, G> CustomTypeOp<F, G> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
|
||||
impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
|
||||
where
|
||||
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
|
||||
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,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
|
||||
vec![];
|
||||
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::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<Foo=_1>` 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<Foo=_1>`
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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<T>(&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<T>(&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<Span>) {
|
||||
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<Span>,
|
||||
) -> 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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 `<A: T>` 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:?}"),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
9
src/test/mir-opt/issue-101867.rs
Normal file
9
src/test/mir-opt/issue-101867.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
|
||||
// EMIT_MIR issue_101867.main.mir_map.0.mir
|
||||
fn main() {
|
||||
let x: Option<u8> = Some(1);
|
||||
let Some(y) = x else {
|
||||
panic!();
|
||||
};
|
||||
}
|
||||
20
src/test/mir-opt/issue-101973.rs
Normal file
20
src/test/mir-opt/issue-101973.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
75
src/test/mir-opt/issue_101867.main.mir_map.0.mir
Normal file
75
src/test/mir-opt/issue_101867.main.mir_map.0.mir
Normal file
|
|
@ -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<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
|
||||
| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/issue-101867.rs:+0:11: +0:11
|
||||
let _1: std::option::Option<u8> 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::<u8>::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(<ZST>) }
|
||||
// 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
|
||||
}
|
||||
}
|
||||
100
src/test/mir-opt/issue_101973.inner.ConstProp.diff
Normal file
100
src/test/mir-opt/issue_101973.inner.ConstProp.diff
Normal file
|
|
@ -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::<impl u32>::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::<u32>(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::<u32>}, val: Value(<ZST>) }
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
85
src/test/rustdoc-gui/links-color.goml
Normal file
85
src/test/rustdoc-gui/links-color.goml
Normal file
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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 `<a>` 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 `<a>` 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 `<a>` 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...
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
12
src/test/ui/associated-consts/issue-102335-const.rs
Normal file
12
src/test/ui/associated-consts/issue-102335-const.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#![feature(associated_const_equality)]
|
||||
|
||||
trait T {
|
||||
type A: S<C<X = 0i32> = 34>;
|
||||
//~^ ERROR associated type bindings are not allowed here
|
||||
}
|
||||
|
||||
trait S {
|
||||
const C: i32;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
9
src/test/ui/associated-consts/issue-102335-const.stderr
Normal file
9
src/test/ui/associated-consts/issue-102335-const.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-102335-const.rs:4:17
|
||||
|
|
||||
LL | type A: S<C<X = 0i32> = 34>;
|
||||
| ^^^^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
12
src/test/ui/associated-type-bounds/issue-102335-ty.rs
Normal file
12
src/test/ui/associated-type-bounds/issue-102335-ty.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
trait T {
|
||||
type A: S<C<i32 = u32> = ()>;
|
||||
//~^ ERROR associated type bindings are not allowed here
|
||||
}
|
||||
|
||||
trait Q {}
|
||||
|
||||
trait S {
|
||||
type C: Q;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-102335-ty.rs:2:17
|
||||
|
|
||||
LL | type A: S<C<i32 = u32> = ()>;
|
||||
| ^^^^^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
|
|
@ -4,7 +4,7 @@ error[E0423]: expected value, found type parameter `T`
|
|||
LL | impl<T> Bar<T> 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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
|
||||
|
|
|
|||
35
src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs
Normal file
35
src/test/ui/generic-associated-types/bugs/hrtb-implied-1.rs
Normal file
|
|
@ -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<I>(_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::<WindowsMut<'_>>(windows);
|
||||
}
|
||||
|
|
@ -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::<WindowsMut<'_>>(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`.
|
||||
40
src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs
Normal file
40
src/test/ui/generic-associated-types/bugs/hrtb-implied-2.rs
Normal file
|
|
@ -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<I: LendingIterator, F>(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<I: LendingIterator> 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>(I, F);
|
||||
impl<I: LendingIterator, F> Iterator for Eat<I, F>
|
||||
where
|
||||
F: FnMut(I::Item<'_>),
|
||||
{
|
||||
type Item = ();
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
error[E0521]: borrowed data escapes outside of function
|
||||
--> $DIR/hrtb-implied-2.rs:18:17
|
||||
|
|
||||
LL | fn fails<I: LendingIterator, F>(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 <https://doc.rust-lang.org/nomicon/subtyping.html> 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`.
|
||||
23
src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs
Normal file
23
src/test/ui/generic-associated-types/bugs/hrtb-implied-3.rs
Normal file
|
|
@ -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>(_: I)
|
||||
where
|
||||
I: LendingIterator,
|
||||
for<'a> I::Item<'a>: Sized,
|
||||
{
|
||||
}
|
||||
|
||||
fn fails(iter: &str) {
|
||||
trivial_bound(iter);
|
||||
//~^ borrowed data escapes
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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`.
|
||||
15
src/test/ui/generic-associated-types/issue-102333.rs
Normal file
15
src/test/ui/generic-associated-types/issue-102333.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// check-pass
|
||||
|
||||
trait A {
|
||||
type T: B<U<1i32> = ()>;
|
||||
}
|
||||
|
||||
trait B {
|
||||
type U<const C: i32>;
|
||||
}
|
||||
|
||||
fn f<T: A>() {
|
||||
let _: <<T as A>::T as B>::U<1i32> = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
12
src/test/ui/generic-associated-types/issue-102335-gat.rs
Normal file
12
src/test/ui/generic-associated-types/issue-102335-gat.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
trait T {
|
||||
type A: S<C<(), i32 = ()> = ()>;
|
||||
//~^ ERROR associated type bindings are not allowed here
|
||||
}
|
||||
|
||||
trait Q {}
|
||||
|
||||
trait S {
|
||||
type C<T>: Q;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0229]: associated type bindings are not allowed here
|
||||
--> $DIR/issue-102335-gat.rs:2:21
|
||||
|
|
||||
LL | type A: S<C<(), i32 = ()> = ()>;
|
||||
| ^^^^^^^^ associated type not allowed here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0229`.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
50
src/test/ui/implied-bounds/issue-101951.rs
Normal file
50
src/test/ui/implied-bounds/issue-101951.rs
Normal file
|
|
@ -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<T>
|
||||
where
|
||||
T: ConstructionFirm,
|
||||
{
|
||||
fn add_building(
|
||||
&mut self,
|
||||
building: &mut <<T as ConstructionFirm>::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<ArchitectsInc> for CondoEstate {
|
||||
fn add_building(&mut self, _building: &mut PrettyCondo<'_>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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<T>() where for<'a> T: 'a {}
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
19
src/test/ui/let-else/const-fn.rs
Normal file
19
src/test/ui/let-else/const-fn.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// run-pass
|
||||
// issue #101932
|
||||
|
||||
#![cfg_attr(bootstrap, feature(let_else))]
|
||||
|
||||
const fn foo(a: Option<i32>) -> 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);
|
||||
}
|
||||
20
src/test/ui/let-else/issue-102317.rs
Normal file
20
src/test/ui/let-else/issue-102317.rs
Normal file
|
|
@ -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::<SegmentJob>::new();
|
||||
let Some(_job) = jobs.into_iter().next() else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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<T>() {
|
||||
| - found this type pararmeter
|
||||
| - found this type parameter
|
||||
LL | let t = T { i: 0 };
|
||||
| ^ not a struct, variant or union type
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
24
src/test/ui/mir/issue-99852.rs
Normal file
24
src/test/ui/mir/issue-99852.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// check-pass
|
||||
// compile-flags: -Z validate-mir
|
||||
#![feature(let_chains)]
|
||||
|
||||
fn lambda<T, U>() -> U
|
||||
where
|
||||
T: Default,
|
||||
U: Default,
|
||||
{
|
||||
let foo: Result<T, ()> = Ok(T::default());
|
||||
let baz: U = U::default();
|
||||
|
||||
if let Ok(foo) = foo && let Ok(bar) = transform(foo) {
|
||||
bar
|
||||
} else {
|
||||
baz
|
||||
}
|
||||
}
|
||||
|
||||
fn transform<T, U>(input: T) -> Result<U, ()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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>(_: 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<AssociatedType = &'a ()>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ LL | fn test2<'a>() {
|
|||
| -- lifetime `'a` defined here
|
||||
LL | outlives_forall::<Value<'a>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Baz> Foo<Baz> for Bar {
|
||||
| --- found this type pararmeter
|
||||
| --- found this type parameter
|
||||
...
|
||||
LL | Baz { num } => num,
|
||||
| ^^^ not a struct, variant or union type
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error[E0404]: expected trait, found type parameter `Add`
|
|||
LL | impl<T: Clone, Add> Add for Foo<T> {
|
||||
| --- ^^^ not a trait
|
||||
| |
|
||||
| found this type pararmeter
|
||||
| found this type parameter
|
||||
|
|
||||
help: consider importing this trait instead
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::ops::Deref;
|
|||
trait Foo {
|
||||
type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
|
||||
//~^ 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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ help: add missing lifetime argument
|
|||
LL | type Bar<'a>: Deref<Target = <Self>::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<Target = <Self>::Bar<Target = Self>>;
|
||||
| ^^^^^^^^^^^^^ associated type not allowed here
|
||||
|
||||
For more information about this error, try `rustc --explain E0107`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0107, E0229.
|
||||
For more information about an error, try `rustc --explain E0107`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue