Auto merge of #135713 - matthiaskrgr:rollup-c04uupz, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #135616 (CI: split i686-msvc job to two free runners) - #135623 (ci: use ghcr ubuntu image for mingw-check-tidy) - #135640 (Drop MIPS glibc 2.23 patches that reside in crosstool-ng now) - #135663 (Fix ICE in resolving associated items as non-bindings) - #135680 (coverage: Clean up a few things after the counters overhaul) - #135697 (Get rid of `ToPolyTraitRef`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
01706e1a34
32 changed files with 388 additions and 460 deletions
|
@ -1,5 +1,5 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::{Ident, Span};
|
||||
pub use rustc_type_ir::elaborate::*;
|
||||
|
||||
|
@ -125,8 +125,8 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
|
|||
.iter_identity_copied()
|
||||
.map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
|
||||
.filter_map(|clause| clause.as_trait_clause())
|
||||
// FIXME: Negative supertraits are elaborated here lol
|
||||
.map(|trait_pred| trait_pred.to_poly_trait_ref()),
|
||||
.filter(|clause| clause.polarity() == ty::PredicatePolarity::Positive)
|
||||
.map(|clause| clause.map_bound(|clause| clause.trait_ref)),
|
||||
);
|
||||
|
||||
return Some(trait_ref);
|
||||
|
|
|
@ -71,11 +71,7 @@ impl ConditionId {
|
|||
|
||||
/// Enum that can hold a constant zero value, the ID of an physical coverage
|
||||
/// counter, or the ID of a coverage-counter expression.
|
||||
///
|
||||
/// This was originally only used for expression operands (and named `Operand`),
|
||||
/// but the zero/counter/expression distinction is also useful for representing
|
||||
/// the value of code/gap mappings, and the true/false arms of branch mappings.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum CovTerm {
|
||||
Zero,
|
||||
|
@ -171,7 +167,7 @@ impl Op {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Expression {
|
||||
pub lhs: CovTerm,
|
||||
|
|
|
@ -79,8 +79,7 @@ pub use self::predicate::{
|
|||
PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
|
||||
PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
|
||||
PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
|
||||
RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
|
||||
TypeOutlivesPredicate,
|
||||
RegionOutlivesPredicate, SubtypePredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate,
|
||||
};
|
||||
pub use self::region::{
|
||||
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,
|
||||
|
|
|
@ -476,16 +476,6 @@ impl<'tcx> Clause<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ToPolyTraitRef<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
|
||||
self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
ty::Binder::dummy(from).upcast(tcx)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use either::Either;
|
||||
use itertools::Itertools;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
|
@ -20,76 +19,31 @@ mod iter_nodes;
|
|||
mod node_flow;
|
||||
mod union_find;
|
||||
|
||||
/// The coverage counter or counter expression associated with a particular
|
||||
/// BCB node or BCB edge.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
enum BcbCounter {
|
||||
Counter { id: CounterId },
|
||||
Expression { id: ExpressionId },
|
||||
}
|
||||
|
||||
impl BcbCounter {
|
||||
fn as_term(&self) -> CovTerm {
|
||||
match *self {
|
||||
BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
|
||||
BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for BcbCounter {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()),
|
||||
Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
struct BcbExpression {
|
||||
lhs: BcbCounter,
|
||||
op: Op,
|
||||
rhs: BcbCounter,
|
||||
}
|
||||
|
||||
/// Enum representing either a node or an edge in the coverage graph.
|
||||
///
|
||||
/// FIXME(#135481): This enum is no longer needed now that we only instrument
|
||||
/// nodes and not edges. It can be removed in a subsequent PR.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(super) enum Site {
|
||||
Node { bcb: BasicCoverageBlock },
|
||||
}
|
||||
|
||||
/// Generates and stores coverage counter and coverage expression information
|
||||
/// associated with nodes/edges in the BCB graph.
|
||||
pub(super) struct CoverageCounters {
|
||||
/// List of places where a counter-increment statement should be injected
|
||||
/// into MIR, each with its corresponding counter ID.
|
||||
counter_increment_sites: IndexVec<CounterId, Site>,
|
||||
|
||||
/// Coverage counters/expressions that are associated with individual BCBs.
|
||||
node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
|
||||
|
||||
/// Table of expression data, associating each expression ID with its
|
||||
/// corresponding operator (+ or -) and its LHS/RHS operands.
|
||||
expressions: IndexVec<ExpressionId, BcbExpression>,
|
||||
/// Remember expressions that have already been created (or simplified),
|
||||
/// so that we don't create unnecessary duplicates.
|
||||
expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
|
||||
}
|
||||
|
||||
impl CoverageCounters {
|
||||
/// Ensures that each BCB node needing a counter has one, by creating physical
|
||||
/// counters or counter expressions for nodes and edges as required.
|
||||
/// counters or counter expressions for nodes as required.
|
||||
pub(super) fn make_bcb_counters(
|
||||
graph: &CoverageGraph,
|
||||
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
|
||||
) -> Self {
|
||||
) -> CoverageCounters {
|
||||
// Create the derived graphs that are necessary for subsequent steps.
|
||||
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
|
||||
let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph);
|
||||
|
||||
// Use those graphs to determine which nodes get physical counters, and how
|
||||
// to compute the execution counts of other nodes from those counters.
|
||||
let nodes = make_node_counter_priority_list(graph, balanced_graph);
|
||||
let node_counters = merged_graph.make_node_counters(&nodes);
|
||||
|
||||
// Convert the counters into a form suitable for embedding into MIR.
|
||||
transcribe_counters(&node_counters, bcb_needs_counter)
|
||||
}
|
||||
|
||||
/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
|
||||
/// take priority in being given a counter expression instead of a physical counter.
|
||||
fn make_node_counter_priority_list(
|
||||
graph: &CoverageGraph,
|
||||
balanced_graph: BalancedFlowGraph<&CoverageGraph>,
|
||||
) -> Vec<BasicCoverageBlock> {
|
||||
// A "reloop" node has exactly one out-edge, which jumps back to the top
|
||||
// of an enclosing loop. Reloop nodes are typically visited more times
|
||||
// than loop-exit nodes, so try to avoid giving them physical counters.
|
||||
|
@ -116,38 +70,112 @@ impl CoverageCounters {
|
|||
// Otherwise, prefer a physical counter for dominating nodes.
|
||||
.then_with(|| graph.cmp_in_dominator_order(a, b).reverse())
|
||||
});
|
||||
let node_counters = merged_graph.make_node_counters(&nodes);
|
||||
|
||||
Transcriber::new(graph.num_nodes(), node_counters).transcribe_counters(bcb_needs_counter)
|
||||
nodes
|
||||
}
|
||||
|
||||
// Converts node counters into a form suitable for embedding into MIR.
|
||||
fn transcribe_counters(
|
||||
old: &NodeCounters<BasicCoverageBlock>,
|
||||
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
|
||||
) -> CoverageCounters {
|
||||
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
|
||||
|
||||
for bcb in bcb_needs_counter.iter() {
|
||||
// Our counter-creation algorithm doesn't guarantee that a counter
|
||||
// expression starts or ends with a positive term, so partition the
|
||||
// counters into "positive" and "negative" lists for easier handling.
|
||||
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
|
||||
old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op {
|
||||
Op::Add => Either::Left(node),
|
||||
Op::Subtract => Either::Right(node),
|
||||
});
|
||||
|
||||
if pos.is_empty() {
|
||||
// If we somehow end up with no positive terms, fall back to
|
||||
// creating a physical counter. There's no known way for this
|
||||
// to happen, but we can avoid an ICE if it does.
|
||||
debug_assert!(false, "{bcb:?} has no positive counter terms");
|
||||
pos = vec![bcb];
|
||||
neg = vec![];
|
||||
}
|
||||
|
||||
// These intermediate sorts are not strictly necessary, but were helpful
|
||||
// in reducing churn when switching to the current counter-creation scheme.
|
||||
// They also help to slightly decrease the overall size of the expression
|
||||
// table, due to more subexpressions being shared.
|
||||
pos.sort();
|
||||
neg.sort();
|
||||
|
||||
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
|
||||
sites.into_iter().map(|node| new.ensure_phys_counter(node)).collect::<Vec<_>>()
|
||||
};
|
||||
let mut pos = new_counters_for_sites(pos);
|
||||
let mut neg = new_counters_for_sites(neg);
|
||||
|
||||
// These sorts are also not strictly necessary; see above.
|
||||
pos.sort();
|
||||
neg.sort();
|
||||
|
||||
let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
|
||||
let new_counter = new.make_subtracted_sum(pos_counter, &neg);
|
||||
new.set_node_counter(bcb, new_counter);
|
||||
}
|
||||
|
||||
new
|
||||
}
|
||||
|
||||
/// Generates and stores coverage counter and coverage expression information
|
||||
/// associated with nodes in the coverage graph.
|
||||
pub(super) struct CoverageCounters {
|
||||
/// List of places where a counter-increment statement should be injected
|
||||
/// into MIR, each with its corresponding counter ID.
|
||||
phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
|
||||
next_counter_id: CounterId,
|
||||
|
||||
/// Coverage counters/expressions that are associated with individual BCBs.
|
||||
node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
|
||||
|
||||
/// Table of expression data, associating each expression ID with its
|
||||
/// corresponding operator (+ or -) and its LHS/RHS operands.
|
||||
expressions: IndexVec<ExpressionId, Expression>,
|
||||
/// Remember expressions that have already been created (or simplified),
|
||||
/// so that we don't create unnecessary duplicates.
|
||||
expressions_memo: FxHashMap<Expression, CovTerm>,
|
||||
}
|
||||
|
||||
impl CoverageCounters {
|
||||
fn with_num_bcbs(num_bcbs: usize) -> Self {
|
||||
Self {
|
||||
counter_increment_sites: IndexVec::new(),
|
||||
phys_counter_for_node: FxIndexMap::default(),
|
||||
next_counter_id: CounterId::ZERO,
|
||||
node_counters: IndexVec::from_elem_n(None, num_bcbs),
|
||||
expressions: IndexVec::new(),
|
||||
expressions_memo: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new physical counter for a BCB node or edge.
|
||||
fn make_phys_counter(&mut self, site: Site) -> BcbCounter {
|
||||
let id = self.counter_increment_sites.push(site);
|
||||
BcbCounter::Counter { id }
|
||||
/// Returns the physical counter for the given node, creating it if necessary.
|
||||
fn ensure_phys_counter(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
|
||||
let id = *self.phys_counter_for_node.entry(bcb).or_insert_with(|| {
|
||||
let id = self.next_counter_id;
|
||||
self.next_counter_id = id + 1;
|
||||
id
|
||||
});
|
||||
CovTerm::Counter(id)
|
||||
}
|
||||
|
||||
fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
|
||||
let new_expr = BcbExpression { lhs, op, rhs };
|
||||
*self.expressions_memo.entry(new_expr).or_insert_with(|| {
|
||||
fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> CovTerm {
|
||||
let new_expr = Expression { lhs, op, rhs };
|
||||
*self.expressions_memo.entry(new_expr.clone()).or_insert_with(|| {
|
||||
let id = self.expressions.push(new_expr);
|
||||
BcbCounter::Expression { id }
|
||||
CovTerm::Expression(id)
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a counter that is the sum of the given counters.
|
||||
///
|
||||
/// Returns `None` if the given list of counters was empty.
|
||||
fn make_sum(&mut self, counters: &[BcbCounter]) -> Option<BcbCounter> {
|
||||
fn make_sum(&mut self, counters: &[CovTerm]) -> Option<CovTerm> {
|
||||
counters
|
||||
.iter()
|
||||
.copied()
|
||||
|
@ -155,16 +183,18 @@ impl CoverageCounters {
|
|||
}
|
||||
|
||||
/// Creates a counter whose value is `lhs - SUM(rhs)`.
|
||||
fn make_subtracted_sum(&mut self, lhs: BcbCounter, rhs: &[BcbCounter]) -> BcbCounter {
|
||||
fn make_subtracted_sum(&mut self, lhs: CovTerm, rhs: &[CovTerm]) -> CovTerm {
|
||||
let Some(rhs_sum) = self.make_sum(rhs) else { return lhs };
|
||||
self.make_expression(lhs, Op::Subtract, rhs_sum)
|
||||
}
|
||||
|
||||
pub(super) fn num_counters(&self) -> usize {
|
||||
self.counter_increment_sites.len()
|
||||
let num_counters = self.phys_counter_for_node.len();
|
||||
assert_eq!(num_counters, self.next_counter_id.as_usize());
|
||||
num_counters
|
||||
}
|
||||
|
||||
fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter {
|
||||
fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> CovTerm {
|
||||
let existing = self.node_counters[bcb].replace(counter);
|
||||
assert!(
|
||||
existing.is_none(),
|
||||
|
@ -174,16 +204,16 @@ impl CoverageCounters {
|
|||
}
|
||||
|
||||
pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
|
||||
self.node_counters[bcb].map(|counter| counter.as_term())
|
||||
self.node_counters[bcb]
|
||||
}
|
||||
|
||||
/// Returns an iterator over all the nodes/edges in the coverage graph that
|
||||
/// Returns an iterator over all the nodes in the coverage graph that
|
||||
/// should have a counter-increment statement injected into MIR, along with
|
||||
/// each site's corresponding counter ID.
|
||||
pub(super) fn counter_increment_sites(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (CounterId, Site)> + Captures<'_> {
|
||||
self.counter_increment_sites.iter_enumerated().map(|(id, &site)| (id, site))
|
||||
) -> impl Iterator<Item = (CounterId, BasicCoverageBlock)> + Captures<'_> {
|
||||
self.phys_counter_for_node.iter().map(|(&site, &id)| (id, site))
|
||||
}
|
||||
|
||||
/// Returns an iterator over the subset of BCB nodes that have been associated
|
||||
|
@ -193,93 +223,13 @@ impl CoverageCounters {
|
|||
) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
|
||||
self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter {
|
||||
// Yield the BCB along with its associated expression ID.
|
||||
Some(BcbCounter::Expression { id }) => Some((bcb, id)),
|
||||
Some(CovTerm::Expression(id)) => Some((bcb, id)),
|
||||
// This BCB is associated with a counter or nothing, so skip it.
|
||||
Some(BcbCounter::Counter { .. }) | None => None,
|
||||
Some(CovTerm::Counter { .. } | CovTerm::Zero) | None => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
|
||||
let old_len = self.expressions.len();
|
||||
let expressions = self
|
||||
.expressions
|
||||
.into_iter()
|
||||
.map(|BcbExpression { lhs, op, rhs }| Expression {
|
||||
lhs: lhs.as_term(),
|
||||
op,
|
||||
rhs: rhs.as_term(),
|
||||
})
|
||||
.collect::<IndexVec<ExpressionId, _>>();
|
||||
|
||||
// Expression IDs are indexes into this vector, so make sure we didn't
|
||||
// accidentally invalidate them by changing its length.
|
||||
assert_eq!(old_len, expressions.len());
|
||||
expressions
|
||||
}
|
||||
}
|
||||
|
||||
struct Transcriber {
|
||||
old: NodeCounters<BasicCoverageBlock>,
|
||||
new: CoverageCounters,
|
||||
phys_counter_for_site: FxHashMap<Site, BcbCounter>,
|
||||
}
|
||||
|
||||
impl Transcriber {
|
||||
fn new(num_nodes: usize, old: NodeCounters<BasicCoverageBlock>) -> Self {
|
||||
Self {
|
||||
old,
|
||||
new: CoverageCounters::with_num_bcbs(num_nodes),
|
||||
phys_counter_for_site: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn transcribe_counters(
|
||||
mut self,
|
||||
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
|
||||
) -> CoverageCounters {
|
||||
for bcb in bcb_needs_counter.iter() {
|
||||
let site = Site::Node { bcb };
|
||||
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
|
||||
self.old.counter_expr(bcb).iter().partition_map(
|
||||
|&CounterTerm { node, op }| match op {
|
||||
Op::Add => Either::Left(node),
|
||||
Op::Subtract => Either::Right(node),
|
||||
},
|
||||
);
|
||||
|
||||
if pos.is_empty() {
|
||||
// If we somehow end up with no positive terms, fall back to
|
||||
// creating a physical counter. There's no known way for this
|
||||
// to happen, but we can avoid an ICE if it does.
|
||||
debug_assert!(false, "{site:?} has no positive counter terms");
|
||||
pos = vec![bcb];
|
||||
neg = vec![];
|
||||
}
|
||||
|
||||
pos.sort();
|
||||
neg.sort();
|
||||
|
||||
let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| {
|
||||
sites
|
||||
.into_iter()
|
||||
.map(|node| self.ensure_phys_counter(Site::Node { bcb: node }))
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let mut pos = new_counters_for_sites(pos);
|
||||
let mut neg = new_counters_for_sites(neg);
|
||||
|
||||
pos.sort();
|
||||
neg.sort();
|
||||
|
||||
let pos_counter = self.new.make_sum(&pos).expect("`pos` should not be empty");
|
||||
let new_counter = self.new.make_subtracted_sum(pos_counter, &neg);
|
||||
self.new.set_node_counter(bcb, new_counter);
|
||||
}
|
||||
|
||||
self.new
|
||||
}
|
||||
|
||||
fn ensure_phys_counter(&mut self, site: Site) -> BcbCounter {
|
||||
*self.phys_counter_for_site.entry(site).or_insert_with(|| self.new.make_phys_counter(site))
|
||||
self.expressions
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_span::Span;
|
|||
use rustc_span::def_id::LocalDefId;
|
||||
use tracing::{debug, debug_span, trace};
|
||||
|
||||
use crate::coverage::counters::{CoverageCounters, Site};
|
||||
use crate::coverage::counters::CoverageCounters;
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::mappings::ExtractedMappings;
|
||||
|
||||
|
@ -89,8 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
return;
|
||||
}
|
||||
|
||||
let coverage_counters =
|
||||
CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
|
||||
let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
|
||||
|
||||
let mappings = create_mappings(&extracted_mappings, &coverage_counters);
|
||||
if mappings.is_empty() {
|
||||
|
@ -239,14 +238,8 @@ fn inject_coverage_statements<'tcx>(
|
|||
coverage_counters: &CoverageCounters,
|
||||
) {
|
||||
// Inject counter-increment statements into MIR.
|
||||
for (id, site) in coverage_counters.counter_increment_sites() {
|
||||
// Determine the block to inject a counter-increment statement into.
|
||||
// For BCB nodes this is just their first block, but for edges we need
|
||||
// to create a new block between the two BCBs, and inject into that.
|
||||
let target_bb = match site {
|
||||
Site::Node { bcb } => graph[bcb].leader_bb(),
|
||||
};
|
||||
|
||||
for (id, bcb) in coverage_counters.counter_increment_sites() {
|
||||
let target_bb = graph[bcb].leader_bb();
|
||||
inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb);
|
||||
}
|
||||
|
||||
|
|
|
@ -3960,7 +3960,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
match res {
|
||||
Res::SelfCtor(_) // See #70549.
|
||||
| Res::Def(
|
||||
DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::ConstParam,
|
||||
DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst | DefKind::ConstParam,
|
||||
_,
|
||||
) if is_syntactic_ambiguity => {
|
||||
// Disambiguate in favor of a unit struct/variant or constant pattern.
|
||||
|
@ -3969,7 +3969,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
Some(res)
|
||||
}
|
||||
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static { .. }, _) => {
|
||||
Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
|
||||
// This is unambiguously a fresh binding, either syntactically
|
||||
// (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
|
||||
// to something unusable as a pattern (e.g., constructor function),
|
||||
|
@ -4005,7 +4005,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
);
|
||||
None
|
||||
}
|
||||
Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => {
|
||||
Res::Def(DefKind::Fn | DefKind::AssocFn, _) | Res::Local(..) | Res::Err => {
|
||||
// These entities are explicitly allowed to be shadowed by fresh bindings.
|
||||
None
|
||||
}
|
||||
|
|
|
@ -172,14 +172,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let bound_predicate = predicate.kind();
|
||||
let mut err = match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
let trait_ref = bound_predicate.rebind(data.trait_ref);
|
||||
debug!(?trait_ref);
|
||||
let trait_pred = bound_predicate.rebind(data);
|
||||
debug!(?trait_pred);
|
||||
|
||||
if let Err(e) = predicate.error_reported() {
|
||||
return e;
|
||||
}
|
||||
|
||||
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
|
||||
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) {
|
||||
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
|
||||
// other `Foo` impls are incoherent.
|
||||
return guar;
|
||||
|
@ -200,13 +200,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// avoid inundating the user with unnecessary errors, but we now
|
||||
// check upstream for type errors and don't add the obligations to
|
||||
// begin with in those cases.
|
||||
if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
|
||||
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) {
|
||||
match self.tainted_by_errors() {
|
||||
None => {
|
||||
let err = self.emit_inference_failure_err(
|
||||
obligation.cause.body_id,
|
||||
span,
|
||||
trait_ref.self_ty().skip_binder().into(),
|
||||
trait_pred.self_ty().skip_binder().into(),
|
||||
TypeAnnotationNeeded::E0282,
|
||||
false,
|
||||
);
|
||||
|
@ -251,10 +251,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
let mut ambiguities = compute_applicable_impls_for_diagnostics(
|
||||
self.infcx,
|
||||
&obligation.with(self.tcx, trait_ref),
|
||||
&obligation.with(self.tcx, trait_pred),
|
||||
);
|
||||
let has_non_region_infer =
|
||||
trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
|
||||
let has_non_region_infer = trait_pred
|
||||
.skip_binder()
|
||||
.trait_ref
|
||||
.args
|
||||
.types()
|
||||
.any(|t| !t.is_ty_or_numeric_infer());
|
||||
// It doesn't make sense to talk about applicable impls if there are more than a
|
||||
// handful of them. If there are a lot of them, but only a few of them have no type
|
||||
// params, we only show those, as they are more likely to be useful/intended.
|
||||
|
@ -294,7 +298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if impl_candidates.len() < 40 {
|
||||
self.report_similar_impl_candidates(
|
||||
impl_candidates.as_slice(),
|
||||
trait_ref,
|
||||
trait_pred,
|
||||
obligation.cause.body_id,
|
||||
&mut err,
|
||||
false,
|
||||
|
@ -306,7 +310,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if let ObligationCauseCode::WhereClause(def_id, _)
|
||||
| ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
|
||||
{
|
||||
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
|
||||
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
|
||||
}
|
||||
|
||||
if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
|
||||
|
|
|
@ -23,9 +23,7 @@ use rustc_middle::ty::print::{
|
|||
FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
|
||||
PrintTraitRefExt as _, with_forced_trimmed_paths,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
|
||||
};
|
||||
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
|
||||
use tracing::{debug, instrument};
|
||||
|
@ -155,12 +153,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(leaf_trait_predicate, &obligation)
|
||||
};
|
||||
|
||||
let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
|
||||
let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
|
||||
|
||||
if let Some(guar) = self.emit_specialized_closure_kind_error(
|
||||
&obligation,
|
||||
leaf_trait_ref,
|
||||
leaf_trait_predicate,
|
||||
) {
|
||||
return guar;
|
||||
}
|
||||
|
@ -202,14 +197,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
} = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);
|
||||
|
||||
let have_alt_message = message.is_some() || label.is_some();
|
||||
let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
|
||||
let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
|
||||
let is_unsize =
|
||||
self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize);
|
||||
self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
|
||||
let (message, notes, append_const_msg) = if is_try_conversion {
|
||||
(
|
||||
Some(format!(
|
||||
"`?` couldn't convert the error to `{}`",
|
||||
main_trait_ref.skip_binder().self_ty(),
|
||||
main_trait_predicate.skip_binder().self_ty(),
|
||||
)),
|
||||
vec![
|
||||
"the question mark operation (`?`) implicitly performs a \
|
||||
|
@ -230,12 +225,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
post_message,
|
||||
);
|
||||
|
||||
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_ref.def_id(), LangItem::TransmuteTrait)
|
||||
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
|
||||
{
|
||||
// Recompute the safe transmute reason and use that for the error reporting
|
||||
match self.get_safe_transmute_error_and_reason(
|
||||
obligation.clone(),
|
||||
main_trait_ref,
|
||||
main_trait_predicate,
|
||||
span,
|
||||
) {
|
||||
GetSafeTransmuteErrorAndReason::Silent => {
|
||||
|
@ -266,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
let mut suggested = false;
|
||||
if is_try_conversion {
|
||||
suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err);
|
||||
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
|
||||
}
|
||||
|
||||
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
|
||||
|
@ -274,12 +269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
ret_span,
|
||||
format!(
|
||||
"expected `{}` because of this",
|
||||
main_trait_ref.skip_binder().self_ty()
|
||||
main_trait_predicate.skip_binder().self_ty()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) {
|
||||
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
|
||||
self.add_tuple_trait_message(
|
||||
obligation.cause.code().peel_derives(),
|
||||
&mut err,
|
||||
|
@ -319,7 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// If it has a custom `#[rustc_on_unimplemented]`
|
||||
// error message, let's display it as the label!
|
||||
err.span_label(span, s);
|
||||
if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
|
||||
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
|
||||
// When the self type is a type param We don't need to "the trait
|
||||
// `std::marker::Sized` is not implemented for `T`" as we will point
|
||||
// at the type param with a label to suggest constraining it.
|
||||
|
@ -339,7 +334,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if let ObligationCauseCode::Coercion { source, target } =
|
||||
*obligation.cause.code().peel_derives()
|
||||
{
|
||||
if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) {
|
||||
if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) {
|
||||
self.suggest_borrowing_for_object_cast(
|
||||
&mut err,
|
||||
root_obligation,
|
||||
|
@ -368,7 +363,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
err.span_label(tcx.def_span(body), s);
|
||||
}
|
||||
|
||||
self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref);
|
||||
self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate);
|
||||
self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);
|
||||
suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);
|
||||
|
@ -376,7 +371,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
suggested = if let &[cand] = &impl_candidates[..] {
|
||||
let cand = cand.trait_ref;
|
||||
if let (ty::FnPtr(..), ty::FnDef(..)) =
|
||||
(cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
|
||||
(cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
|
||||
{
|
||||
// Wrap method receivers and `&`-references in parens
|
||||
let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
|
||||
|
@ -423,11 +418,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
span,
|
||||
leaf_trait_predicate,
|
||||
);
|
||||
self.note_version_mismatch(&mut err, leaf_trait_ref);
|
||||
self.note_version_mismatch(&mut err, leaf_trait_predicate);
|
||||
self.suggest_remove_await(&obligation, &mut err);
|
||||
self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);
|
||||
|
||||
if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) {
|
||||
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) {
|
||||
self.suggest_await_before_try(
|
||||
&mut err,
|
||||
&obligation,
|
||||
|
@ -455,9 +450,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id());
|
||||
let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id());
|
||||
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
|
||||
*leaf_trait_ref.skip_binder().self_ty().kind()
|
||||
*leaf_trait_predicate.skip_binder().self_ty().kind()
|
||||
{
|
||||
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
} else {
|
||||
|
@ -509,7 +504,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);
|
||||
self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref);
|
||||
self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate);
|
||||
|
||||
// Return early if the trait is Debug or Display and the invocation
|
||||
// originates within a standard library macro, because the output
|
||||
|
@ -527,7 +522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
if in_std_macro
|
||||
&& matches!(
|
||||
self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()),
|
||||
self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()),
|
||||
Some(sym::Debug | sym::Display)
|
||||
)
|
||||
{
|
||||
|
@ -785,21 +780,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn emit_specialized_closure_kind_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
mut trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> Option<ErrorGuaranteed> {
|
||||
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
|
||||
// doesn't extend the goal kind. This is worth reporting, but we can only do so
|
||||
// if we actually know which closure this goal comes from, so look at the cause
|
||||
// to see if we can extract that information.
|
||||
if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper)
|
||||
&& let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
|
||||
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
|
||||
&& let Some(found_kind) =
|
||||
trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
|
||||
&& let Some(expected_kind) =
|
||||
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
|
||||
trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
|
||||
&& !found_kind.extends(expected_kind)
|
||||
{
|
||||
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
|
||||
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
|
||||
trait_ref = parent.to_poly_trait_ref();
|
||||
trait_pred = parent;
|
||||
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
|
||||
obligation.cause.code()
|
||||
&& let Some(typeck_results) = &self.typeck_results
|
||||
|
@ -820,9 +816,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let self_ty = trait_ref.self_ty().skip_binder();
|
||||
let self_ty = trait_pred.self_ty().skip_binder();
|
||||
|
||||
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
|
||||
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
|
||||
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
|
||||
ty::Closure(def_id, args) => {
|
||||
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
|
||||
|
@ -837,7 +833,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
_ => return None,
|
||||
};
|
||||
|
||||
let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
|
||||
let expected_args =
|
||||
trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
|
||||
|
||||
// Verify that the arguments are compatible. If the signature is
|
||||
// mismatched, then we have a totally different error to report.
|
||||
|
@ -909,7 +906,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn try_conversion_context(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
) -> bool {
|
||||
let span = obligation.cause.span;
|
||||
|
@ -953,8 +950,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
|
||||
return false;
|
||||
}
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
|
||||
let self_ty = trait_pred.skip_binder().self_ty();
|
||||
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
|
||||
|
||||
let mut prev_ty = self.resolve_vars_if_possible(
|
||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||
|
@ -1223,18 +1220,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
goal: ty::TraitPredicate<'tcx>,
|
||||
assumption: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
// Fast path
|
||||
if goal.polarity != assumption.polarity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let trait_goal = goal.trait_ref;
|
||||
let trait_assumption = self.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
infer::BoundRegionConversionTime::HigherRankedType,
|
||||
assumption.to_poly_trait_ref(),
|
||||
assumption,
|
||||
);
|
||||
|
||||
self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption)
|
||||
self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref)
|
||||
}
|
||||
|
||||
fn can_match_projection(
|
||||
|
@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
pub(super) fn report_similar_impl_candidates(
|
||||
&self,
|
||||
impl_candidates: &[ImplCandidate<'tcx>],
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
body_def_id: LocalDefId,
|
||||
err: &mut Diag<'_>,
|
||||
other: bool,
|
||||
|
@ -1727,7 +1724,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// We'll check for the case where the reason for the mismatch is that the trait comes from
|
||||
// one crate version and the type comes from another crate version, even though they both
|
||||
// are from the same crate.
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
let trait_def_id = trait_pred.def_id();
|
||||
let trait_name = self.tcx.item_name(trait_def_id);
|
||||
let crate_name = self.tcx.crate_name(trait_def_id.krate);
|
||||
if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| {
|
||||
|
@ -1739,7 +1736,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// different crate `DefId`. We highlight the traits.
|
||||
|
||||
let found_type =
|
||||
if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() {
|
||||
if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() {
|
||||
Some(def.did())
|
||||
} else {
|
||||
None
|
||||
|
@ -1836,7 +1833,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if self.probe(|_| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
|
||||
self.enter_forall(trait_ref, |obligation_trait_ref| {
|
||||
self.enter_forall(trait_pred, |obligation_trait_ref| {
|
||||
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
|
||||
let impl_trait_ref = ocx.normalize(
|
||||
&ObligationCause::dummy(),
|
||||
|
@ -1864,7 +1861,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
let mut terrs = vec![];
|
||||
for (obligation_arg, impl_arg) in
|
||||
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
|
||||
std::iter::zip(obligation_trait_ref.trait_ref.args, impl_trait_ref.args)
|
||||
{
|
||||
if (obligation_arg, impl_arg).references_error() {
|
||||
return false;
|
||||
|
@ -1906,8 +1903,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let traits = self.cmp_traits(
|
||||
obligation_trait_ref.def_id,
|
||||
&obligation_trait_ref.args[1..],
|
||||
obligation_trait_ref.def_id(),
|
||||
&obligation_trait_ref.trait_ref.args[1..],
|
||||
impl_trait_ref.def_id,
|
||||
&impl_trait_ref.args[1..],
|
||||
);
|
||||
|
@ -1991,7 +1988,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
if let &[cand] = &candidates[..] {
|
||||
let (desc, mention_castable) =
|
||||
match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
|
||||
match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
|
||||
(ty::FnPtr(..), ty::FnDef(..)) => {
|
||||
(" implemented for fn pointer `", ", cast using `as`")
|
||||
}
|
||||
|
@ -2055,7 +2052,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
.filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let def_id = trait_ref.def_id();
|
||||
let def_id = trait_pred.def_id();
|
||||
if impl_candidates.is_empty() {
|
||||
if self.tcx.trait_is_auto(def_id)
|
||||
|| self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
|
||||
|
@ -2132,11 +2129,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
&& !self.tcx.trait_is_auto(def_id)
|
||||
&& !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
|
||||
{
|
||||
let trait_ref = trait_pred.to_poly_trait_ref();
|
||||
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
|
||||
self.report_similar_impl_candidates(
|
||||
&impl_candidates,
|
||||
trait_ref,
|
||||
trait_pred,
|
||||
body_def_id,
|
||||
err,
|
||||
true,
|
||||
|
@ -2173,12 +2169,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||
/// with the same path as `trait_ref`, a help message about
|
||||
/// a probable version mismatch is added to `err`
|
||||
fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool {
|
||||
fn note_version_mismatch(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let get_trait_impls = |trait_def_id| {
|
||||
let mut trait_impls = vec![];
|
||||
self.tcx.for_each_relevant_impl(
|
||||
trait_def_id,
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
trait_pred.skip_binder().self_ty(),
|
||||
|impl_def_id| {
|
||||
trait_impls.push(impl_def_id);
|
||||
},
|
||||
|
@ -2186,11 +2186,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
trait_impls
|
||||
};
|
||||
|
||||
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
|
||||
let required_trait_path = self.tcx.def_path_str(trait_pred.def_id());
|
||||
let traits_with_same_path: UnordSet<_> = self
|
||||
.tcx
|
||||
.visible_traits()
|
||||
.filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
|
||||
.filter(|trait_def_id| *trait_def_id != trait_pred.def_id())
|
||||
.map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id))
|
||||
.filter(|(p, _)| *p == required_trait_path)
|
||||
.collect();
|
||||
|
@ -2374,7 +2374,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn get_safe_transmute_error_and_reason(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
) -> GetSafeTransmuteErrorAndReason {
|
||||
use rustc_transmute::Answer;
|
||||
|
@ -2386,19 +2386,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Erase regions because layout code doesn't particularly care about regions.
|
||||
let trait_ref =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
|
||||
let trait_pred =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred));
|
||||
|
||||
let src_and_dst = rustc_transmute::Types {
|
||||
dst: trait_ref.args.type_at(0),
|
||||
src: trait_ref.args.type_at(1),
|
||||
dst: trait_pred.trait_ref.args.type_at(0),
|
||||
src: trait_pred.trait_ref.args.type_at(1),
|
||||
};
|
||||
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let Ok(assume) = ocx.structurally_normalize_const(
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
trait_ref.args.const_at(2),
|
||||
trait_pred.trait_ref.args.const_at(2),
|
||||
) else {
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
|
@ -2417,8 +2417,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
};
|
||||
|
||||
let dst = trait_ref.args.type_at(0);
|
||||
let src = trait_ref.args.type_at(1);
|
||||
let dst = trait_pred.trait_ref.args.type_at(0);
|
||||
let src = trait_pred.trait_ref.args.type_at(1);
|
||||
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
||||
|
||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||
|
@ -2566,12 +2566,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
trait_predicate.skip_binder().polarity,
|
||||
)
|
||||
{
|
||||
self.add_help_message_for_fn_trait(
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
err,
|
||||
implemented_kind,
|
||||
params,
|
||||
);
|
||||
self.add_help_message_for_fn_trait(trait_predicate, err, implemented_kind, params);
|
||||
} else if !trait_predicate.has_non_region_infer()
|
||||
&& self.predicate_can_apply(obligation.param_env, trait_predicate)
|
||||
{
|
||||
|
@ -2606,7 +2601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
|
||||
if !self.report_similar_impl_candidates(
|
||||
&impl_candidates,
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
trait_predicate,
|
||||
body_def_id,
|
||||
err,
|
||||
true,
|
||||
|
@ -2623,7 +2618,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
self.suggest_convert_to_slice(
|
||||
err,
|
||||
obligation,
|
||||
trait_predicate.to_poly_trait_ref(),
|
||||
trait_predicate,
|
||||
impl_candidates.as_slice(),
|
||||
span,
|
||||
);
|
||||
|
@ -2634,7 +2629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
fn add_help_message_for_fn_trait(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
implemented_kind: ty::ClosureKind,
|
||||
params: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
|
@ -2647,12 +2642,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// to implement.
|
||||
let selected_kind = self
|
||||
.tcx
|
||||
.fn_trait_kind_from_def_id(trait_ref.def_id())
|
||||
.fn_trait_kind_from_def_id(trait_pred.def_id())
|
||||
.expect("expected to map DefId to ClosureKind");
|
||||
if !implemented_kind.extends(selected_kind) {
|
||||
err.note(format!(
|
||||
"`{}` implements `{}`, but it must implement `{}`, which is more general",
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
trait_pred.skip_binder().self_ty(),
|
||||
implemented_kind,
|
||||
selected_kind
|
||||
));
|
||||
|
@ -2660,7 +2655,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
// Note any argument mismatches
|
||||
let given_ty = params.skip_binder();
|
||||
let expected_ty = trait_ref.skip_binder().args.type_at(1);
|
||||
let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
|
||||
if let ty::Tuple(given) = given_ty.kind()
|
||||
&& let ty::Tuple(expected) = expected_ty.kind()
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_hir::{AttrArgs, AttrKind, Attribute};
|
|||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TyCtxt};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
|
||||
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
|
||||
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::{Span, Symbol, kw, sym};
|
||||
|
@ -42,18 +42,18 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
|
|||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||
let tcx = self.tcx;
|
||||
let param_env = obligation.param_env;
|
||||
self.enter_forall(trait_ref, |trait_ref| {
|
||||
let trait_self_ty = trait_ref.self_ty();
|
||||
self.enter_forall(trait_pred, |trait_pred| {
|
||||
let trait_self_ty = trait_pred.self_ty();
|
||||
|
||||
let mut self_match_impls = vec![];
|
||||
let mut fuzzy_match_impls = vec![];
|
||||
|
||||
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
|
||||
self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| {
|
||||
let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
|
||||
|
@ -64,7 +64,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
self_match_impls.push((def_id, impl_args));
|
||||
|
||||
if iter::zip(
|
||||
trait_ref.args.types().skip(1),
|
||||
trait_pred.trait_ref.args.types().skip(1),
|
||||
impl_trait_ref.args.types().skip(1),
|
||||
)
|
||||
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
|
||||
|
@ -117,7 +117,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let (def_id, args) = self
|
||||
.impl_similar_to(trait_pred.to_poly_trait_ref(), obligation)
|
||||
.impl_similar_to(trait_pred, obligation)
|
||||
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
|
||||
let trait_pred = trait_pred.skip_binder();
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ use rustc_middle::ty::print::{
|
|||
with_forced_trimmed_paths, with_no_trimmed_paths,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericArgs, InferTy, IsSuggestable, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable,
|
||||
TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast,
|
||||
suggest_arbitrary_trait_bound, suggest_constraining_type_param,
|
||||
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
|
||||
TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound,
|
||||
suggest_constraining_type_param,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
@ -218,15 +218,15 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
|
|||
(_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
|
||||
(None, Some((ident, []))) => (
|
||||
ident.span.shrink_to_hi(),
|
||||
format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
|
||||
format!(": {}", trait_pred.print_modifiers_and_trait_path()),
|
||||
),
|
||||
(_, Some((_, [.., bounds]))) => (
|
||||
bounds.span().shrink_to_hi(),
|
||||
format!(" + {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
|
||||
format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
|
||||
),
|
||||
(Some(_), Some((_, []))) => (
|
||||
hir_generics.span.shrink_to_hi(),
|
||||
format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()),
|
||||
format!(": {}", trait_pred.print_modifiers_and_trait_path()),
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -3729,7 +3729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) {
|
||||
let rhs_span = match obligation.cause.code() {
|
||||
ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
|
||||
|
@ -3737,8 +3737,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
_ => return,
|
||||
};
|
||||
if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
|
||||
&& let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().args.type_at(1).kind()
|
||||
if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
|
||||
&& let ty::Infer(InferTy::IntVar(_)) =
|
||||
trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
rhs_span.shrink_to_hi(),
|
||||
|
@ -4448,7 +4449,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
candidate_impls: &[ImplCandidate<'tcx>],
|
||||
span: Span,
|
||||
) {
|
||||
|
@ -4464,7 +4465,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// 1. `[T; _]` (array of T)
|
||||
// 2. `&[T; _]` (reference to array of T)
|
||||
// 3. `&mut [T; _]` (mutable reference to array of T)
|
||||
let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() {
|
||||
let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() {
|
||||
ty::Array(element_ty, _) => (element_ty, None),
|
||||
|
||||
ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() {
|
||||
|
@ -4620,14 +4621,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
pub(super) fn suggest_desugaring_async_fn_in_trait(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) {
|
||||
// Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
|
||||
if self.tcx.features().return_type_notation() {
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
let trait_def_id = trait_pred.def_id();
|
||||
|
||||
// Only suggest specifying auto traits
|
||||
if !self.tcx.trait_is_auto(trait_def_id) {
|
||||
|
@ -4635,7 +4636,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Look for an RPITIT
|
||||
let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else {
|
||||
let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else {
|
||||
return;
|
||||
};
|
||||
let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_infer::traits::{
|
|||
Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
|
||||
};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_type_ir::Interner;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
@ -186,10 +186,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
selcx.infcx.probe(|_| {
|
||||
// We checked the polarity already
|
||||
match selcx.match_normalize_trait_ref(
|
||||
obligation,
|
||||
placeholder_trait_predicate.trait_ref,
|
||||
bound.to_poly_trait_ref(),
|
||||
bound.map_bound(|pred| pred.trait_ref),
|
||||
) {
|
||||
Ok(None) => {
|
||||
candidates.vec.push(ProjectionCandidate(idx));
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_type_ir::elaborate;
|
||||
|
@ -458,8 +458,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ensure_sufficient_stack(|| {
|
||||
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
|
||||
|
||||
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
|
||||
let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
|
||||
assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive);
|
||||
let trait_ref =
|
||||
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
|
||||
let trait_obligations = self.impl_or_trait_obligations(
|
||||
&cause,
|
||||
obligation.recursion_depth + 1,
|
||||
|
|
|
@ -97,6 +97,11 @@ tidy:
|
|||
prepare:
|
||||
$(Q)$(BOOTSTRAP) build --stage 2 --dry-run
|
||||
|
||||
# Set of tests that represent around half of the time of the test suite.
|
||||
# Used to split tests across multiple CI runners.
|
||||
STAGE_2_TEST_SET1 := test --stage 2 --skip=compiler --skip=src
|
||||
STAGE_2_TEST_SET2 := test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
|
||||
|
||||
## MSVC native builders
|
||||
|
||||
# this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows
|
||||
|
@ -105,6 +110,10 @@ ci-msvc-py:
|
|||
ci-msvc-ps1:
|
||||
$(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --skip tidy
|
||||
ci-msvc: ci-msvc-py ci-msvc-ps1
|
||||
ci-msvc-py-set1:
|
||||
$(Q)$(CFG_SRC_DIR)/x.py $(STAGE_2_TEST_SET1)
|
||||
ci-msvc-ps1-set2:
|
||||
$(Q)$(CFG_SRC_DIR)/x.ps1 $(STAGE_2_TEST_SET2)
|
||||
|
||||
## MingW native builders
|
||||
|
||||
|
@ -112,9 +121,9 @@ ci-msvc: ci-msvc-py ci-msvc-ps1
|
|||
# Used to split tests across multiple CI runners.
|
||||
# Test both x and bootstrap entrypoints.
|
||||
ci-mingw-x:
|
||||
$(Q)$(CFG_SRC_DIR)/x test --stage 2 --skip=compiler --skip=src
|
||||
$(Q)$(CFG_SRC_DIR)/x $(STAGE_2_TEST_SET1)
|
||||
ci-mingw-bootstrap:
|
||||
$(Q)$(BOOTSTRAP) test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest
|
||||
$(Q)$(BOOTSTRAP) $(STAGE_2_TEST_SET2)
|
||||
ci-mingw: ci-mingw-x ci-mingw-bootstrap
|
||||
|
||||
.PHONY: dist
|
||||
|
|
|
@ -305,8 +305,6 @@ For targets: `mips-unknown-linux-gnu`
|
|||
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
|
||||
- Path and misc options > Use a mirror = ENABLE
|
||||
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
|
||||
- Path and misc options > Patches origin = Bundled, then local
|
||||
- Path and misc options > Local patch directory = /tmp/patches
|
||||
- Target options > Target Architecture = mips
|
||||
- Target options > ABI = o32
|
||||
- Target options > Endianness = Big endian
|
||||
|
@ -327,8 +325,6 @@ For targets: `mipsel-unknown-linux-gnu`
|
|||
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
|
||||
- Path and misc options > Use a mirror = ENABLE
|
||||
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
|
||||
- Path and misc options > Patches origin = Bundled, then local
|
||||
- Path and misc options > Local patch directory = /tmp/patches
|
||||
- Target options > Target Architecture = mips
|
||||
- Target options > ABI = o32
|
||||
- Target options > Endianness = Little endian
|
||||
|
@ -349,8 +345,6 @@ For targets: `mips64-unknown-linux-gnuabi64`
|
|||
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
|
||||
- Path and misc options > Use a mirror = ENABLE
|
||||
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
|
||||
- Path and misc options > Patches origin = Bundled, then local
|
||||
- Path and misc options > Local patch directory = /tmp/patches
|
||||
- Target options > Target Architecture = mips
|
||||
- Target options > ABI = n64
|
||||
- Target options > Endianness = Big endian
|
||||
|
@ -370,8 +364,6 @@ For targets: `mips64el-unknown-linux-gnuabi64`
|
|||
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
|
||||
- Path and misc options > Use a mirror = ENABLE
|
||||
- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
|
||||
- Path and misc options > Patches origin = Bundled, then local
|
||||
- Path and misc options > Local patch directory = /tmp/patches
|
||||
- Target options > Target Architecture = mips
|
||||
- Target options > ABI = n64
|
||||
- Target options > Endianness = Little endian
|
||||
|
|
|
@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
|
|||
WORKDIR /tmp
|
||||
|
||||
COPY scripts/crosstool-ng-build.sh /scripts/
|
||||
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
|
||||
COPY host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig /tmp/crosstool.defconfig
|
||||
RUN /scripts/crosstool-ng-build.sh
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
|
|||
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
|
||||
CT_USE_MIRROR=y
|
||||
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
|
||||
CT_PATCH_BUNDLED_LOCAL=y
|
||||
CT_LOCAL_PATCH_DIR="/tmp/patches"
|
||||
CT_ARCH_MIPS=y
|
||||
CT_ARCH_mips_o32=y
|
||||
CT_ARCH_ARCH="mips32r2"
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
From 43c2948756bb6e144c7b871e827bba37d61ad3a3 Mon Sep 17 00:00:00 2001
|
||||
From: Aurelien Jarno <aurelien@aurel32.net>
|
||||
Date: Sat, 18 Jun 2016 19:11:23 +0200
|
||||
Subject: [PATCH 1/2] MIPS, SPARC: fix wrong vfork aliases in libpthread.so
|
||||
|
||||
With recent binutils versions the GNU libc fails to build on at least
|
||||
MISP and SPARC, with this kind of error:
|
||||
|
||||
/home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0'
|
||||
/home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here
|
||||
|
||||
It appears that on these architectures pt-vfork.S includes vfork.S
|
||||
(through the alpha version of pt-vfork.S) and that the __vfork aliases
|
||||
are not conditionalized on IS_IN (libc) like on other architectures.
|
||||
Therefore the aliases are also wrongly included in libpthread.so.
|
||||
|
||||
Fix this by properly conditionalizing the aliases like on other
|
||||
architectures.
|
||||
|
||||
Changelog:
|
||||
* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize
|
||||
hidden_def, weak_alias and strong_alias on [IS_IN (libc)].
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
|
||||
---
|
||||
sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
index 8c6615143708..c0c0ce699159 100644
|
||||
--- a/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
@@ -106,6 +106,8 @@ L(error):
|
||||
#endif
|
||||
END(__vfork)
|
||||
|
||||
+#if IS_IN (libc)
|
||||
libc_hidden_def(__vfork)
|
||||
weak_alias (__vfork, vfork)
|
||||
strong_alias (__vfork, __libc_vfork)
|
||||
+#endif
|
||||
--
|
||||
2.37.3
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
From b87c1ec3fa398646f042a68f0ce0f7d09c1348c7 Mon Sep 17 00:00:00 2001
|
||||
From: Aurelien Jarno <aurelien@aurel32.net>
|
||||
Date: Tue, 21 Jun 2016 23:59:37 +0200
|
||||
Subject: [PATCH 2/2] MIPS, SPARC: more fixes to the vfork aliases in
|
||||
libpthread.so
|
||||
|
||||
Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS
|
||||
and SPARC, but failed to do it correctly, introducing an ABI change.
|
||||
|
||||
This patch does the remaining changes needed to align the MIPS and SPARC
|
||||
vfork implementations with the other architectures. That way the the
|
||||
alpha version of pt-vfork.S works correctly for MIPS and SPARC. The
|
||||
changes for alpha were done in 82aab97c.
|
||||
|
||||
Changelog:
|
||||
* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into
|
||||
__libc_vfork.
|
||||
(__vfork) [IS_IN (libc)]: Remove alias.
|
||||
(__libc_vfork) [IS_IN (libc)]: Define as an alias.
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
|
||||
---
|
||||
sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
index c0c0ce699159..1867c8626ebe 100644
|
||||
--- a/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
+++ b/sysdeps/unix/sysv/linux/mips/vfork.S
|
||||
@@ -31,13 +31,13 @@
|
||||
LOCALSZ= 1
|
||||
FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
|
||||
GPOFF= FRAMESZ-(1*SZREG)
|
||||
-NESTED(__vfork,FRAMESZ,sp)
|
||||
+NESTED(__libc_vfork,FRAMESZ,sp)
|
||||
#ifdef __PIC__
|
||||
SETUP_GP
|
||||
#endif
|
||||
PTR_SUBU sp, FRAMESZ
|
||||
cfi_adjust_cfa_offset (FRAMESZ)
|
||||
- SETUP_GP64_REG (a5, __vfork)
|
||||
+ SETUP_GP64_REG (a5, __libc_vfork)
|
||||
#ifdef __PIC__
|
||||
SAVE_GP (GPOFF)
|
||||
#endif
|
||||
@@ -104,10 +104,10 @@ L(error):
|
||||
RESTORE_GP64_REG
|
||||
j __syscall_error
|
||||
#endif
|
||||
- END(__vfork)
|
||||
+ END(__libc_vfork)
|
||||
|
||||
#if IS_IN (libc)
|
||||
-libc_hidden_def(__vfork)
|
||||
-weak_alias (__vfork, vfork)
|
||||
-strong_alias (__vfork, __libc_vfork)
|
||||
+weak_alias (__libc_vfork, vfork)
|
||||
+strong_alias (__libc_vfork, __vfork)
|
||||
+libc_hidden_def (__vfork)
|
||||
#endif
|
||||
--
|
||||
2.37.3
|
||||
|
|
@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
|
|||
WORKDIR /tmp
|
||||
|
||||
COPY scripts/crosstool-ng-build.sh /scripts/
|
||||
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
|
||||
COPY host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig /tmp/crosstool.defconfig
|
||||
RUN /scripts/crosstool-ng-build.sh
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
|
|||
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
|
||||
CT_USE_MIRROR=y
|
||||
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
|
||||
CT_PATCH_BUNDLED_LOCAL=y
|
||||
CT_LOCAL_PATCH_DIR="/tmp/patches"
|
||||
CT_ARCH_MIPS=y
|
||||
CT_ARCH_mips_n64=y
|
||||
CT_ARCH_64=y
|
||||
|
|
|
@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
|
|||
WORKDIR /tmp
|
||||
|
||||
COPY scripts/crosstool-ng-build.sh /scripts/
|
||||
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
|
||||
COPY host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig /tmp/crosstool.defconfig
|
||||
RUN /scripts/crosstool-ng-build.sh
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
|
|||
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
|
||||
CT_USE_MIRROR=y
|
||||
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
|
||||
CT_PATCH_BUNDLED_LOCAL=y
|
||||
CT_LOCAL_PATCH_DIR="/tmp/patches"
|
||||
CT_ARCH_MIPS=y
|
||||
CT_ARCH_mips_n64=y
|
||||
CT_ARCH_LE=y
|
||||
|
|
|
@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
|
|||
WORKDIR /tmp
|
||||
|
||||
COPY scripts/crosstool-ng-build.sh /scripts/
|
||||
COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
|
||||
COPY host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig /tmp/crosstool.defconfig
|
||||
RUN /scripts/crosstool-ng-build.sh
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4"
|
|||
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
|
||||
CT_USE_MIRROR=y
|
||||
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
|
||||
CT_PATCH_BUNDLED_LOCAL=y
|
||||
CT_LOCAL_PATCH_DIR="/tmp/patches"
|
||||
CT_ARCH_MIPS=y
|
||||
CT_ARCH_mips_o32=y
|
||||
CT_ARCH_LE=y
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
FROM ubuntu:22.04
|
||||
# We use the ghcr base image because ghcr doesn't have a rate limit
|
||||
# and the mingw-check-tidy job doesn't cache docker images in CI.
|
||||
FROM ghcr.io/rust-lang/ubuntu:22.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
|
|
@ -448,11 +448,18 @@ auto:
|
|||
SCRIPT: make ci-msvc
|
||||
<<: *job-windows-8c
|
||||
|
||||
- name: i686-msvc
|
||||
# i686-msvc is split into two jobs to run tests in parallel.
|
||||
- name: i686-msvc-1
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
|
||||
SCRIPT: make ci-msvc
|
||||
<<: *job-windows-8c
|
||||
SCRIPT: make ci-msvc-py-set1
|
||||
<<: *job-windows
|
||||
|
||||
- name: i686-msvc-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
|
||||
SCRIPT: make ci-msvc-ps1-set2
|
||||
<<: *job-windows
|
||||
|
||||
# x86_64-msvc-ext is split into multiple jobs to run tests in parallel.
|
||||
- name: x86_64-msvc-ext1
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
error[E0005]: refutable pattern in local binding
|
||||
--> $DIR/resolve-issue-135614-assoc-const.rs:21:9
|
||||
|
|
||||
LL | let DEFAULT: u32 = 0;
|
||||
| ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
|
||||
LL | const DEFAULT: u32 = 0;
|
||||
| ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
|
||||
|
|
||||
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
|
||||
= note: the matched value is of type `u32`
|
||||
help: introduce a variable instead
|
||||
|
|
||||
LL | let DEFAULT_var: u32 = 0;
|
||||
| ~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0005`.
|
|
@ -0,0 +1,30 @@
|
|||
error[E0658]: `use` associated items of traits is unstable
|
||||
--> $DIR/resolve-issue-135614-assoc-const.rs:6:5
|
||||
|
|
||||
LL | use MyDefault::DEFAULT;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
|
||||
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0005]: refutable pattern in local binding
|
||||
--> $DIR/resolve-issue-135614-assoc-const.rs:21:9
|
||||
|
|
||||
LL | let DEFAULT: u32 = 0;
|
||||
| ^^^^^^^ pattern `1_u32..=u32::MAX` not covered
|
||||
LL | const DEFAULT: u32 = 0;
|
||||
| ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable
|
||||
|
|
||||
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html
|
||||
= note: the matched value is of type `u32`
|
||||
help: introduce a variable instead
|
||||
|
|
||||
LL | let DEFAULT_var: u32 = 0;
|
||||
| ~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0005, E0658.
|
||||
For more information about an error, try `rustc --explain E0005`.
|
30
tests/ui/resolve/resolve-issue-135614-assoc-const.rs
Normal file
30
tests/ui/resolve/resolve-issue-135614-assoc-const.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
//@ revisions: normal import_trait_associated_functions
|
||||
#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
|
||||
|
||||
// Makes sure that imported constant can be used in pattern bindings.
|
||||
|
||||
use MyDefault::DEFAULT; //[normal]~ ERROR `use` associated items of traits is unstable
|
||||
|
||||
trait MyDefault {
|
||||
const DEFAULT: Self;
|
||||
}
|
||||
|
||||
impl MyDefault for u32 {
|
||||
const DEFAULT: u32 = 0;
|
||||
}
|
||||
|
||||
impl MyDefault for () {
|
||||
const DEFAULT: () = ();
|
||||
}
|
||||
|
||||
fn foo(x: u32) -> u32 {
|
||||
let DEFAULT: u32 = 0; //~ ERROR refutable pattern in local binding
|
||||
const DEFAULT: u32 = 0;
|
||||
if let DEFAULT = x { DEFAULT } else { 1 }
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let DEFAULT = ();
|
||||
}
|
||||
|
||||
fn main() {}
|
13
tests/ui/resolve/resolve-issue-135614.normal.stderr
Normal file
13
tests/ui/resolve/resolve-issue-135614.normal.stderr
Normal file
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: `use` associated items of traits is unstable
|
||||
--> $DIR/resolve-issue-135614.rs:7:5
|
||||
|
|
||||
LL | use A::b;
|
||||
| ^^^^
|
||||
|
|
||||
= note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information
|
||||
= help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
15
tests/ui/resolve/resolve-issue-135614.rs
Normal file
15
tests/ui/resolve/resolve-issue-135614.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
//@ revisions: normal import_trait_associated_functions
|
||||
//@[import_trait_associated_functions] check-pass
|
||||
#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))]
|
||||
|
||||
// Makes sure that imported associated functions are shadowed by the local declarations.
|
||||
|
||||
use A::b; //[normal]~ ERROR `use` associated items of traits is unstable
|
||||
|
||||
trait A {
|
||||
fn b() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let b: ();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue