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:
bors 2022-10-10 00:22:17 +00:00
commit da7ffa2d1d
95 changed files with 1976 additions and 1084 deletions

View file

@ -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;

View file

@ -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");

View file

@ -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>,

View file

@ -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>,
}

View file

@ -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| {

View file

@ -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(

View file

@ -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,);
});

View file

@ -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 = {""}

View file

@ -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;

View file

@ -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(_))

View file

@ -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();

View file

@ -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
}
}
}

View file

@ -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(),
}
}

View file

@ -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,

View file

@ -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, &region_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)
}

View file

@ -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,
}

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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"]

View file

@ -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`")
}

View file

@ -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)
}
}

View file

@ -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> {

View file

@ -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!(

View file

@ -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),

View file

@ -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 {

View file

@ -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.

View file

@ -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(

View file

@ -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;

View file

@ -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,
})
}
}

View file

@ -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!(

View file

@ -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)
});

View file

@ -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()

View file

@ -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

View file

@ -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,
);
}
}
}

View file

@ -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
}
}

View file

@ -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,
}
}

View file

@ -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,
},

View file

@ -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");
}

View file

@ -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);

View file

@ -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![] });

View file

@ -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)),
&region_constraint_data,
);

View file

@ -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,

View file

@ -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

View file

@ -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(())
}

View file

@ -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
}
}

View file

@ -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,

View file

@ -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,
);
})
}

View file

@ -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:?}"),
),

View file

@ -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> {

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View 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!();
};
}

View 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);
}

View 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
}
}

View 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
}
}

View 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,
)

View file

@ -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...

View file

@ -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 {

View 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() {}

View 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`.

View 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() {}

View file

@ -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`.

View file

@ -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

View file

@ -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`
}

View file

@ -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`.

View 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);
}

View file

@ -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`.

View 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() {}

View file

@ -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`.

View 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() {}

View file

@ -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`.

View 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() {}

View 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() {}

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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

View 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() {}

View file

@ -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

View 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);
}

View 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() {}

View file

@ -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

View file

@ -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

View 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() {}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
|

View file

@ -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
}

View file

@ -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`.