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:
bors 2024-04-15 16:46:59 +00:00
commit 99d0186b1d
53 changed files with 1319 additions and 796 deletions

View File

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

View File

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

View File

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

View File

@ -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(
&region_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;

View File

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

View File

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

View File

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

View File

@ -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(..) => {

View File

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

View File

@ -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()`.
///

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -853,6 +853,7 @@ impl<'a> Builder<'a> {
dist::Clippy,
dist::Miri,
dist::LlvmTools,
dist::LlvmBitcodeLinker,
dist::RustDev,
dist::Bootstrap,
dist::Extended,

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

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