mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #123968 - jieyouxu:rollup-1pnkxor, r=jieyouxu
Rollup of 12 pull requests Successful merges: - #123423 (Distribute LLVM bitcode linker as a preview component) - #123548 (libtest: also measure time in Miri) - #123666 (Fix some typos in doc) - #123864 (Remove a HACK by instead inferring opaque types during expected/formal type checking) - #123896 (Migrate some diagnostics in `rustc_resolve` to session diagnostic) - #123919 (builtin-derive: tag → discriminant) - #123922 (Remove magic constants when using `base_n`.) - #123931 (Don't leak unnameable types in `-> _` recover) - #123933 (move the LargeAssignments lint logic into its own file) - #123934 (`rustc_data_structures::graph` mini refactor) - #123941 (Fix UB in LLVM FFI when passing zero or >1 bundle) - #123957 (disable create_dir_all_bare test on all(miri, windows)) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
99d0186b1d
@ -216,23 +216,14 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D>
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
|
||||
type Node = RegionVid;
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.constraint_graph.first_constraints.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
|
||||
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> {
|
||||
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
self.outgoing_regions(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'tcx, D: ConstraintGraphDirection> graph::GraphSuccessors<'_>
|
||||
for RegionGraph<'s, 'tcx, D>
|
||||
{
|
||||
type Item = RegionVid;
|
||||
type Iter = Successors<'s, 'tcx, D>;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||
@ -262,7 +262,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
|
||||
|
||||
// We first handle the cases where the loan doesn't go out of scope, depending on the issuing
|
||||
// region's successors.
|
||||
for successor in self.regioncx.region_graph().depth_first_search(issuing_region) {
|
||||
for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
|
||||
// 1. Via applied member constraints
|
||||
//
|
||||
// The issuing region can flow into the choice regions, and they are either:
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::constraints::ConstraintSccIndex;
|
||||
use crate::RegionInferenceContext;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_data_structures::graph::vec_graph::VecGraph;
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use std::ops::Range;
|
||||
|
||||
@ -23,8 +23,7 @@ impl ReverseSccGraph {
|
||||
scc0: ConstraintSccIndex,
|
||||
) -> impl Iterator<Item = RegionVid> + 'a {
|
||||
let mut duplicates = FxIndexSet::default();
|
||||
self.graph
|
||||
.depth_first_search(scc0)
|
||||
graph::depth_first_search(&self.graph, scc0)
|
||||
.flat_map(move |scc1| {
|
||||
self.scc_regions
|
||||
.get(&scc1)
|
||||
|
@ -1,5 +1,4 @@
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
@ -64,7 +63,10 @@ pub(super) fn trace<'mir, 'tcx>(
|
||||
// Traverse each issuing region's constraints, and record the loan as flowing into the
|
||||
// outlived region.
|
||||
for (loan, issuing_region_data) in borrow_set.iter_enumerated() {
|
||||
for succ in region_graph.depth_first_search(issuing_region_data.region) {
|
||||
for succ in rustc_data_structures::graph::depth_first_search(
|
||||
®ion_graph,
|
||||
issuing_region_data.region,
|
||||
) {
|
||||
// We don't need to mention that a loan flows into its issuing region.
|
||||
if succ == issuing_region_data.region {
|
||||
continue;
|
||||
|
@ -181,8 +181,8 @@ fn cs_clone(
|
||||
all_fields = af;
|
||||
vdata = &variant.data;
|
||||
}
|
||||
EnumTag(..) | AllFieldlessEnum(..) => {
|
||||
cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
|
||||
EnumDiscr(..) | AllFieldlessEnum(..) => {
|
||||
cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",))
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
|
||||
|
@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord(
|
||||
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
|
||||
|
||||
// Order in which to perform matching
|
||||
let tag_then_data = if let Annotatable::Item(item) = item
|
||||
let discr_then_data = if let Annotatable::Item(item) = item
|
||||
&& let ItemKind::Enum(def, _) = &item.kind
|
||||
{
|
||||
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
|
||||
match dataful.iter().filter(|&&b| b).count() {
|
||||
// No data, placing the tag check first makes codegen simpler
|
||||
// No data, placing the discriminant check first makes codegen simpler
|
||||
0 => true,
|
||||
1..=2 => false,
|
||||
_ => (0..dataful.len() - 1).any(|i| {
|
||||
@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord(
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
|
||||
cs_partial_cmp(cx, span, substr, tag_then_data)
|
||||
cs_partial_cmp(cx, span, substr, discr_then_data)
|
||||
})),
|
||||
};
|
||||
|
||||
@ -72,7 +72,7 @@ fn cs_partial_cmp(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
tag_then_data: bool,
|
||||
discr_then_data: bool,
|
||||
) -> BlockOrExpr {
|
||||
let test_id = Ident::new(sym::cmp, span);
|
||||
let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
|
||||
@ -108,12 +108,12 @@ fn cs_partial_cmp(
|
||||
// cmp => cmp
|
||||
// }
|
||||
// ```
|
||||
// where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
|
||||
// against the enum variants. This means that we begin by comparing the enum tags,
|
||||
// where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match`
|
||||
// against the enum variants. This means that we begin by comparing the enum discriminants,
|
||||
// before either inspecting their contents (if they match), or returning
|
||||
// the `cmp::Ordering` of comparing the enum tags.
|
||||
// the `cmp::Ordering` of comparing the enum discriminants.
|
||||
// ```
|
||||
// match partial_cmp(self_tag, other_tag) {
|
||||
// match partial_cmp(self_discr, other_discr) {
|
||||
// Some(Ordering::Equal) => match (self, other) {
|
||||
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
|
||||
// (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
|
||||
@ -126,12 +126,12 @@ fn cs_partial_cmp(
|
||||
// ```
|
||||
// match (self, other) {
|
||||
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
|
||||
// _ => partial_cmp(self_tag, other_tag)
|
||||
// _ => partial_cmp(self_discr, other_discr)
|
||||
// }
|
||||
// ```
|
||||
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
|
||||
|
||||
if !tag_then_data
|
||||
if !discr_then_data
|
||||
&& let ExprKind::Match(_, arms, _) = &mut expr1.kind
|
||||
&& let Some(last) = arms.last_mut()
|
||||
&& let PatKind::Wild = last.pat.kind
|
||||
|
@ -53,7 +53,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
|
||||
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
||||
EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
|
||||
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
|
||||
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
|
||||
EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
|
||||
cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
|
||||
}
|
||||
};
|
||||
|
@ -21,7 +21,7 @@
|
||||
//! `struct T(i32, char)`).
|
||||
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
|
||||
//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
|
||||
//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
|
||||
//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants.
|
||||
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
|
||||
//! being derived upon is either an enum or struct respectively. (Any
|
||||
//! argument with type Self is just grouped among the non-self
|
||||
@ -143,11 +143,11 @@
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! For the tags,
|
||||
//! For the discriminants,
|
||||
//!
|
||||
//! ```text
|
||||
//! EnumTag(
|
||||
//! &[<ident of self tag>, <ident of other tag>],
|
||||
//! EnumDiscr(
|
||||
//! &[<ident of self discriminant>, <ident of other discriminant>],
|
||||
//! <expr to combine with>,
|
||||
//! )
|
||||
//! ```
|
||||
@ -315,10 +315,10 @@ pub enum SubstructureFields<'a> {
|
||||
/// variant.
|
||||
EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
|
||||
|
||||
/// The tag of an enum. The first field is a `FieldInfo` for the tags, as
|
||||
/// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
|
||||
/// if they were fields. The second field is the expression to combine the
|
||||
/// tag expression with; it will be `None` if no match is necessary.
|
||||
EnumTag(FieldInfo, Option<P<Expr>>),
|
||||
/// discriminant expression with; it will be `None` if no match is necessary.
|
||||
EnumDiscr(FieldInfo, Option<P<Expr>>),
|
||||
|
||||
/// A static method where `Self` is a struct.
|
||||
StaticStruct(&'a ast::VariantData, StaticFields),
|
||||
@ -1137,9 +1137,9 @@ impl<'a> MethodDef<'a> {
|
||||
/// impl ::core::cmp::PartialEq for A {
|
||||
/// #[inline]
|
||||
/// fn eq(&self, other: &A) -> bool {
|
||||
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
/// __self_tag == __arg1_tag
|
||||
/// let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
/// let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
/// __self_discr == __arg1_discr
|
||||
/// && match (self, other) {
|
||||
/// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
|
||||
/// _ => true,
|
||||
@ -1148,7 +1148,7 @@ impl<'a> MethodDef<'a> {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Creates a tag check combined with a match for a tuple of all
|
||||
/// Creates a discriminant check combined with a match for a tuple of all
|
||||
/// `selflike_args`, with an arm for each variant with fields, possibly an
|
||||
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
|
||||
/// `Unify`), and possibly a default arm.
|
||||
@ -1169,7 +1169,7 @@ impl<'a> MethodDef<'a> {
|
||||
let span = trait_.span;
|
||||
let variants = &enum_def.variants;
|
||||
|
||||
// Traits that unify fieldless variants always use the tag(s).
|
||||
// Traits that unify fieldless variants always use the discriminant(s).
|
||||
let unify_fieldless_variants =
|
||||
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
|
||||
|
||||
@ -1199,25 +1199,25 @@ impl<'a> MethodDef<'a> {
|
||||
//
|
||||
// e.g. for `PartialEq::eq` builds two statements:
|
||||
// ```
|
||||
// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
// let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
// let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
// ```
|
||||
let get_tag_pieces = |cx: &ExtCtxt<'_>| {
|
||||
let tag_idents: Vec<_> = prefixes
|
||||
let get_discr_pieces = |cx: &ExtCtxt<'_>| {
|
||||
let discr_idents: Vec<_> = prefixes
|
||||
.iter()
|
||||
.map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
|
||||
.map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span))
|
||||
.collect();
|
||||
|
||||
let mut tag_exprs: Vec<_> = tag_idents
|
||||
let mut discr_exprs: Vec<_> = discr_idents
|
||||
.iter()
|
||||
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
|
||||
.collect();
|
||||
|
||||
let self_expr = tag_exprs.remove(0);
|
||||
let other_selflike_exprs = tag_exprs;
|
||||
let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
|
||||
let self_expr = discr_exprs.remove(0);
|
||||
let other_selflike_exprs = discr_exprs;
|
||||
let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
|
||||
|
||||
let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args)
|
||||
let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
|
||||
.map(|(&ident, selflike_arg)| {
|
||||
let variant_value = deriving::call_intrinsic(
|
||||
cx,
|
||||
@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
(tag_field, tag_let_stmts)
|
||||
(discr_field, discr_let_stmts)
|
||||
};
|
||||
|
||||
// There are some special cases involving fieldless enums where no
|
||||
@ -1239,19 +1239,19 @@ impl<'a> MethodDef<'a> {
|
||||
if variants.len() > 1 {
|
||||
match self.fieldless_variants_strategy {
|
||||
FieldlessVariantsStrategy::Unify => {
|
||||
// If the type is fieldless and the trait uses the tag and
|
||||
// If the type is fieldless and the trait uses the discriminant and
|
||||
// there are multiple variants, we need just an operation on
|
||||
// the tag(s).
|
||||
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
||||
let mut tag_check = self.call_substructure_method(
|
||||
// the discriminant(s).
|
||||
let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
|
||||
let mut discr_check = self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumTag(tag_field, None),
|
||||
&EnumDiscr(discr_field, None),
|
||||
);
|
||||
tag_let_stmts.append(&mut tag_check.0);
|
||||
return BlockOrExpr(tag_let_stmts, tag_check.1);
|
||||
discr_let_stmts.append(&mut discr_check.0);
|
||||
return BlockOrExpr(discr_let_stmts, discr_check.1);
|
||||
}
|
||||
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
|
||||
return self.call_substructure_method(
|
||||
@ -1266,7 +1266,7 @@ impl<'a> MethodDef<'a> {
|
||||
}
|
||||
} else if variants.len() == 1 {
|
||||
// If there is a single variant, we don't need an operation on
|
||||
// the tag(s). Just use the most degenerate result.
|
||||
// the discriminant(s). Just use the most degenerate result.
|
||||
return self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
@ -1380,22 +1380,22 @@ impl<'a> MethodDef<'a> {
|
||||
cx.expr_match(span, match_arg, match_arms)
|
||||
};
|
||||
|
||||
// If the trait uses the tag and there are multiple variants, we need
|
||||
// to add a tag check operation before the match. Otherwise, the match
|
||||
// If the trait uses the discriminant and there are multiple variants, we need
|
||||
// to add a discriminant check operation before the match. Otherwise, the match
|
||||
// is enough.
|
||||
if unify_fieldless_variants && variants.len() > 1 {
|
||||
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
||||
let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
|
||||
|
||||
// Combine a tag check with the match.
|
||||
let mut tag_check_plus_match = self.call_substructure_method(
|
||||
// Combine a discriminant check with the match.
|
||||
let mut discr_check_plus_match = self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
type_ident,
|
||||
nonselflike_args,
|
||||
&EnumTag(tag_field, Some(get_match_expr(selflike_args))),
|
||||
&EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
|
||||
);
|
||||
tag_let_stmts.append(&mut tag_check_plus_match.0);
|
||||
BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
|
||||
discr_let_stmts.append(&mut discr_check_plus_match.0);
|
||||
BlockOrExpr(discr_let_stmts, discr_check_plus_match.1)
|
||||
} else {
|
||||
BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
|
||||
}
|
||||
@ -1701,16 +1701,16 @@ where
|
||||
rest.iter().rfold(base_expr, op)
|
||||
}
|
||||
}
|
||||
EnumTag(tag_field, match_expr) => {
|
||||
let tag_check_expr = f(cx, CsFold::Single(tag_field));
|
||||
EnumDiscr(discr_field, match_expr) => {
|
||||
let discr_check_expr = f(cx, CsFold::Single(discr_field));
|
||||
if let Some(match_expr) = match_expr {
|
||||
if use_foldl {
|
||||
f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
|
||||
f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone()))
|
||||
} else {
|
||||
f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
|
||||
f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr))
|
||||
}
|
||||
} else {
|
||||
tag_check_expr
|
||||
discr_check_expr
|
||||
}
|
||||
}
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
|
@ -66,9 +66,9 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'
|
||||
fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
|
||||
(stmts, None)
|
||||
}
|
||||
EnumTag(tag_field, match_expr) => {
|
||||
assert!(tag_field.other_selflike_exprs.is_empty());
|
||||
let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
|
||||
EnumDiscr(discr_field, match_expr) => {
|
||||
assert!(discr_field.other_selflike_exprs.is_empty());
|
||||
let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())];
|
||||
(stmts, match_expr.clone())
|
||||
}
|
||||
_ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
|
||||
use super::{DirectedGraph, StartNode, Successors};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use std::ops::ControlFlow;
|
||||
@ -6,14 +6,14 @@ use std::ops::ControlFlow;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn post_order_from<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
pub fn post_order_from<G: DirectedGraph + Successors>(
|
||||
graph: &G,
|
||||
start_node: G::Node,
|
||||
) -> Vec<G::Node> {
|
||||
post_order_from_to(graph, start_node, None)
|
||||
}
|
||||
|
||||
pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
pub fn post_order_from_to<G: DirectedGraph + Successors>(
|
||||
graph: &G,
|
||||
start_node: G::Node,
|
||||
end_node: Option<G::Node>,
|
||||
@ -27,7 +27,7 @@ pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
result
|
||||
}
|
||||
|
||||
fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
fn post_order_walk<G: DirectedGraph + Successors>(
|
||||
graph: &G,
|
||||
node: G::Node,
|
||||
result: &mut Vec<G::Node>,
|
||||
@ -60,7 +60,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
pub fn reverse_post_order<G: DirectedGraph + Successors>(
|
||||
graph: &G,
|
||||
start_node: G::Node,
|
||||
) -> Vec<G::Node> {
|
||||
@ -72,7 +72,7 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
|
||||
/// A "depth-first search" iterator for a directed graph.
|
||||
pub struct DepthFirstSearch<'graph, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
graph: &'graph G,
|
||||
stack: Vec<G::Node>,
|
||||
@ -81,7 +81,7 @@ where
|
||||
|
||||
impl<'graph, G> DepthFirstSearch<'graph, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
pub fn new(graph: &'graph G) -> Self {
|
||||
Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
|
||||
@ -127,7 +127,7 @@ where
|
||||
|
||||
impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut f = fmt.debug_set();
|
||||
@ -140,7 +140,7 @@ where
|
||||
|
||||
impl<G> Iterator for DepthFirstSearch<'_, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
type Item = G::Node;
|
||||
|
||||
@ -201,7 +201,7 @@ struct Event<N> {
|
||||
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
|
||||
pub struct TriColorDepthFirstSearch<'graph, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
graph: &'graph G,
|
||||
stack: Vec<Event<G::Node>>,
|
||||
@ -211,7 +211,7 @@ where
|
||||
|
||||
impl<'graph, G> TriColorDepthFirstSearch<'graph, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: ?Sized + DirectedGraph + Successors,
|
||||
{
|
||||
pub fn new(graph: &'graph G) -> Self {
|
||||
TriColorDepthFirstSearch {
|
||||
@ -278,7 +278,7 @@ where
|
||||
|
||||
impl<G> TriColorDepthFirstSearch<'_, G>
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
|
||||
G: ?Sized + DirectedGraph + Successors + StartNode,
|
||||
{
|
||||
/// Performs a depth-first search, starting from `G::start_node()`.
|
||||
///
|
||||
|
@ -12,70 +12,43 @@ mod tests;
|
||||
|
||||
pub trait DirectedGraph {
|
||||
type Node: Idx;
|
||||
}
|
||||
|
||||
pub trait WithNumNodes: DirectedGraph {
|
||||
fn num_nodes(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait WithNumEdges: DirectedGraph {
|
||||
pub trait NumEdges: DirectedGraph {
|
||||
fn num_edges(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait WithSuccessors: DirectedGraph
|
||||
where
|
||||
Self: for<'graph> GraphSuccessors<'graph, Item = <Self as DirectedGraph>::Node>,
|
||||
{
|
||||
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter;
|
||||
|
||||
fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self>
|
||||
where
|
||||
Self: WithNumNodes,
|
||||
{
|
||||
iterate::DepthFirstSearch::new(self).with_start_node(from)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
pub trait GraphSuccessors<'graph> {
|
||||
type Item;
|
||||
type Iter: Iterator<Item = Self::Item>;
|
||||
}
|
||||
|
||||
pub trait WithPredecessors: DirectedGraph
|
||||
where
|
||||
Self: for<'graph> GraphPredecessors<'graph, Item = <Self as DirectedGraph>::Node>,
|
||||
{
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter;
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
pub trait GraphPredecessors<'graph> {
|
||||
type Item;
|
||||
type Iter: Iterator<Item = Self::Item>;
|
||||
}
|
||||
|
||||
pub trait WithStartNode: DirectedGraph {
|
||||
pub trait StartNode: DirectedGraph {
|
||||
fn start_node(&self) -> Self::Node;
|
||||
}
|
||||
|
||||
pub trait ControlFlowGraph:
|
||||
DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
|
||||
{
|
||||
// convenient trait
|
||||
pub trait Successors: DirectedGraph {
|
||||
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>;
|
||||
}
|
||||
|
||||
impl<T> ControlFlowGraph for T where
|
||||
T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
|
||||
{
|
||||
pub trait Predecessors: DirectedGraph {
|
||||
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node>;
|
||||
}
|
||||
|
||||
/// Alias for [`DirectedGraph`] + [`StartNode`] + [`Predecessors`] + [`Successors`].
|
||||
pub trait ControlFlowGraph: DirectedGraph + StartNode + Predecessors + Successors {}
|
||||
impl<T> ControlFlowGraph for T where T: DirectedGraph + StartNode + Predecessors + Successors {}
|
||||
|
||||
/// Returns `true` if the graph has a cycle that is reachable from the start node.
|
||||
pub fn is_cyclic<G>(graph: &G) -> bool
|
||||
where
|
||||
G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
|
||||
G: ?Sized + DirectedGraph + StartNode + Successors,
|
||||
{
|
||||
iterate::TriColorDepthFirstSearch::new(graph)
|
||||
.run_from_start(&mut iterate::CycleDetector)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn depth_first_search<G>(graph: &G, from: G::Node) -> iterate::DepthFirstSearch<'_, G>
|
||||
where
|
||||
G: ?Sized + Successors,
|
||||
{
|
||||
iterate::DepthFirstSearch::new(graph).with_start_node(from)
|
||||
}
|
||||
|
@ -2,38 +2,26 @@ use super::*;
|
||||
|
||||
impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G {
|
||||
type Node = G::Node;
|
||||
}
|
||||
|
||||
impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G {
|
||||
fn num_nodes(&self) -> usize {
|
||||
(**self).num_nodes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph, G: WithStartNode> WithStartNode for &'graph G {
|
||||
impl<'graph, G: StartNode> StartNode for &'graph G {
|
||||
fn start_node(&self) -> Self::Node {
|
||||
(**self).start_node()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G {
|
||||
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
impl<'graph, G: Successors> Successors for &'graph G {
|
||||
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
(**self).successors(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G {
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as GraphPredecessors<'_>>::Iter {
|
||||
impl<'graph, G: Predecessors> Predecessors for &'graph G {
|
||||
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
(**self).predecessors(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G {
|
||||
type Item = G::Node;
|
||||
type Iter = <G as GraphPredecessors<'iter>>::Iter;
|
||||
}
|
||||
|
||||
impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G {
|
||||
type Item = G::Node;
|
||||
type Iter = <G as GraphSuccessors<'iter>>::Iter;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
use crate::fx::FxHashSet;
|
||||
use crate::graph::vec_graph::VecGraph;
|
||||
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
|
||||
use crate::graph::{DirectedGraph, NumEdges, Successors};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use std::ops::Range;
|
||||
|
||||
@ -39,7 +39,7 @@ pub struct SccData<S: Idx> {
|
||||
}
|
||||
|
||||
impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
|
||||
pub fn new(graph: &(impl DirectedGraph<Node = N> + WithNumNodes + WithSuccessors)) -> Self {
|
||||
pub fn new(graph: &(impl DirectedGraph<Node = N> + Successors)) -> Self {
|
||||
SccsConstruction::construct(graph)
|
||||
}
|
||||
|
||||
@ -89,30 +89,22 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Idx, S: Idx> DirectedGraph for Sccs<N, S> {
|
||||
impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
|
||||
type Node = S;
|
||||
}
|
||||
|
||||
impl<N: Idx, S: Idx + Ord> WithNumNodes for Sccs<N, S> {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.num_sccs()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> {
|
||||
impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
|
||||
fn num_edges(&self) -> usize {
|
||||
self.scc_data.all_successors.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
|
||||
type Item = S;
|
||||
|
||||
type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>;
|
||||
}
|
||||
|
||||
impl<N: Idx, S: Idx + Ord> WithSuccessors for Sccs<N, S> {
|
||||
fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
|
||||
fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> {
|
||||
self.successors(node).iter().cloned()
|
||||
}
|
||||
}
|
||||
@ -158,7 +150,7 @@ impl<S: Idx> SccData<S> {
|
||||
}
|
||||
}
|
||||
|
||||
struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> {
|
||||
struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> {
|
||||
graph: &'c G,
|
||||
|
||||
/// The state of each node; used during walk to record the stack
|
||||
@ -218,7 +210,7 @@ enum WalkReturn<S> {
|
||||
|
||||
impl<'c, G, S> SccsConstruction<'c, G, S>
|
||||
where
|
||||
G: DirectedGraph + WithNumNodes + WithSuccessors,
|
||||
G: DirectedGraph + Successors,
|
||||
S: Idx,
|
||||
{
|
||||
/// Identifies SCCs in the graph `G` and computes the resulting
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::fx::FxHashMap;
|
||||
use std::cmp::max;
|
||||
use std::iter;
|
||||
use std::slice;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -36,38 +34,26 @@ impl TestGraph {
|
||||
|
||||
impl DirectedGraph for TestGraph {
|
||||
type Node = usize;
|
||||
}
|
||||
|
||||
impl WithStartNode for TestGraph {
|
||||
fn start_node(&self) -> usize {
|
||||
self.start_node
|
||||
}
|
||||
}
|
||||
|
||||
impl WithNumNodes for TestGraph {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.num_nodes
|
||||
}
|
||||
}
|
||||
|
||||
impl WithPredecessors for TestGraph {
|
||||
fn predecessors(&self, node: usize) -> <Self as GraphPredecessors<'_>>::Iter {
|
||||
impl StartNode for TestGraph {
|
||||
fn start_node(&self) -> usize {
|
||||
self.start_node
|
||||
}
|
||||
}
|
||||
|
||||
impl Predecessors for TestGraph {
|
||||
fn predecessors(&self, node: usize) -> impl Iterator<Item = Self::Node> {
|
||||
self.predecessors[&node].iter().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl WithSuccessors for TestGraph {
|
||||
fn successors(&self, node: usize) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
impl Successors for TestGraph {
|
||||
fn successors(&self, node: usize) -> impl Iterator<Item = Self::Node> {
|
||||
self.successors[&node].iter().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> GraphPredecessors<'graph> for TestGraph {
|
||||
type Item = usize;
|
||||
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
|
||||
}
|
||||
|
||||
impl<'graph> GraphSuccessors<'graph> for TestGraph {
|
||||
type Item = usize;
|
||||
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
|
||||
use crate::graph::{DirectedGraph, NumEdges, Successors};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
|
||||
#[cfg(test)]
|
||||
@ -80,28 +80,20 @@ impl<N: Idx + Ord> VecGraph<N> {
|
||||
|
||||
impl<N: Idx> DirectedGraph for VecGraph<N> {
|
||||
type Node = N;
|
||||
}
|
||||
|
||||
impl<N: Idx> WithNumNodes for VecGraph<N> {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.node_starts.len() - 1
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Idx> WithNumEdges for VecGraph<N> {
|
||||
impl<N: Idx> NumEdges for VecGraph<N> {
|
||||
fn num_edges(&self) -> usize {
|
||||
self.edge_targets.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
|
||||
type Item = N;
|
||||
|
||||
type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>;
|
||||
}
|
||||
|
||||
impl<N: Idx + Ord> WithSuccessors for VecGraph<N> {
|
||||
fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
impl<N: Idx + Ord> Successors for VecGraph<N> {
|
||||
fn successors(&self, node: N) -> impl Iterator<Item = Self::Node> {
|
||||
self.successors(node).iter().cloned()
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::graph;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn create_graph() -> VecGraph<usize> {
|
||||
@ -37,6 +39,6 @@ fn successors() {
|
||||
#[test]
|
||||
fn dfs() {
|
||||
let graph = create_graph();
|
||||
let dfs: Vec<_> = graph.depth_first_search(0).collect();
|
||||
let dfs: Vec<_> = graph::depth_first_search(&graph, 0).collect();
|
||||
assert_eq!(dfs, vec![0, 1, 3, 4, 2]);
|
||||
}
|
||||
|
@ -1373,16 +1373,16 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
// Don't leak types into signatures unless they're nameable!
|
||||
// For example, if a function returns itself, we don't want that
|
||||
// recursive function definition to leak out into the fn sig.
|
||||
let mut should_recover = false;
|
||||
let mut recovered_ret_ty = None;
|
||||
|
||||
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with the correct return type",
|
||||
ret_ty,
|
||||
suggestable_ret_ty,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
should_recover = true;
|
||||
recovered_ret_ty = Some(suggestable_ret_ty);
|
||||
} else if let Some(sugg) =
|
||||
suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
|
||||
{
|
||||
@ -1404,18 +1404,13 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
}
|
||||
|
||||
let guar = diag.emit();
|
||||
|
||||
if should_recover {
|
||||
ty::Binder::dummy(fn_sig)
|
||||
} else {
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().copied(),
|
||||
Ty::new_error(tcx, guar),
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.unsafety,
|
||||
fn_sig.abi,
|
||||
))
|
||||
}
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().copied(),
|
||||
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.unsafety,
|
||||
fn_sig.abi,
|
||||
))
|
||||
}
|
||||
None => icx.lowerer().lower_fn_ty(
|
||||
hir_id,
|
||||
|
@ -236,7 +236,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
ty::FnDef(..) | ty::Coroutine(..) | ty::Closure(..) | ty::CoroutineClosure(..) => {
|
||||
bug!("Unexpected coroutine/closure type in variance computation");
|
||||
bug!("Unexpected unnameable type in variance computation: {ty}");
|
||||
}
|
||||
|
||||
ty::Ref(region, ty, mutbl) => {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::FnCtxt;
|
||||
use rustc_data_structures::{
|
||||
graph::WithSuccessors,
|
||||
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
|
||||
graph::{self, iterate::DepthFirstSearch, vec_graph::VecGraph},
|
||||
unord::{UnordBag, UnordMap, UnordSet},
|
||||
};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
@ -300,7 +299,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
debug!(
|
||||
"calculate_diverging_fallback: root_vid={:?} reaches {:?}",
|
||||
root_vid,
|
||||
coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>()
|
||||
graph::depth_first_search(&coercion_graph, root_vid).collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// drain the iterator to visit all nodes reachable from this node
|
||||
@ -342,8 +341,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
for &diverging_vid in &diverging_vids {
|
||||
let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
|
||||
let root_vid = self.root_var(diverging_vid);
|
||||
let can_reach_non_diverging = coercion_graph
|
||||
.depth_first_search(root_vid)
|
||||
let can_reach_non_diverging = graph::depth_first_search(&coercion_graph, root_vid)
|
||||
.any(|n| roots_reachable_from_non_diverging.visited(n));
|
||||
|
||||
let infer_var_infos: UnordBag<_> = self
|
||||
|
@ -715,32 +715,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
|
||||
let ret_ty = expected_ret.only_has_type(self)?;
|
||||
|
||||
// HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
|
||||
// Without it, the inference
|
||||
// variable will get instantiated with the opaque type. The inference variable often
|
||||
// has various helpful obligations registered for it that help closures figure out their
|
||||
// signature. If we infer the inference var to the opaque type, the closure won't be able
|
||||
// to find those obligations anymore, and it can't necessarily find them from the opaque
|
||||
// type itself. We could be more powerful with inference if we *combined* the obligations
|
||||
// so that we got both the obligations from the opaque type and the ones from the inference
|
||||
// variable. That will accept more code than we do right now, so we need to carefully consider
|
||||
// the implications.
|
||||
// Note: this check is pessimistic, as the inference type could be matched with something other
|
||||
// than the opaque type, but then we need a new `TypeRelation` just for this specific case and
|
||||
// can't re-use `sup` below.
|
||||
// See tests/ui/impl-trait/hidden-type-is-opaque.rs and
|
||||
// tests/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
|
||||
if formal_ret.has_infer_types() {
|
||||
for ty in ret_ty.walk() {
|
||||
if let ty::GenericArgKind::Type(ty) = ty.unpack()
|
||||
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
|
||||
&& self.can_define_opaque_ty(def_id)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let expect_args = self
|
||||
.fudge_inference_if_ok(|| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
|
@ -297,22 +297,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// 3. Check if the formal type is a supertype of the checked one
|
||||
// and register any such obligations for future type checks
|
||||
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
|
||||
DefineOpaqueTypes::No,
|
||||
DefineOpaqueTypes::Yes,
|
||||
formal_input_ty,
|
||||
coerced_ty,
|
||||
);
|
||||
let subtyping_error = match supertype_error {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
None
|
||||
}
|
||||
Err(err) => Some(err),
|
||||
};
|
||||
|
||||
// If neither check failed, the types are compatible
|
||||
match subtyping_error {
|
||||
None => Compatibility::Compatible,
|
||||
Some(_) => Compatibility::Incompatible(subtyping_error),
|
||||
match supertype_error {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
Compatibility::Compatible
|
||||
}
|
||||
Err(err) => Compatibility::Incompatible(Some(err)),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1524,13 +1524,21 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
OperandBundleDef **OpBundles,
|
||||
OperandBundleDef **OpBundlesIndirect,
|
||||
unsigned NumOpBundles) {
|
||||
Value *Callee = unwrap(Fn);
|
||||
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||
|
||||
// FIXME: Is there a way around this?
|
||||
SmallVector<OperandBundleDef> OpBundles;
|
||||
OpBundles.reserve(NumOpBundles);
|
||||
for (unsigned i = 0; i < NumOpBundles; ++i) {
|
||||
OpBundles.push_back(*OpBundlesIndirect[i]);
|
||||
}
|
||||
|
||||
return wrap(unwrap(B)->CreateCall(
|
||||
FTy, Callee, ArrayRef<Value*>(unwrap(Args), NumArgs),
|
||||
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles)));
|
||||
ArrayRef<OperandBundleDef>(OpBundles)));
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
|
||||
@ -1570,13 +1578,21 @@ extern "C" LLVMValueRef
|
||||
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
|
||||
OperandBundleDef **OpBundles, unsigned NumOpBundles,
|
||||
OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
|
||||
const char *Name) {
|
||||
Value *Callee = unwrap(Fn);
|
||||
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||
|
||||
// FIXME: Is there a way around this?
|
||||
SmallVector<OperandBundleDef> OpBundles;
|
||||
OpBundles.reserve(NumOpBundles);
|
||||
for (unsigned i = 0; i < NumOpBundles; ++i) {
|
||||
OpBundles.push_back(*OpBundlesIndirect[i]);
|
||||
}
|
||||
|
||||
return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
|
||||
ArrayRef<Value*>(unwrap(Args), NumArgs),
|
||||
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
|
||||
ArrayRef<OperandBundleDef>(OpBundles),
|
||||
Name));
|
||||
}
|
||||
|
||||
@ -1585,7 +1601,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||
LLVMBasicBlockRef DefaultDest,
|
||||
LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
|
||||
LLVMValueRef *Args, unsigned NumArgs,
|
||||
OperandBundleDef **OpBundles, unsigned NumOpBundles,
|
||||
OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
|
||||
const char *Name) {
|
||||
Value *Callee = unwrap(Fn);
|
||||
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||
@ -1597,11 +1613,18 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||
IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i]));
|
||||
}
|
||||
|
||||
// FIXME: Is there a way around this?
|
||||
SmallVector<OperandBundleDef> OpBundles;
|
||||
OpBundles.reserve(NumOpBundles);
|
||||
for (unsigned i = 0; i < NumOpBundles; ++i) {
|
||||
OpBundles.push_back(*OpBundlesIndirect[i]);
|
||||
}
|
||||
|
||||
return wrap(unwrap(B)->CreateCallBr(
|
||||
FTy, Callee, unwrap(DefaultDest),
|
||||
ArrayRef<BasicBlock*>(IndirectDestsUnwrapped),
|
||||
ArrayRef<Value*>(unwrap(Args), NumArgs),
|
||||
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
|
||||
ArrayRef<OperandBundleDef>(OpBundles),
|
||||
Name));
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::mir::traversal::Postorder;
|
||||
use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorKind, START_BLOCK};
|
||||
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind, START_BLOCK};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::graph;
|
||||
@ -141,42 +141,30 @@ impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
|
||||
|
||||
impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
|
||||
type Node = BasicBlock;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.basic_blocks.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
|
||||
impl<'tcx> graph::StartNode for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn start_node(&self) -> Self::Node {
|
||||
START_BLOCK
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
|
||||
impl<'tcx> graph::Successors for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
|
||||
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
self.basic_blocks[node].terminator().successors()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = Successors<'b>;
|
||||
}
|
||||
|
||||
impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
|
||||
type Item = BasicBlock;
|
||||
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
|
||||
impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> {
|
||||
#[inline]
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
|
||||
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
self.predecessors()[node].iter().copied()
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use std::io::{self, Write};
|
||||
|
||||
pub struct GraphvizWriter<
|
||||
'a,
|
||||
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
|
||||
G: graph::DirectedGraph + graph::Successors + graph::StartNode,
|
||||
NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
|
||||
EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
|
||||
> {
|
||||
@ -19,7 +19,7 @@ pub struct GraphvizWriter<
|
||||
|
||||
impl<
|
||||
'a,
|
||||
G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
|
||||
G: graph::DirectedGraph + graph::Successors + graph::StartNode,
|
||||
NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
|
||||
EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
|
||||
> GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Debug};
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::graph::WithNumNodes;
|
||||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::dominators::{self, Dominators};
|
||||
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
|
||||
use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
|
||||
@ -193,16 +193,14 @@ impl IndexMut<BasicCoverageBlock> for CoverageGraph {
|
||||
|
||||
impl graph::DirectedGraph for CoverageGraph {
|
||||
type Node = BasicCoverageBlock;
|
||||
}
|
||||
|
||||
impl graph::WithNumNodes for CoverageGraph {
|
||||
#[inline]
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.bcbs.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl graph::WithStartNode for CoverageGraph {
|
||||
impl graph::StartNode for CoverageGraph {
|
||||
#[inline]
|
||||
fn start_node(&self) -> Self::Node {
|
||||
self.bcb_from_bb(mir::START_BLOCK)
|
||||
@ -210,28 +208,16 @@ impl graph::WithStartNode for CoverageGraph {
|
||||
}
|
||||
}
|
||||
|
||||
type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>;
|
||||
|
||||
impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph {
|
||||
type Item = BasicCoverageBlock;
|
||||
type Iter = std::iter::Cloned<BcbSuccessors<'graph>>;
|
||||
}
|
||||
|
||||
impl graph::WithSuccessors for CoverageGraph {
|
||||
impl graph::Successors for CoverageGraph {
|
||||
#[inline]
|
||||
fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
self.successors[node].iter().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph {
|
||||
type Item = BasicCoverageBlock;
|
||||
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>;
|
||||
}
|
||||
|
||||
impl graph::WithPredecessors for CoverageGraph {
|
||||
impl graph::Predecessors for CoverageGraph {
|
||||
#[inline]
|
||||
fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
|
||||
fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
self.predecessors[node].iter().copied()
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_data_structures::graph::WithNumNodes;
|
||||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
@ -28,8 +28,7 @@ use super::counters;
|
||||
use super::graph::{self, BasicCoverageBlock};
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_data_structures::graph::WithNumNodes;
|
||||
use rustc_data_structures::graph::WithSuccessors;
|
||||
use rustc_data_structures::graph::{DirectedGraph, Successors};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty;
|
||||
|
@ -205,6 +205,8 @@
|
||||
//! this is not implemented however: a mono item will be produced
|
||||
//! regardless of whether it is actually needed or not.
|
||||
|
||||
mod move_check;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock};
|
||||
use rustc_hir as hir;
|
||||
@ -227,7 +229,6 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgs};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::source_map::{dummy_spanned, respan, Spanned};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
@ -236,9 +237,9 @@ use rustc_target::abi::Size;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::errors::{
|
||||
self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit,
|
||||
TypeLengthLimit,
|
||||
self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit,
|
||||
};
|
||||
use move_check::MoveCheckState;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum MonoItemCollectionStrategy {
|
||||
@ -667,11 +668,8 @@ struct MirUsedCollector<'a, 'tcx> {
|
||||
/// Note that this contains *not-monomorphized* items!
|
||||
used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>,
|
||||
instance: Instance<'tcx>,
|
||||
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
|
||||
move_size_spans: Vec<Span>,
|
||||
visiting_call_terminator: bool,
|
||||
/// Set of functions for which it is OK to move large data into.
|
||||
skip_move_check_fns: Option<Vec<DefId>>,
|
||||
move_check: move_check::MoveCheckState,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
||||
@ -687,124 +685,6 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
if limit.0 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is called by visit_operand() which visits _all_
|
||||
// operands, including TerminatorKind::Call operands. But if
|
||||
// check_fn_args_move_size() has been called, the operands have already
|
||||
// been visited. Do not visit them again.
|
||||
if self.visiting_call_terminator {
|
||||
return;
|
||||
}
|
||||
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, source_info.span);
|
||||
};
|
||||
}
|
||||
|
||||
fn check_fn_args_move_size(
|
||||
&mut self,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: &[Spanned<mir::Operand<'tcx>>],
|
||||
fn_span: Span,
|
||||
location: Location,
|
||||
) {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
if limit.0 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow large moves into container types that themselves are cheap to move
|
||||
let ty::FnDef(def_id, _) = *callee_ty.kind() else {
|
||||
return;
|
||||
};
|
||||
if self
|
||||
.skip_move_check_fns
|
||||
.get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
|
||||
.contains(&def_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(?def_id, ?fn_span);
|
||||
|
||||
for arg in args {
|
||||
// Moving args into functions is typically implemented with pointer
|
||||
// passing at the llvm-ir level and not by memcpy's. So always allow
|
||||
// moving args into functions.
|
||||
let operand: &mir::Operand<'tcx> = &arg.node;
|
||||
if let mir::Operand::Move(_) = operand {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn operand_size_if_too_large(
|
||||
&mut self,
|
||||
limit: Limit,
|
||||
operand: &mir::Operand<'tcx>,
|
||||
) -> Option<Size> {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
let ty = self.monomorphize(ty);
|
||||
let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
|
||||
return None;
|
||||
};
|
||||
if layout.size.bytes_usize() > limit.0 {
|
||||
debug!(?layout);
|
||||
Some(layout.size)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_large_assignment(
|
||||
&mut self,
|
||||
limit: usize,
|
||||
too_large_size: Size,
|
||||
location: Location,
|
||||
span: Span,
|
||||
) {
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
for reported_span in &self.move_size_spans {
|
||||
if reported_span.overlaps(span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
|
||||
debug!(?lint_root);
|
||||
let Some(lint_root) = lint_root else {
|
||||
// This happens when the issue is in a function from a foreign crate that
|
||||
// we monomorphized in the current crate. We can't get a `HirId` for things
|
||||
// in other crates.
|
||||
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
|
||||
// but correct span? This would make the lint at least accept crate-level lint attributes.
|
||||
return;
|
||||
};
|
||||
self.tcx.emit_node_span_lint(
|
||||
LARGE_ASSIGNMENTS,
|
||||
lint_root,
|
||||
span,
|
||||
LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 },
|
||||
);
|
||||
self.move_size_spans.push(span);
|
||||
}
|
||||
|
||||
/// Evaluates a *not yet monomorphized* constant.
|
||||
fn eval_constant(
|
||||
&mut self,
|
||||
@ -1367,19 +1247,6 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
|
||||
return None;
|
||||
}
|
||||
|
||||
fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
|
||||
let fns = [
|
||||
(tcx.lang_items().owned_box(), "new"),
|
||||
(tcx.get_diagnostic_item(sym::Rc), "new"),
|
||||
(tcx.get_diagnostic_item(sym::Arc), "new"),
|
||||
];
|
||||
fns.into_iter()
|
||||
.filter_map(|(def_id, fn_name)| {
|
||||
def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Scans the MIR in order to find function calls, closures, and drop-glue.
|
||||
///
|
||||
/// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
|
||||
@ -1409,9 +1276,8 @@ fn collect_items_of_instance<'tcx>(
|
||||
used_items,
|
||||
used_mentioned_items: &mut used_mentioned_items,
|
||||
instance,
|
||||
move_size_spans: vec![],
|
||||
visiting_call_terminator: false,
|
||||
skip_move_check_fns: None,
|
||||
move_check: MoveCheckState::new(),
|
||||
};
|
||||
|
||||
if mode == CollectionMode::UsedItems {
|
||||
|
155
compiler/rustc_monomorphize/src/collector/move_check.rs
Normal file
155
compiler/rustc_monomorphize/src/collector/move_check.rs
Normal file
@ -0,0 +1,155 @@
|
||||
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
|
||||
|
||||
use super::*;
|
||||
use crate::errors::LargeAssignmentsLint;
|
||||
|
||||
pub(super) struct MoveCheckState {
|
||||
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
|
||||
move_size_spans: Vec<Span>,
|
||||
/// Set of functions for which it is OK to move large data into.
|
||||
skip_move_check_fns: Option<Vec<DefId>>,
|
||||
}
|
||||
|
||||
impl MoveCheckState {
|
||||
pub(super) fn new() -> Self {
|
||||
MoveCheckState { move_size_spans: vec![], skip_move_check_fns: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
|
||||
pub(super) fn check_operand_move_size(
|
||||
&mut self,
|
||||
operand: &mir::Operand<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
if limit.0 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is called by visit_operand() which visits _all_
|
||||
// operands, including TerminatorKind::Call operands. But if
|
||||
// check_fn_args_move_size() has been called, the operands have already
|
||||
// been visited. Do not visit them again.
|
||||
if self.visiting_call_terminator {
|
||||
return;
|
||||
}
|
||||
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, source_info.span);
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn check_fn_args_move_size(
|
||||
&mut self,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: &[Spanned<mir::Operand<'tcx>>],
|
||||
fn_span: Span,
|
||||
location: Location,
|
||||
) {
|
||||
let limit = self.tcx.move_size_limit();
|
||||
if limit.0 == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow large moves into container types that themselves are cheap to move
|
||||
let ty::FnDef(def_id, _) = *callee_ty.kind() else {
|
||||
return;
|
||||
};
|
||||
if self
|
||||
.move_check
|
||||
.skip_move_check_fns
|
||||
.get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
|
||||
.contains(&def_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(?def_id, ?fn_span);
|
||||
|
||||
for arg in args {
|
||||
// Moving args into functions is typically implemented with pointer
|
||||
// passing at the llvm-ir level and not by memcpy's. So always allow
|
||||
// moving args into functions.
|
||||
let operand: &mir::Operand<'tcx> = &arg.node;
|
||||
if let mir::Operand::Move(_) = operand {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
|
||||
self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn operand_size_if_too_large(
|
||||
&mut self,
|
||||
limit: Limit,
|
||||
operand: &mir::Operand<'tcx>,
|
||||
) -> Option<Size> {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
let ty = self.monomorphize(ty);
|
||||
let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else {
|
||||
return None;
|
||||
};
|
||||
if layout.size.bytes_usize() > limit.0 {
|
||||
debug!(?layout);
|
||||
Some(layout.size)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_large_assignment(
|
||||
&mut self,
|
||||
limit: usize,
|
||||
too_large_size: Size,
|
||||
location: Location,
|
||||
span: Span,
|
||||
) {
|
||||
let source_info = self.body.source_info(location);
|
||||
debug!(?source_info);
|
||||
for reported_span in &self.move_check.move_size_spans {
|
||||
if reported_span.overlaps(span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
|
||||
debug!(?lint_root);
|
||||
let Some(lint_root) = lint_root else {
|
||||
// This happens when the issue is in a function from a foreign crate that
|
||||
// we monomorphized in the current crate. We can't get a `HirId` for things
|
||||
// in other crates.
|
||||
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
|
||||
// but correct span? This would make the lint at least accept crate-level lint attributes.
|
||||
return;
|
||||
};
|
||||
self.tcx.emit_node_span_lint(
|
||||
LARGE_ASSIGNMENTS,
|
||||
lint_root,
|
||||
span,
|
||||
LargeAssignmentsLint { span, size: too_large_size.bytes(), limit: limit as u64 },
|
||||
);
|
||||
self.move_check.move_size_spans.push(span);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
|
||||
let fns = [
|
||||
(tcx.lang_items().owned_box(), "new"),
|
||||
(tcx.get_diagnostic_item(sym::Rc), "new"),
|
||||
(tcx.get_diagnostic_item(sym::Arc), "new"),
|
||||
];
|
||||
fns.into_iter()
|
||||
.filter_map(|(def_id, fn_name)| {
|
||||
def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
@ -11,6 +11,8 @@ resolve_added_macro_use =
|
||||
resolve_ancestor_only =
|
||||
visibilities can only be restricted to ancestor modules
|
||||
|
||||
resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here
|
||||
|
||||
resolve_associated_const_with_similar_name_exists =
|
||||
there is an associated constant with a similar name
|
||||
|
||||
@ -20,6 +22,10 @@ resolve_associated_fn_with_similar_name_exists =
|
||||
resolve_associated_type_with_similar_name_exists =
|
||||
there is an associated type with a similar name
|
||||
|
||||
resolve_attempt_to_define_builtin_macro_twice =
|
||||
attempted to define built-in macro more than once
|
||||
.note = previously defined here
|
||||
|
||||
resolve_attempt_to_use_non_constant_value_in_constant =
|
||||
attempt to use a non-constant value in a constant
|
||||
|
||||
@ -32,6 +38,11 @@ resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
|
||||
resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
|
||||
this would need to be a `{$suggestion}`
|
||||
|
||||
resolve_attributes_starting_with_rustc_are_reserved =
|
||||
attributes starting with `rustc` are reserved for use by the `rustc` compiler
|
||||
|
||||
resolve_bad_macro_import = bad macro import
|
||||
|
||||
resolve_binding_in_never_pattern =
|
||||
never patterns cannot contain variable bindings
|
||||
.suggestion = use a wildcard `_` instead
|
||||
@ -62,12 +73,19 @@ resolve_cannot_determine_macro_resolution =
|
||||
cannot determine resolution for the {$kind} `{$path}`
|
||||
.note = import resolution is stuck, try simplifying macro imports
|
||||
|
||||
resolve_cannot_find_builtin_macro_with_name =
|
||||
cannot find a built-in macro with name `{$ident}`
|
||||
|
||||
resolve_cannot_find_ident_in_this_scope =
|
||||
cannot find {$expected} `{$ident}` in this scope
|
||||
|
||||
resolve_cannot_glob_import_possible_crates =
|
||||
cannot glob-import all possible crates
|
||||
|
||||
resolve_cannot_use_through_an_import =
|
||||
cannot use {$article} {$descr} through an import
|
||||
.note = the {$descr} imported here
|
||||
|
||||
resolve_change_import_binding =
|
||||
you can use `as` to change the binding name of the import
|
||||
|
||||
@ -80,6 +98,12 @@ resolve_consider_adding_macro_export =
|
||||
resolve_consider_declaring_with_pub =
|
||||
consider declaring type or module `{$ident}` with `pub`
|
||||
|
||||
resolve_consider_making_the_field_public =
|
||||
{ $number_of_fields ->
|
||||
[one] consider making the field publicly accessible
|
||||
*[other] consider making the fields publicly accessible
|
||||
}
|
||||
|
||||
resolve_consider_marking_as_pub =
|
||||
consider marking `{$ident}` as `pub` in the imported module
|
||||
|
||||
@ -100,17 +124,44 @@ resolve_const_param_in_non_trivial_anon_const =
|
||||
resolve_const_param_in_ty_of_const_param =
|
||||
const parameters may not be used in the type of const parameters
|
||||
|
||||
resolve_expected_found =
|
||||
resolve_constructor_private_if_any_field_private =
|
||||
a constructor is private if any of the fields is private
|
||||
|
||||
resolve_elided_anonymous_lifetime_report_error =
|
||||
`&` without an explicit lifetime name cannot be used here
|
||||
.label = explicit lifetime name needed here
|
||||
|
||||
resolve_elided_anonymous_lifetime_report_error_suggestion =
|
||||
consider introducing a higher-ranked lifetime here
|
||||
|
||||
resolve_expected_module_found =
|
||||
expected module, found {$res} `{$path_str}`
|
||||
.label = not a module
|
||||
|
||||
resolve_explicit_anonymous_lifetime_report_error =
|
||||
`'_` cannot be used here
|
||||
.label = `'_` is a reserved lifetime name
|
||||
|
||||
resolve_explicit_unsafe_traits =
|
||||
unsafe traits like `{$ident}` should be implemented explicitly
|
||||
|
||||
resolve_extern_crate_loading_macro_not_at_crate_root =
|
||||
an `extern crate` loading macros must be at the crate root
|
||||
|
||||
resolve_extern_crate_self_requires_renaming =
|
||||
`extern crate self;` requires renaming
|
||||
.suggestion = rename the `self` crate to be able to import it
|
||||
|
||||
resolve_forward_declared_generic_param =
|
||||
generic parameters with a default cannot use forward declared identifiers
|
||||
.label = defaulted generic parameters cannot be forward declared
|
||||
|
||||
resolve_found_an_item_configured_out =
|
||||
found an item that was configured out
|
||||
|
||||
resolve_generic_arguments_in_macro_path =
|
||||
generic arguments in macro path
|
||||
|
||||
resolve_generic_params_from_outer_item =
|
||||
can't use {$is_self ->
|
||||
[true] `Self`
|
||||
@ -135,7 +186,6 @@ resolve_generic_params_from_outer_item_static = a `static` is a separate item fr
|
||||
|
||||
resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
|
||||
|
||||
|
||||
resolve_ident_bound_more_than_once_in_parameter_list =
|
||||
identifier `{$identifier}` is bound more than once in this parameter list
|
||||
.label = used as parameter more than once
|
||||
@ -144,8 +194,18 @@ resolve_ident_bound_more_than_once_in_same_pattern =
|
||||
identifier `{$identifier}` is bound more than once in the same pattern
|
||||
.label = used in a pattern more than once
|
||||
|
||||
resolve_ident_imported_here_but_it_is_desc =
|
||||
`{$imported_ident}` is imported here, but it is {$imported_ident_desc}
|
||||
|
||||
resolve_ident_in_scope_but_it_is_desc =
|
||||
`{$imported_ident}` is in scope, but it is {$imported_ident_desc}
|
||||
|
||||
resolve_implicit_elided_lifetimes_not_allowed_here = implicit elided lifetime not allowed here
|
||||
|
||||
resolve_imported_crate = `$crate` may not be imported
|
||||
|
||||
resolve_imported_macro_not_found = imported macro not found
|
||||
|
||||
resolve_imports_cannot_refer_to =
|
||||
imports cannot refer to {$what}
|
||||
|
||||
@ -161,6 +221,13 @@ resolve_is_not_directly_importable =
|
||||
`{$target}` is not directly importable
|
||||
.label = cannot be imported directly
|
||||
|
||||
resolve_is_private =
|
||||
{$ident_descr} `{$ident}` is private
|
||||
.label = private {$ident_descr}
|
||||
|
||||
resolve_item_was_behind_feature =
|
||||
the item is gated behind the `{$feature}` feature
|
||||
|
||||
resolve_items_in_traits_are_not_importable =
|
||||
items in traits are not importable
|
||||
|
||||
@ -183,11 +250,23 @@ resolve_lowercase_self =
|
||||
resolve_macro_defined_later =
|
||||
a macro with the same name exists, but it appears later at here
|
||||
|
||||
resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments =
|
||||
macro-expanded `extern crate` items cannot shadow names passed with `--extern`
|
||||
|
||||
resolve_macro_expected_found =
|
||||
expected {$expected}, found {$found} `{$macro_path}`
|
||||
.label = not {$article} {$expected}
|
||||
|
||||
resolve_macro_extern_deprecated =
|
||||
`#[macro_escape]` is a deprecated synonym for `#[macro_use]`
|
||||
.help = try an outer attribute: `#[macro_use]`
|
||||
|
||||
resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
|
||||
|
||||
resolve_macro_use_name_already_in_use =
|
||||
`{$name}` is already in scope
|
||||
.note = macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
|
||||
|
||||
resolve_method_not_member_of_trait =
|
||||
method `{$method}` is not a member of trait `{$trait_}`
|
||||
.label = not a member of trait `{$trait_}`
|
||||
@ -197,11 +276,45 @@ resolve_missing_macro_rules_name = maybe you have forgotten to define a name for
|
||||
resolve_module_only =
|
||||
visibility must resolve to a module
|
||||
|
||||
resolve_name_defined_multiple_time =
|
||||
the name `{$name}` is defined multiple times
|
||||
.note = `{$name}` must be defined only once in the {$descr} namespace of this {$container}
|
||||
|
||||
resolve_name_defined_multiple_time_old_binding_definition =
|
||||
previous definition of the {$old_kind} `{$name}` here
|
||||
|
||||
resolve_name_defined_multiple_time_old_binding_import =
|
||||
previous import of the {$old_kind} `{$name}` here
|
||||
|
||||
resolve_name_defined_multiple_time_redefined =
|
||||
`{$name}` redefined here
|
||||
|
||||
resolve_name_defined_multiple_time_reimported =
|
||||
`{$name}` reimported here
|
||||
|
||||
resolve_name_is_already_used_as_generic_parameter =
|
||||
the name `{$name}` is already used for a generic parameter in this item's generic parameters
|
||||
.label = already used
|
||||
.first_use_of_name = first use of `{$name}`
|
||||
|
||||
resolve_name_reserved_in_attribute_namespace =
|
||||
name `{$ident}` is reserved in attribute namespace
|
||||
|
||||
resolve_note_and_refers_to_the_item_defined_here =
|
||||
{$first ->
|
||||
[true] {$dots ->
|
||||
[true] the {$binding_descr} `{$binding_name}` is defined here...
|
||||
*[false] the {$binding_descr} `{$binding_name}` is defined here
|
||||
}
|
||||
*[false] {$dots ->
|
||||
[true] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here...
|
||||
*[false] ...and refers to the {$binding_descr} `{$binding_name}` which is defined here
|
||||
}
|
||||
}
|
||||
|
||||
resolve_outer_ident_is_not_publicly_reexported =
|
||||
{$outer_ident_descr} `{$outer_ident}` is not publicly re-exported
|
||||
|
||||
resolve_param_in_enum_discriminant =
|
||||
generic parameters may not be used in enum discriminant values
|
||||
.label = cannot perform const operation using `{$name}`
|
||||
@ -217,6 +330,8 @@ resolve_param_in_ty_of_const_param =
|
||||
the type of const parameters must not depend on other generic parameters
|
||||
.label = the type must not depend on the parameter `{$name}`
|
||||
|
||||
resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}`
|
||||
|
||||
resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
|
||||
.help = you can define integration tests in a directory named `tests`
|
||||
|
||||
@ -233,6 +348,8 @@ resolve_relative_2018 =
|
||||
resolve_remove_surrounding_derive =
|
||||
remove from the surrounding `derive()`
|
||||
|
||||
resolve_remove_unnecessary_import = remove unnecessary import
|
||||
|
||||
resolve_self_import_can_only_appear_once_in_the_list =
|
||||
`self` import can only appear once in an import list
|
||||
.label = can only appear once in an import list
|
||||
@ -254,16 +371,43 @@ resolve_self_in_generic_param_default =
|
||||
generic parameters cannot use `Self` in their defaults
|
||||
.label = `Self` in generic parameter default
|
||||
|
||||
resolve_similarly_named_defined_here =
|
||||
similarly named {$candidate_descr} `{$candidate}` defined here
|
||||
|
||||
resolve_single_item_defined_here =
|
||||
{$candidate_descr} `{$candidate}` defined here
|
||||
|
||||
resolve_static_lifetime_is_reserved = invalid lifetime parameter name: `{$lifetime}`
|
||||
.label = 'static is a reserved lifetime name
|
||||
|
||||
resolve_suggestion_import_ident_directly =
|
||||
import `{$ident}` directly
|
||||
|
||||
resolve_suggestion_import_ident_through_reexport =
|
||||
import `{$ident}` through the re-export
|
||||
|
||||
resolve_tool_module_imported =
|
||||
cannot use a tool module through an import
|
||||
.note = the tool module imported here
|
||||
|
||||
resolve_tool_only_accepts_identifiers =
|
||||
`{$tool}` only accepts identifiers
|
||||
.label = not an identifier
|
||||
|
||||
resolve_tool_was_already_registered =
|
||||
tool `{$tool}` was already registered
|
||||
.label = already registered here
|
||||
|
||||
resolve_trait_impl_duplicate =
|
||||
duplicate definitions with name `{$name}`:
|
||||
.label = duplicate definition
|
||||
.old_span_label = previous definition here
|
||||
.trait_item_span = item in trait
|
||||
|
||||
resolve_trait_impl_mismatch =
|
||||
item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
|
||||
.label = does not match trait
|
||||
.trait_impl_mismatch_label_item = item in trait
|
||||
resolve_try_using_similarly_named_label =
|
||||
try using similarly named label
|
||||
|
||||
@ -284,12 +428,18 @@ resolve_undeclared_label =
|
||||
use of undeclared label `{$name}`
|
||||
.label = undeclared label `{$name}`
|
||||
|
||||
resolve_underscore_lifetime_is_reserved = `'_` cannot be used here
|
||||
.label = `'_` is a reserved lifetime name
|
||||
|
||||
resolve_unexpected_res_change_ty_to_const_param_sugg =
|
||||
you might have meant to write a const parameter here
|
||||
|
||||
resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg =
|
||||
if you meant to collect the rest of the slice in `{$ident}`, use the at operator
|
||||
|
||||
resolve_unnamed_crate_root_import =
|
||||
crate root imports need to be explicitly named: `use crate as name;`
|
||||
|
||||
resolve_unreachable_label =
|
||||
use of unreachable label `{$name}`
|
||||
.label = unreachable label `{$name}`
|
||||
@ -312,3 +462,8 @@ resolve_variable_bound_with_different_mode =
|
||||
variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
|
||||
.label = bound in different ways
|
||||
.first_binding_span = first binding
|
||||
|
||||
resolve_variable_is_not_bound_in_all_patterns =
|
||||
variable `{$name}` is not bound in all patterns
|
||||
|
||||
resolve_variable_not_in_all_patterns = variable not in all patterns
|
||||
|
@ -19,7 +19,6 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
|
||||
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability};
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_hir::def::{self, *};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
@ -529,11 +528,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
if ident.name == kw::Crate {
|
||||
self.r.dcx().span_err(
|
||||
ident.span,
|
||||
"crate root imports need to be explicitly named: \
|
||||
`use crate as name;`",
|
||||
);
|
||||
self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span });
|
||||
}
|
||||
|
||||
let kind = ImportKind::Single {
|
||||
@ -848,16 +843,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
let expansion = parent_scope.expansion;
|
||||
|
||||
let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
|
||||
self.r
|
||||
.dcx()
|
||||
.struct_span_err(item.span, "`extern crate self;` requires renaming")
|
||||
.with_span_suggestion(
|
||||
item.span,
|
||||
"rename the `self` crate to be able to import it",
|
||||
"extern crate self as name;",
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.emit();
|
||||
self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp });
|
||||
return;
|
||||
} else if orig_name == Some(kw::SelfLower) {
|
||||
Some(self.r.graph_root)
|
||||
@ -897,9 +883,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
if parent == self.r.graph_root {
|
||||
if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
|
||||
if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
|
||||
let msg = "macro-expanded `extern crate` items cannot \
|
||||
shadow names passed with `--extern`";
|
||||
self.r.dcx().span_err(item.span, msg);
|
||||
self.r.dcx().emit_err(
|
||||
errors::MacroExpandedExternCrateCannotShadowExternArguments {
|
||||
span: item.span,
|
||||
},
|
||||
);
|
||||
// `return` is intended to discard this binding because it's an
|
||||
// unregistered ambiguity error which would result in a panic
|
||||
// caused by inconsistency `path_res`
|
||||
@ -1030,10 +1018,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
allow_shadowing: bool,
|
||||
) {
|
||||
if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
|
||||
let msg = format!("`{name}` is already in scope");
|
||||
let note =
|
||||
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
|
||||
self.r.dcx().struct_span_err(span, msg).with_note(note).emit();
|
||||
self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1044,13 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
for attr in &item.attrs {
|
||||
if attr.has_name(sym::macro_use) {
|
||||
if self.parent_scope.module.parent.is_some() {
|
||||
struct_span_code_err!(
|
||||
self.r.dcx(),
|
||||
item.span,
|
||||
E0468,
|
||||
"an `extern crate` loading macros must be at the crate root"
|
||||
)
|
||||
.emit();
|
||||
self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot {
|
||||
span: item.span,
|
||||
});
|
||||
}
|
||||
if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
|
||||
if orig_name == kw::SelfLower {
|
||||
@ -1058,7 +1039,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
}
|
||||
}
|
||||
let ill_formed = |span| {
|
||||
struct_span_code_err!(self.r.dcx(), span, E0466, "bad macro import").emit();
|
||||
self.r.dcx().emit_err(errors::BadMacroImport { span });
|
||||
};
|
||||
match attr.meta() {
|
||||
Some(meta) => match meta.kind {
|
||||
@ -1143,13 +1124,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
allow_shadowing,
|
||||
);
|
||||
} else {
|
||||
struct_span_code_err!(
|
||||
self.r.dcx(),
|
||||
ident.span,
|
||||
E0469,
|
||||
"imported macro not found"
|
||||
)
|
||||
.emit();
|
||||
self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1160,18 +1135,16 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::macro_escape) {
|
||||
let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
|
||||
let mut err = self.r.dcx().struct_span_warn(attr.span, msg);
|
||||
if let ast::AttrStyle::Inner = attr.style {
|
||||
err.help("try an outer attribute: `#[macro_use]`");
|
||||
}
|
||||
err.emit();
|
||||
let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner).then_some(());
|
||||
self.r
|
||||
.dcx()
|
||||
.emit_warn(errors::MacroExternDeprecated { span: attr.span, inner_attribute });
|
||||
} else if !attr.has_name(sym::macro_use) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !attr.is_word() {
|
||||
self.r.dcx().span_err(attr.span, "arguments to `macro_use` are not allowed here");
|
||||
self.r.dcx().emit_err(errors::ArgumentsMacroUseNotAllowed { span: attr.span });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ use rustc_ast::{MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, Diag,
|
||||
DiagCtxt, ErrorGuaranteed, MultiSpan, SuggestionStyle,
|
||||
codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt,
|
||||
ErrorGuaranteed, MultiSpan, SuggestionStyle,
|
||||
};
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
@ -29,10 +29,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
|
||||
use crate::errors::{
|
||||
ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition,
|
||||
MaybeMissingMacroRulesName,
|
||||
self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
|
||||
ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition, MaybeMissingMacroRulesName,
|
||||
};
|
||||
use crate::imports::{Import, ImportKind};
|
||||
use crate::late::{PatternSource, Rib};
|
||||
@ -226,16 +225,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
ModuleKind::Block => "block",
|
||||
};
|
||||
|
||||
let old_noun = match old_binding.is_import_user_facing() {
|
||||
true => "import",
|
||||
false => "definition",
|
||||
};
|
||||
|
||||
let new_participle = match new_binding.is_import_user_facing() {
|
||||
true => "imported",
|
||||
false => "defined",
|
||||
};
|
||||
|
||||
let (name, span) =
|
||||
(ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
|
||||
|
||||
@ -254,35 +243,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
(TypeNS, _) => "type",
|
||||
};
|
||||
|
||||
let msg = format!("the name `{name}` is defined multiple times");
|
||||
|
||||
let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
|
||||
(true, true) => struct_span_code_err!(self.dcx(), span, E0259, "{}", msg),
|
||||
let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
|
||||
(true, true) => E0259,
|
||||
(true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
|
||||
true => struct_span_code_err!(self.dcx(), span, E0254, "{}", msg),
|
||||
false => struct_span_code_err!(self.dcx(), span, E0260, "{}", msg),
|
||||
true => E0254,
|
||||
false => E0260,
|
||||
},
|
||||
_ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
|
||||
(false, false) => struct_span_code_err!(self.dcx(), span, E0428, "{}", msg),
|
||||
(true, true) => struct_span_code_err!(self.dcx(), span, E0252, "{}", msg),
|
||||
_ => struct_span_code_err!(self.dcx(), span, E0255, "{}", msg),
|
||||
(false, false) => E0428,
|
||||
(true, true) => E0252,
|
||||
_ => E0255,
|
||||
},
|
||||
};
|
||||
|
||||
err.note(format!(
|
||||
"`{}` must be defined only once in the {} namespace of this {}",
|
||||
name,
|
||||
ns.descr(),
|
||||
container
|
||||
));
|
||||
let label = match new_binding.is_import_user_facing() {
|
||||
true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name },
|
||||
false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name },
|
||||
};
|
||||
|
||||
err.span_label(span, format!("`{name}` re{new_participle} here"));
|
||||
if !old_binding.span.is_dummy() && old_binding.span != span {
|
||||
err.span_label(
|
||||
self.tcx.sess.source_map().guess_head_span(old_binding.span),
|
||||
format!("previous {old_noun} of the {old_kind} `{name}` here"),
|
||||
);
|
||||
}
|
||||
let old_binding_label =
|
||||
(!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
|
||||
let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
|
||||
match old_binding.is_import_user_facing() {
|
||||
true => errors::NameDefinedMultipleTimeOldBindingLabel::Import {
|
||||
span,
|
||||
name,
|
||||
old_kind,
|
||||
},
|
||||
false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
|
||||
span,
|
||||
name,
|
||||
old_kind,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
let mut err = self
|
||||
.dcx()
|
||||
.create_err(errors::NameDefinedMultipleTime {
|
||||
span,
|
||||
descr: ns.descr(),
|
||||
container,
|
||||
label,
|
||||
old_binding_label,
|
||||
})
|
||||
.with_code(code);
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/32354
|
||||
use NameBindingKind::Import;
|
||||
@ -330,20 +335,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|
||||
match import {
|
||||
Some((import, span, true)) if should_remove_import && import.is_nested() => {
|
||||
self.add_suggestion_for_duplicate_nested_use(&mut err, import, span)
|
||||
self.add_suggestion_for_duplicate_nested_use(&mut err, import, span);
|
||||
}
|
||||
Some((import, _, true)) if should_remove_import && !import.is_glob() => {
|
||||
// Simple case - remove the entire import. Due to the above match arm, this can
|
||||
// only be a single use so just remove it entirely.
|
||||
err.tool_only_span_suggestion(
|
||||
import.use_span_with_attributes,
|
||||
"remove unnecessary import",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
err.subdiagnostic(
|
||||
self.tcx.dcx(),
|
||||
errors::ToolOnlyRemoveUnnecessaryImport {
|
||||
span: import.use_span_with_attributes,
|
||||
},
|
||||
);
|
||||
}
|
||||
Some((import, span, _)) => {
|
||||
self.add_suggestion_for_rename_of_use(&mut err, name, import, span)
|
||||
self.add_suggestion_for_rename_of_use(&mut err, name, import, span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -444,7 +449,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
binding_span: Span,
|
||||
) {
|
||||
assert!(import.is_nested());
|
||||
let message = "remove unnecessary import";
|
||||
|
||||
// Two examples will be used to illustrate the span manipulations we're doing:
|
||||
//
|
||||
@ -460,22 +464,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// previous imports.
|
||||
if found_closing_brace {
|
||||
if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
|
||||
err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect);
|
||||
err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span });
|
||||
} else {
|
||||
// Remove the entire line if we cannot extend the span back, this indicates an
|
||||
// `issue_52891::{self}` case.
|
||||
err.span_suggestion(
|
||||
import.use_span_with_attributes,
|
||||
message,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes },
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err.span_suggestion(span, message, "", Applicability::MachineApplicable);
|
||||
err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span });
|
||||
}
|
||||
|
||||
pub(crate) fn lint_if_path_starts_with_module(
|
||||
@ -571,14 +573,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
resolution_error: ResolutionError<'a>,
|
||||
) -> Diag<'_> {
|
||||
match resolution_error {
|
||||
ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => {
|
||||
ResolutionError::GenericParamsFromOuterItem(
|
||||
outer_res,
|
||||
has_generic_params,
|
||||
def_kind,
|
||||
) => {
|
||||
use errs::GenericParamsFromOuterItemLabel as Label;
|
||||
let static_or_const = match def_kind {
|
||||
DefKind::Static{ .. } => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
|
||||
DefKind::Static { .. } => {
|
||||
Some(errs::GenericParamsFromOuterItemStaticOrConst::Static)
|
||||
}
|
||||
DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
|
||||
_ => None,
|
||||
};
|
||||
let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
|
||||
let is_self =
|
||||
matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
|
||||
let mut err = errs::GenericParamsFromOuterItem {
|
||||
span,
|
||||
label: None,
|
||||
@ -677,18 +686,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let origin_sp = origin.iter().copied().collect::<Vec<_>>();
|
||||
|
||||
let msp = MultiSpan::from_spans(target_sp.clone());
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
msp,
|
||||
E0408,
|
||||
"variable `{}` is not bound in all patterns",
|
||||
name,
|
||||
);
|
||||
let mut err = self
|
||||
.dcx()
|
||||
.create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
|
||||
for sp in target_sp {
|
||||
err.span_label(sp, format!("pattern doesn't bind `{name}`"));
|
||||
err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name });
|
||||
}
|
||||
for sp in origin_sp {
|
||||
err.span_label(sp, "variable not in all patterns");
|
||||
err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp });
|
||||
}
|
||||
if could_be_path {
|
||||
let import_suggestions = self.lookup_import_candidates(
|
||||
@ -961,17 +966,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
code,
|
||||
trait_item_span,
|
||||
trait_path,
|
||||
} => {
|
||||
self.dcx().struct_span_err(
|
||||
} => self
|
||||
.dcx()
|
||||
.create_err(errors::TraitImplMismatch {
|
||||
span,
|
||||
format!(
|
||||
"item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
|
||||
),
|
||||
)
|
||||
.with_code(code)
|
||||
.with_span_label(span, "does not match trait")
|
||||
.with_span_label(trait_item_span, "item in trait")
|
||||
}
|
||||
name,
|
||||
kind,
|
||||
trait_path,
|
||||
trait_item_span,
|
||||
})
|
||||
.with_code(code),
|
||||
ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
|
||||
.dcx()
|
||||
.create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
|
||||
@ -1005,7 +1009,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
|
||||
),
|
||||
VisResolutionError::ExpectedFound(span, path_str, res) => {
|
||||
self.dcx().create_err(errs::ExpectedFound { span, res, path_str })
|
||||
self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
|
||||
}
|
||||
VisResolutionError::Indeterminate(span) => {
|
||||
self.dcx().create_err(errs::Indeterminate(span))
|
||||
@ -1532,17 +1536,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
};
|
||||
if let crate::NameBindingKind::Import { import, .. } = binding.kind {
|
||||
if !import.span.is_dummy() {
|
||||
err.span_note(
|
||||
import.span,
|
||||
format!("`{ident}` is imported here, but it is {desc}"),
|
||||
);
|
||||
let note = errors::IdentImporterHereButItIsDesc {
|
||||
span: import.span,
|
||||
imported_ident: ident,
|
||||
imported_ident_desc: &desc,
|
||||
};
|
||||
err.subdiagnostic(self.tcx.dcx(), note);
|
||||
// Silence the 'unused import' warning we might get,
|
||||
// since this diagnostic already covers that import.
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
return;
|
||||
}
|
||||
}
|
||||
err.note(format!("`{ident}` is in scope, but it is {desc}"));
|
||||
let note = errors::IdentInScopeButItIsDesc {
|
||||
imported_ident: ident,
|
||||
imported_ident_desc: &desc,
|
||||
};
|
||||
err.subdiagnostic(self.tcx.dcx(), note);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1582,20 +1592,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// | ^
|
||||
return false;
|
||||
}
|
||||
let prefix = match suggestion.target {
|
||||
SuggestionTarget::SimilarlyNamed => "similarly named ",
|
||||
SuggestionTarget::SingleItem => "",
|
||||
let span = self.tcx.sess.source_map().guess_head_span(def_span);
|
||||
let candidate_descr = suggestion.res.descr();
|
||||
let candidate = suggestion.candidate;
|
||||
let label = match suggestion.target {
|
||||
SuggestionTarget::SimilarlyNamed => {
|
||||
errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
|
||||
}
|
||||
SuggestionTarget::SingleItem => {
|
||||
errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
|
||||
}
|
||||
};
|
||||
|
||||
err.span_label(
|
||||
self.tcx.sess.source_map().guess_head_span(def_span),
|
||||
format!(
|
||||
"{}{} `{}` defined here",
|
||||
prefix,
|
||||
suggestion.res.descr(),
|
||||
suggestion.candidate,
|
||||
),
|
||||
);
|
||||
err.subdiagnostic(self.tcx.dcx(), label);
|
||||
}
|
||||
|
||||
let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
|
||||
@ -1749,16 +1757,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
|b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
|
||||
|
||||
// Print the primary message.
|
||||
let descr = get_descr(binding);
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
ident.span,
|
||||
E0603,
|
||||
"{} `{}` is private",
|
||||
descr,
|
||||
ident
|
||||
);
|
||||
err.span_label(ident.span, format!("private {descr}"));
|
||||
let ident_descr = get_descr(binding);
|
||||
let mut err =
|
||||
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
|
||||
|
||||
let mut not_publicly_reexported = false;
|
||||
if let Some((this_res, outer_ident)) = outermost_res {
|
||||
@ -1782,10 +1783,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// If we suggest importing a public re-export, don't point at the definition.
|
||||
if point_to_def && ident.span != outer_ident.span {
|
||||
not_publicly_reexported = true;
|
||||
err.span_label(
|
||||
outer_ident.span,
|
||||
format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()),
|
||||
);
|
||||
let label = errors::OuterIdentIsNotPubliclyReexported {
|
||||
span: outer_ident.span,
|
||||
outer_ident_descr: this_res.descr(),
|
||||
outer_ident,
|
||||
};
|
||||
err.subdiagnostic(self.tcx.dcx(), label);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1799,18 +1802,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
{
|
||||
non_exhaustive = Some(attr.span);
|
||||
} else if let Some(span) = ctor_fields_span {
|
||||
err.span_label(span, "a constructor is private if any of the fields is private");
|
||||
let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
|
||||
err.subdiagnostic(self.tcx.dcx(), label);
|
||||
if let Res::Def(_, d) = res
|
||||
&& let Some(fields) = self.field_visibility_spans.get(&d)
|
||||
{
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"consider making the field{} publicly accessible",
|
||||
pluralize!(fields.len())
|
||||
),
|
||||
fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
let spans = fields.iter().map(|span| *span).collect();
|
||||
let sugg =
|
||||
errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
|
||||
err.subdiagnostic(self.tcx.dcx(), sugg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1893,13 +1893,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
|
||||
}
|
||||
let first = binding == first_binding;
|
||||
let msg = format!(
|
||||
"{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
|
||||
and_refers_to = if first { "" } else { "...and refers to " },
|
||||
item = get_descr(binding),
|
||||
which = if first { "" } else { " which" },
|
||||
dots = if next_binding.is_some() { "..." } else { "" },
|
||||
);
|
||||
let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
|
||||
let mut note_span = MultiSpan::from_span(def_span);
|
||||
if !first && binding.vis.is_public() {
|
||||
@ -1919,7 +1912,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
"cannot be constructed because it is `#[non_exhaustive]`",
|
||||
);
|
||||
}
|
||||
err.span_note(note_span, msg);
|
||||
let note = errors::NoteAndRefersToTheItemDefinedHere {
|
||||
span: note_span,
|
||||
binding_descr: get_descr(binding),
|
||||
binding_name: name,
|
||||
first,
|
||||
dots: next_binding.is_some(),
|
||||
};
|
||||
err.subdiagnostic(self.tcx.dcx(), note);
|
||||
}
|
||||
// We prioritize shorter paths, non-core imports and direct imports over the alternatives.
|
||||
sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
|
||||
@ -1933,15 +1933,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
continue;
|
||||
}
|
||||
let path = sugg.join("::");
|
||||
err.span_suggestion_verbose(
|
||||
dedup_span,
|
||||
format!(
|
||||
"import `{ident}` {}",
|
||||
if reexport { "through the re-export" } else { "directly" }
|
||||
),
|
||||
path,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let sugg = if reexport {
|
||||
errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
|
||||
} else {
|
||||
errors::ImportIdent::Directly { span: dedup_span, ident, path }
|
||||
};
|
||||
err.subdiagnostic(self.tcx.dcx(), sugg);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2521,13 +2518,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
continue;
|
||||
}
|
||||
|
||||
err.span_note(name.span, "found an item that was configured out");
|
||||
let note = errors::FoundItemConfigureOut { span: name.span };
|
||||
err.subdiagnostic(self.tcx.dcx(), note);
|
||||
|
||||
if let MetaItemKind::List(nested) = &cfg.kind
|
||||
&& let NestedMetaItem::MetaItem(meta_item) = &nested[0]
|
||||
&& let MetaItemKind::NameValue(feature_name) = &meta_item.kind
|
||||
{
|
||||
err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol));
|
||||
let note = errors::ItemWasBehindFeature { feature: feature_name.symbol };
|
||||
err.subdiagnostic(self.tcx.dcx(), note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_errors::{codes::*, Applicability};
|
||||
use rustc_errors::{codes::*, Applicability, MultiSpan};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{
|
||||
symbol::{Ident, Symbol},
|
||||
@ -495,8 +495,8 @@ pub(crate) struct Relative2018 {
|
||||
pub(crate) struct AncestorOnly(#[primary_span] pub(crate) Span);
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_expected_found, code = E0577)]
|
||||
pub(crate) struct ExpectedFound {
|
||||
#[diag(resolve_expected_module_found, code = E0577)]
|
||||
pub(crate) struct ExpectedModuleFound {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
@ -525,8 +525,10 @@ pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span);
|
||||
#[diag(resolve_macro_expected_found)]
|
||||
pub(crate) struct MacroExpectedFound<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) found: &'a str,
|
||||
pub(crate) article: &'static str,
|
||||
pub(crate) expected: &'a str,
|
||||
pub(crate) macro_path: &'a str,
|
||||
#[subdiagnostic]
|
||||
@ -801,3 +803,421 @@ pub(crate) struct UnexpectedResUseAtOpInSlicePatWithRangeSugg {
|
||||
pub ident: Ident,
|
||||
pub snippet: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_extern_crate_loading_macro_not_at_crate_root, code = E0468)]
|
||||
pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_bad_macro_import, code = E0466)]
|
||||
pub(crate) struct BadMacroImport {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_extern_crate_self_requires_renaming)]
|
||||
pub(crate) struct ExternCrateSelfRequiresRenaming {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "extern crate self as name;", applicability = "has-placeholders")]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_macro_use_name_already_in_use)]
|
||||
#[note]
|
||||
pub(crate) struct MacroUseNameAlreadyInUse {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_imported_macro_not_found, code = E0469)]
|
||||
pub(crate) struct ImportedMacroNotFound {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_macro_extern_deprecated)]
|
||||
pub(crate) struct MacroExternDeprecated {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[help]
|
||||
pub inner_attribute: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_arguments_macro_use_not_allowed)]
|
||||
pub(crate) struct ArgumentsMacroUseNotAllowed {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_unnamed_crate_root_import)]
|
||||
pub(crate) struct UnnamedCrateRootImport {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)]
|
||||
pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)]
|
||||
pub(crate) struct ElidedAnonymousLivetimeReportError {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
resolve_elided_anonymous_lifetime_report_error_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion {
|
||||
#[suggestion_part(code = "for<'a> ")]
|
||||
pub(crate) lo: Span,
|
||||
#[suggestion_part(code = "'a ")]
|
||||
pub(crate) hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)]
|
||||
pub(crate) struct ExplicitAnonymousLivetimeReportError {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_implicit_elided_lifetimes_not_allowed_here, code = E0726)]
|
||||
pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_underscore_lifetime_is_reserved, code = E0637)]
|
||||
pub(crate) struct UnderscoreLifetimeIsReserved {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_static_lifetime_is_reserved, code = E0262)]
|
||||
pub(crate) struct StaticLifetimeIsReserved {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) lifetime: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_attempt_to_define_builtin_macro_twice, code = E0773)]
|
||||
pub(crate) struct AttemptToDefineBuiltinMacroTwice {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
#[note]
|
||||
pub(crate) note_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_variable_is_not_bound_in_all_patterns, code = E0408)]
|
||||
pub(crate) struct VariableIsNotBoundInAllPatterns {
|
||||
#[primary_span]
|
||||
pub(crate) multispan: MultiSpan,
|
||||
pub(crate) name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic, Debug, Clone)]
|
||||
#[label(resolve_pattern_doesnt_bind_name)]
|
||||
pub(crate) struct PatternDoesntBindName {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic, Debug, Clone)]
|
||||
#[label(resolve_variable_not_in_all_patterns)]
|
||||
pub(crate) struct VariableNotInAllPatterns {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_name_defined_multiple_time)]
|
||||
#[note]
|
||||
pub(crate) struct NameDefinedMultipleTime {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) descr: &'static str,
|
||||
pub(crate) container: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub(crate) label: NameDefinedMultipleTimeLabel,
|
||||
#[subdiagnostic]
|
||||
pub(crate) old_binding_label: Option<NameDefinedMultipleTimeOldBindingLabel>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum NameDefinedMultipleTimeLabel {
|
||||
#[label(resolve_name_defined_multiple_time_reimported)]
|
||||
Reimported {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
},
|
||||
#[label(resolve_name_defined_multiple_time_redefined)]
|
||||
Redefined {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum NameDefinedMultipleTimeOldBindingLabel {
|
||||
#[label(resolve_name_defined_multiple_time_old_binding_import)]
|
||||
Import {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
old_kind: &'static str,
|
||||
},
|
||||
#[label(resolve_name_defined_multiple_time_old_binding_definition)]
|
||||
Definition {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
old_kind: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_is_private, code = E0603)]
|
||||
pub(crate) struct IsPrivate<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ident_descr: &'a str,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_generic_arguments_in_macro_path)]
|
||||
pub(crate) struct GenericArgumentsInMacroPath {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_attributes_starting_with_rustc_are_reserved)]
|
||||
pub(crate) struct AttributesStartingWithRustcAreReserved {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_cannot_use_through_an_import)]
|
||||
pub(crate) struct CannotUseThroughAnImport {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) article: &'static str,
|
||||
pub(crate) descr: &'static str,
|
||||
#[note]
|
||||
pub(crate) binding_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_name_reserved_in_attribute_namespace)]
|
||||
pub(crate) struct NameReservedInAttributeNamespace {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_cannot_find_builtin_macro_with_name)]
|
||||
pub(crate) struct CannotFindBuiltinMacroWithName {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_tool_was_already_registered)]
|
||||
pub(crate) struct ToolWasAlreadyRegistered {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) tool: Ident,
|
||||
#[label]
|
||||
pub(crate) old_ident_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_tool_only_accepts_identifiers)]
|
||||
pub(crate) struct ToolOnlyAcceptsIdentifiers {
|
||||
#[label]
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) tool: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum DefinedHere {
|
||||
#[label(resolve_similarly_named_defined_here)]
|
||||
SimilarlyNamed {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
candidate_descr: &'static str,
|
||||
candidate: Symbol,
|
||||
},
|
||||
#[label(resolve_single_item_defined_here)]
|
||||
SingleItem {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
candidate_descr: &'static str,
|
||||
candidate: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(resolve_outer_ident_is_not_publicly_reexported)]
|
||||
pub(crate) struct OuterIdentIsNotPubliclyReexported {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) outer_ident_descr: &'static str,
|
||||
pub(crate) outer_ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(resolve_constructor_private_if_any_field_private)]
|
||||
pub(crate) struct ConstructorPrivateIfAnyFieldPrivate {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
resolve_consider_making_the_field_public,
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub(crate) struct ConsiderMakingTheFieldPublic {
|
||||
#[suggestion_part(code = "pub ")]
|
||||
pub(crate) spans: Vec<Span>,
|
||||
pub(crate) number_of_fields: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ImportIdent {
|
||||
#[suggestion(
|
||||
resolve_suggestion_import_ident_through_reexport,
|
||||
code = "{path}",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
ThroughReExport {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
path: String,
|
||||
},
|
||||
#[suggestion(
|
||||
resolve_suggestion_import_ident_directly,
|
||||
code = "{path}",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
Directly {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
path: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(resolve_note_and_refers_to_the_item_defined_here)]
|
||||
pub(crate) struct NoteAndRefersToTheItemDefinedHere<'a> {
|
||||
#[primary_span]
|
||||
pub(crate) span: MultiSpan,
|
||||
pub(crate) binding_descr: &'a str,
|
||||
pub(crate) binding_name: Ident,
|
||||
pub(crate) first: bool,
|
||||
pub(crate) dots: bool,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(resolve_remove_unnecessary_import, code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) struct RemoveUnnecessaryImport {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
resolve_remove_unnecessary_import,
|
||||
code = "",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub(crate) struct ToolOnlyRemoveUnnecessaryImport {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(resolve_ident_imported_here_but_it_is_desc)]
|
||||
pub(crate) struct IdentImporterHereButItIsDesc<'a> {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) imported_ident: Ident,
|
||||
pub(crate) imported_ident_desc: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(resolve_ident_in_scope_but_it_is_desc)]
|
||||
pub(crate) struct IdentInScopeButItIsDesc<'a> {
|
||||
pub(crate) imported_ident: Ident,
|
||||
pub(crate) imported_ident_desc: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(resolve_found_an_item_configured_out)]
|
||||
pub(crate) struct FoundItemConfigureOut {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(resolve_item_was_behind_feature)]
|
||||
pub(crate) struct ItemWasBehindFeature {
|
||||
pub(crate) feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_trait_impl_mismatch)]
|
||||
pub(crate) struct TraitImplMismatch {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) name: Symbol,
|
||||
pub(crate) kind: &'static str,
|
||||
pub(crate) trait_path: String,
|
||||
#[label(resolve_trait_impl_mismatch_label_item)]
|
||||
pub(crate) trait_item_span: Span,
|
||||
}
|
||||
|
@ -6,8 +6,7 @@
|
||||
//! If you wonder why there's no `early.rs`, that's because it's split into three files -
|
||||
//! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
|
||||
|
||||
use crate::errors::ImportsCannotReferTo;
|
||||
use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
|
||||
use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
|
||||
use crate::{BindingKey, Used};
|
||||
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||
@ -16,9 +15,7 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
codes::*, struct_span_code_err, Applicability, DiagArgValue, IntoDiagArg, StashKey,
|
||||
};
|
||||
use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey};
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
@ -1666,18 +1663,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
);
|
||||
}
|
||||
LifetimeRibKind::AnonymousReportError => {
|
||||
let (msg, note) = if elided {
|
||||
(
|
||||
"`&` without an explicit lifetime name cannot be used here",
|
||||
"explicit lifetime name needed here",
|
||||
)
|
||||
} else {
|
||||
("`'_` cannot be used here", "`'_` is a reserved lifetime name")
|
||||
};
|
||||
let mut diag =
|
||||
struct_span_code_err!(self.r.dcx(), lifetime.ident.span, E0637, "{}", msg,);
|
||||
diag.span_label(lifetime.ident.span, note);
|
||||
if elided {
|
||||
let mut suggestion = None;
|
||||
for rib in self.lifetime_ribs[i..].iter().rev() {
|
||||
if let LifetimeRibKind::Generics {
|
||||
span,
|
||||
@ -1685,19 +1672,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
..
|
||||
} = &rib.kind
|
||||
{
|
||||
diag.multipart_suggestion(
|
||||
"consider introducing a higher-ranked lifetime here",
|
||||
vec![
|
||||
(span.shrink_to_lo(), "for<'a> ".into()),
|
||||
(lifetime.ident.span.shrink_to_hi(), "'a ".into()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
suggestion =
|
||||
Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
|
||||
lo: span.shrink_to_lo(),
|
||||
hi: lifetime.ident.span.shrink_to_hi(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
diag.emit();
|
||||
self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
|
||||
span: lifetime.ident.span,
|
||||
suggestion,
|
||||
});
|
||||
} else {
|
||||
self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError {
|
||||
span: lifetime.ident.span,
|
||||
});
|
||||
};
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
||||
return;
|
||||
}
|
||||
@ -1863,13 +1854,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
|
||||
| LifetimeRibKind::AnonymousWarn(_) => {
|
||||
let mut err =
|
||||
self.r.dcx().create_err(errors::ImplicitElidedLifetimeNotAllowedHere {
|
||||
span: path_span,
|
||||
});
|
||||
let sess = self.r.tcx.sess;
|
||||
let mut err = struct_span_code_err!(
|
||||
sess.dcx(),
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
&mut err,
|
||||
@ -2313,7 +2302,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
let report_error = |this: &Self, ns| {
|
||||
if this.should_report_errs() {
|
||||
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
||||
this.r.dcx().emit_err(ImportsCannotReferTo { span: ident.span, what });
|
||||
this.r.dcx().emit_err(errors::ImportsCannotReferTo { span: ident.span, what });
|
||||
}
|
||||
};
|
||||
|
||||
@ -2633,29 +2622,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
}
|
||||
|
||||
if param.ident.name == kw::UnderscoreLifetime {
|
||||
struct_span_code_err!(
|
||||
self.r.dcx(),
|
||||
param.ident.span,
|
||||
E0637,
|
||||
"`'_` cannot be used here"
|
||||
)
|
||||
.with_span_label(param.ident.span, "`'_` is a reserved lifetime name")
|
||||
.emit();
|
||||
self.r
|
||||
.dcx()
|
||||
.emit_err(errors::UnderscoreLifetimeIsReserved { span: param.ident.span });
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if param.ident.name == kw::StaticLifetime {
|
||||
struct_span_code_err!(
|
||||
self.r.dcx(),
|
||||
param.ident.span,
|
||||
E0262,
|
||||
"invalid lifetime parameter name: `{}`",
|
||||
param.ident,
|
||||
)
|
||||
.with_span_label(param.ident.span, "'static is a reserved lifetime name")
|
||||
.emit();
|
||||
self.r.dcx().emit_err(errors::StaticLifetimeIsReserved {
|
||||
span: param.ident.span,
|
||||
lifetime: param.ident,
|
||||
});
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
|
@ -14,7 +14,7 @@ use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::StabilityLevel;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, StashKey};
|
||||
use rustc_errors::{Applicability, StashKey};
|
||||
use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
|
||||
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use rustc_expand::compile_declarative_macro;
|
||||
@ -123,20 +123,18 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
|
||||
match nested_meta.ident() {
|
||||
Some(ident) => {
|
||||
if let Some(old_ident) = registered_tools.replace(ident) {
|
||||
let msg = format!("{} `{}` was already registered", "tool", ident);
|
||||
tcx.dcx()
|
||||
.struct_span_err(ident.span, msg)
|
||||
.with_span_label(old_ident.span, "already registered here")
|
||||
.emit();
|
||||
tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered {
|
||||
span: ident.span,
|
||||
tool: ident,
|
||||
old_ident_span: old_ident.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let msg = format!("`{}` only accepts identifiers", sym::register_tool);
|
||||
let span = nested_meta.span();
|
||||
tcx.dcx()
|
||||
.struct_span_err(span, msg)
|
||||
.with_span_label(span, "not an identifier")
|
||||
.emit();
|
||||
tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers {
|
||||
span: nested_meta.span(),
|
||||
tool: sym::register_tool,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -485,13 +483,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
// Report errors for the resolved macro.
|
||||
for segment in &path.segments {
|
||||
if let Some(args) = &segment.args {
|
||||
self.dcx().span_err(args.span(), "generic arguments in macro path");
|
||||
self.dcx().emit_err(errors::GenericArgumentsInMacroPath { span: args.span() });
|
||||
}
|
||||
if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") {
|
||||
self.dcx().span_err(
|
||||
segment.ident.span,
|
||||
"attributes starting with `rustc` are reserved for use by the `rustc` compiler",
|
||||
);
|
||||
self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved {
|
||||
span: segment.ident.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,6 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let mut err = MacroExpectedFound {
|
||||
span: path.span,
|
||||
expected,
|
||||
article,
|
||||
found: res.descr(),
|
||||
macro_path: &path_str,
|
||||
remove_surrounding_derive: None,
|
||||
@ -550,10 +548,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str });
|
||||
}
|
||||
|
||||
self.dcx()
|
||||
.create_err(err)
|
||||
.with_span_label(path.span, format!("not {article} {expected}"))
|
||||
.emit();
|
||||
self.dcx().emit_err(err);
|
||||
|
||||
return Ok((self.dummy_ext(kind), Res::Err));
|
||||
}
|
||||
@ -872,13 +867,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
) {
|
||||
if let Some(Res::NonMacroAttr(kind)) = res {
|
||||
if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
|
||||
let msg =
|
||||
format!("cannot use {} {} through an import", kind.article(), kind.descr());
|
||||
let mut err = self.dcx().struct_span_err(span, msg);
|
||||
if let Some(binding) = binding {
|
||||
err.span_note(binding.span, format!("the {} imported here", kind.descr()));
|
||||
}
|
||||
err.emit();
|
||||
let binding_span = binding.map(|binding| binding.span);
|
||||
self.dcx().emit_err(errors::CannotUseThroughAnImport {
|
||||
span,
|
||||
article: kind.article(),
|
||||
descr: kind.descr(),
|
||||
binding_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -889,10 +884,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
if ident.name == sym::cfg || ident.name == sym::cfg_attr {
|
||||
let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
|
||||
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
|
||||
self.dcx().span_err(
|
||||
ident.span,
|
||||
format!("name `{ident}` is reserved in attribute namespace"),
|
||||
);
|
||||
self.dcx()
|
||||
.emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -916,19 +909,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
rule_spans = Vec::new();
|
||||
}
|
||||
BuiltinMacroState::AlreadySeen(span) => {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
item.span,
|
||||
E0773,
|
||||
"attempted to define built-in macro more than once"
|
||||
)
|
||||
.with_span_note(span, "previously defined here")
|
||||
.emit();
|
||||
self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice {
|
||||
span: item.span,
|
||||
note_span: span,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
|
||||
self.dcx().span_err(item.span, msg);
|
||||
self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName {
|
||||
span: item.span,
|
||||
ident: item.ident,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -736,7 +736,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
|
||||
fn to_disambiguator(num: u64) -> String {
|
||||
if let Some(num) = num.checked_sub(1) {
|
||||
format!("s{}_", base_n::encode(num as u128, 62))
|
||||
format!("s{}_", base_n::encode(num as u128, base_n::ALPHANUMERIC_ONLY))
|
||||
} else {
|
||||
"s_".to_string()
|
||||
}
|
||||
@ -746,7 +746,7 @@ fn to_disambiguator(num: u64) -> String {
|
||||
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
|
||||
fn to_seq_id(num: usize) -> String {
|
||||
if let Some(num) = num.checked_sub(1) {
|
||||
base_n::encode(num as u128, 36).to_uppercase()
|
||||
base_n::encode(num as u128, base_n::CASE_INSENSITIVE).to_uppercase()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||
/// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
|
||||
pub(crate) fn push_integer_62(x: u64, output: &mut String) {
|
||||
if let Some(x) = x.checked_sub(1) {
|
||||
base_n::push_str(x as u128, 62, output);
|
||||
base_n::push_str(x as u128, base_n::ALPHANUMERIC_ONLY, output);
|
||||
}
|
||||
output.push('_');
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ impl Drop for CurrentDir {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(miri, windows), ignore)] // File system access on Windows not supported by Miri
|
||||
fn create_dir_all_bare() {
|
||||
let tmpdir = common::tmpdir();
|
||||
CurrentDir::with(tmpdir.path(), || {
|
||||
|
@ -315,10 +315,8 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
|
||||
|
||||
// Prevent the usage of `Instant` in some cases:
|
||||
// - It's currently not supported for wasm targets.
|
||||
// - We disable it for miri because it's not available when isolation is enabled.
|
||||
let is_instant_unsupported = (cfg!(target_family = "wasm") && !cfg!(target_os = "wasi"))
|
||||
|| cfg!(target_os = "zkvm")
|
||||
|| cfg!(miri);
|
||||
let is_instant_unsupported =
|
||||
(cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) || cfg!(target_os = "zkvm");
|
||||
|
||||
let start_time = (!is_instant_unsupported).then(Instant::now);
|
||||
run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
|
||||
|
@ -1548,6 +1548,7 @@ impl Step for Extended {
|
||||
compiler: builder.compiler(stage, target),
|
||||
backend: "cranelift".to_string(),
|
||||
});
|
||||
add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {compiler, target});
|
||||
|
||||
let etc = builder.src.join("src/etc/installer");
|
||||
|
||||
@ -2224,6 +2225,53 @@ impl Step for LlvmTools {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct LlvmBitcodeLinker {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for LlvmBitcodeLinker {
|
||||
type Output = Option<GeneratedTarball>;
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker");
|
||||
run.alias("llvm-bitcode-linker").default_condition(default)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(LlvmBitcodeLinker {
|
||||
compiler: run.builder.compiler_for(
|
||||
run.builder.top_stage,
|
||||
run.builder.config.build,
|
||||
run.target,
|
||||
),
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
|
||||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
|
||||
let llbc_linker =
|
||||
builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] });
|
||||
|
||||
let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
|
||||
|
||||
// Prepare the image directory
|
||||
let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
|
||||
tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
|
||||
tarball.is_preview(true);
|
||||
|
||||
tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755);
|
||||
|
||||
Some(tarball.generate())
|
||||
}
|
||||
}
|
||||
|
||||
// Tarball intended for internal consumption to ease rustc/std development.
|
||||
//
|
||||
// Should not be considered stable by end users.
|
||||
|
@ -300,6 +300,15 @@ install!((self, builder, _config),
|
||||
);
|
||||
}
|
||||
};
|
||||
LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, {
|
||||
if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { compiler: self.compiler, target: self.target }) {
|
||||
install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball);
|
||||
} else {
|
||||
builder.info(
|
||||
&format!("skipping llvm-bitcode-linker stage{} ({})", self.compiler.stage, self.target),
|
||||
);
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
|
@ -746,9 +746,11 @@ impl Step for LlvmBitcodeLinker {
|
||||
.join(exe(bin_name, self.compiler.host));
|
||||
|
||||
if self.compiler.stage > 0 {
|
||||
let bindir = builder.sysroot(self.compiler).join("bin");
|
||||
t!(fs::create_dir_all(&bindir));
|
||||
let bin_destination = bindir.join(exe(bin_name, self.compiler.host));
|
||||
let bindir_self_contained = builder
|
||||
.sysroot(self.compiler)
|
||||
.join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple));
|
||||
t!(fs::create_dir_all(&bindir_self_contained));
|
||||
let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host));
|
||||
builder.copy_link(&tool_out, &bin_destination);
|
||||
bin_destination
|
||||
} else {
|
||||
|
@ -853,6 +853,7 @@ impl<'a> Builder<'a> {
|
||||
dist::Clippy,
|
||||
dist::Miri,
|
||||
dist::LlvmTools,
|
||||
dist::LlvmBitcodeLinker,
|
||||
dist::RustDev,
|
||||
dist::Bootstrap,
|
||||
dist::Extended,
|
||||
|
@ -377,7 +377,7 @@ struct SuiteOutcome {
|
||||
measured: usize,
|
||||
filtered_out: usize,
|
||||
/// The time it took to execute this test suite, or `None` if time measurement was not possible
|
||||
/// (e.g. due to running inside Miri).
|
||||
/// (e.g. due to running on wasm).
|
||||
exec_time: Option<f64>,
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ pub(crate) enum OverlayKind {
|
||||
RLS,
|
||||
RustAnalyzer,
|
||||
RustcCodegenCranelift,
|
||||
LlvmBitcodeLinker,
|
||||
}
|
||||
|
||||
impl OverlayKind {
|
||||
@ -64,6 +65,12 @@ impl OverlayKind {
|
||||
"compiler/rustc_codegen_cranelift/LICENSE-APACHE",
|
||||
"compiler/rustc_codegen_cranelift/LICENSE-MIT",
|
||||
],
|
||||
OverlayKind::LlvmBitcodeLinker => &[
|
||||
"COPYRIGHT",
|
||||
"LICENSE-APACHE",
|
||||
"LICENSE-MIT",
|
||||
"src/tools/llvm-bitcode-linker/README.md",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +94,7 @@ impl OverlayKind {
|
||||
.rust_analyzer_info
|
||||
.version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
|
||||
OverlayKind::RustcCodegenCranelift => builder.rust_version(),
|
||||
OverlayKind::LlvmBitcodeLinker => builder.rust_version(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ present in the list of expected values. If `"value"` is not in it, then `rustc`
|
||||
the future.*
|
||||
|
||||
To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside
|
||||
`values()`: `values(none())`. It can be followed or precessed by any number of `"value"`.
|
||||
`values()`: `values(none())`. It can be followed or preceded by any number of `"value"`.
|
||||
|
||||
To enable checking of values, but to provide an *none*/empty set of expected values
|
||||
(ie. expect `#[cfg(name)]`), use these forms:
|
||||
@ -163,7 +163,7 @@ fn poke_platypus() {}
|
||||
fn tame_lion() {}
|
||||
|
||||
#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known
|
||||
// condition name, it doens't expect any values
|
||||
// condition name, it doesn't expect any values
|
||||
fn tame_windows() {}
|
||||
```
|
||||
|
||||
|
@ -10,6 +10,10 @@ In addition to the stable set of linker flavors, the following unstable values a
|
||||
- `ptx`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker)
|
||||
for Nvidia NVPTX GPGPU support.
|
||||
- `bpf`: use [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
|
||||
- `llbc`: for linking in llvm bitcode. Install the preview rustup components`llvm-bitcode-linker`
|
||||
and `llvm-tools` to use as a self-contained linker by passing
|
||||
`-Zunstable-options -Clink-self-contained=+linker` together with `-Clinker-flavor=llbc`.
|
||||
Can currently only be used for Nvidia NVPTX targets (`nvptx64-nvidia-cuda`).
|
||||
|
||||
Additionally, a set of more precise linker flavors also exists, for example allowing targets to
|
||||
declare that they use the LLD linker by default. The following values are currently unstable, and
|
||||
|
@ -8,4 +8,4 @@ arguments from argfiles specified with `@shell:<path>`.
|
||||
|
||||
Because this feature controls the parsing of input arguments, the
|
||||
`-Zshell-argfiles` flag must be present before the argument specifying the
|
||||
shell-style arguemnt file.
|
||||
shell-style argument file.
|
||||
|
@ -62,7 +62,7 @@ impl Session {
|
||||
.arg("-o")
|
||||
.arg(&self.link_path)
|
||||
.output()
|
||||
.unwrap();
|
||||
.context("An error occured when calling llvm-link. Make sure the llvm-tools component is installed.")?;
|
||||
|
||||
if !llvm_link_output.status.success() {
|
||||
tracing::error!(
|
||||
@ -108,7 +108,9 @@ impl Session {
|
||||
opt_cmd.arg("--strip-debug");
|
||||
}
|
||||
|
||||
let opt_output = opt_cmd.output().unwrap();
|
||||
let opt_output = opt_cmd.output().context(
|
||||
"An error occured when calling opt. Make sure the llvm-tools component is installed.",
|
||||
)?;
|
||||
|
||||
if !opt_output.status.success() {
|
||||
tracing::error!(
|
||||
@ -133,8 +135,11 @@ impl Session {
|
||||
lcc_command.arg("--mcpu").arg(mcpu);
|
||||
}
|
||||
|
||||
let lcc_output =
|
||||
lcc_command.arg(&self.opt_path).arg("-o").arg(&self.out_path).output().unwrap();
|
||||
let lcc_output = lcc_command
|
||||
.arg(&self.opt_path)
|
||||
.arg("-o").arg(&self.out_path)
|
||||
.output()
|
||||
.context("An error occured when calling llc. Make sure the llvm-tools component is installed.")?;
|
||||
|
||||
if !lcc_output.status.success() {
|
||||
tracing::error!(
|
||||
|
@ -1005,8 +1005,8 @@ impl ::core::default::Default for Fieldless {
|
||||
impl ::core::hash::Hash for Fieldless {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_tag, state)
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_discr, state)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
@ -1015,9 +1015,9 @@ impl ::core::marker::StructuralPartialEq for Fieldless { }
|
||||
impl ::core::cmp::PartialEq for Fieldless {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Fieldless) -> bool {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
__self_tag == __arg1_tag
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
__self_discr == __arg1_discr
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
@ -1032,18 +1032,18 @@ impl ::core::cmp::PartialOrd for Fieldless {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Fieldless)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::Ord for Fieldless {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1096,8 +1096,8 @@ impl ::core::default::Default for Mixed {
|
||||
impl ::core::hash::Hash for Mixed {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_tag, state);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_discr, state);
|
||||
match self {
|
||||
Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state),
|
||||
Mixed::S { d1: __self_0, d2: __self_1 } => {
|
||||
@ -1114,9 +1114,9 @@ impl ::core::marker::StructuralPartialEq for Mixed { }
|
||||
impl ::core::cmp::PartialEq for Mixed {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Mixed) -> bool {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
__self_tag == __arg1_tag &&
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
__self_discr == __arg1_discr &&
|
||||
match (self, other) {
|
||||
(Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
|
||||
*__self_0 == *__arg1_0,
|
||||
@ -1143,8 +1143,8 @@ impl ::core::cmp::PartialOrd for Mixed {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Mixed)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match (self, other) {
|
||||
(Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
@ -1157,8 +1157,8 @@ impl ::core::cmp::PartialOrd for Mixed {
|
||||
cmp => cmp,
|
||||
},
|
||||
_ =>
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_tag,
|
||||
&__arg1_tag),
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_discr,
|
||||
&__arg1_discr),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1166,9 +1166,9 @@ impl ::core::cmp::PartialOrd for Mixed {
|
||||
impl ::core::cmp::Ord for Mixed {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
|
||||
::core::cmp::Ordering::Equal =>
|
||||
match (self, other) {
|
||||
(Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
|
||||
@ -1225,8 +1225,8 @@ impl ::core::fmt::Debug for Fielded {
|
||||
impl ::core::hash::Hash for Fielded {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_tag, state);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_discr, state);
|
||||
match self {
|
||||
Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state),
|
||||
Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state),
|
||||
@ -1240,9 +1240,9 @@ impl ::core::marker::StructuralPartialEq for Fielded { }
|
||||
impl ::core::cmp::PartialEq for Fielded {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Fielded) -> bool {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
__self_tag == __arg1_tag &&
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
__self_discr == __arg1_discr &&
|
||||
match (self, other) {
|
||||
(Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
|
||||
*__self_0 == *__arg1_0,
|
||||
@ -1270,8 +1270,8 @@ impl ::core::cmp::PartialOrd for Fielded {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Fielded)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match (self, other) {
|
||||
(Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
@ -1280,8 +1280,8 @@ impl ::core::cmp::PartialOrd for Fielded {
|
||||
(Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
_ =>
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_tag,
|
||||
&__arg1_tag),
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_discr,
|
||||
&__arg1_discr),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1289,9 +1289,9 @@ impl ::core::cmp::PartialOrd for Fielded {
|
||||
impl ::core::cmp::Ord for Fielded {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
|
||||
::core::cmp::Ordering::Equal =>
|
||||
match (self, other) {
|
||||
(Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
|
||||
@ -1346,8 +1346,8 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
|
||||
EnumGeneric<T, U> {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_tag, state);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
::core::hash::Hash::hash(&__self_discr, state);
|
||||
match self {
|
||||
EnumGeneric::One(__self_0) =>
|
||||
::core::hash::Hash::hash(__self_0, state),
|
||||
@ -1363,9 +1363,9 @@ impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
|
||||
::core::cmp::PartialEq for EnumGeneric<T, U> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &EnumGeneric<T, U>) -> bool {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
__self_tag == __arg1_tag &&
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
__self_discr == __arg1_discr &&
|
||||
match (self, other) {
|
||||
(EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
|
||||
*__self_0 == *__arg1_0,
|
||||
@ -1392,16 +1392,16 @@ impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd>
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &EnumGeneric<T, U>)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match (self, other) {
|
||||
(EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
(EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
_ =>
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_tag,
|
||||
&__arg1_tag),
|
||||
::core::cmp::PartialOrd::partial_cmp(&__self_discr,
|
||||
&__arg1_discr),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1410,9 +1410,9 @@ impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for
|
||||
EnumGeneric<T, U> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering {
|
||||
let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
|
||||
::core::cmp::Ordering::Equal =>
|
||||
match (self, other) {
|
||||
(EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
|
||||
|
13
tests/ui/variance/leaking-unnameables.rs
Normal file
13
tests/ui/variance/leaking-unnameables.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Test variance computation doesn't explode when we leak unnameable
|
||||
// types due to `-> _` recovery.
|
||||
|
||||
pub struct Type<'a>(&'a ());
|
||||
|
||||
pub fn g() {}
|
||||
|
||||
pub fn f<T>() -> _ {
|
||||
//~^ ERROR the placeholder `_` is not allowed within types on item signatures
|
||||
g
|
||||
}
|
||||
|
||||
fn main() {}
|
12
tests/ui/variance/leaking-unnameables.stderr
Normal file
12
tests/ui/variance/leaking-unnameables.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
||||
--> $DIR/leaking-unnameables.rs:8:18
|
||||
|
|
||||
LL | pub fn f<T>() -> _ {
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: replace with the correct return type: `fn()`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
Loading…
Reference in New Issue
Block a user