diff --git a/Cargo.lock b/Cargo.lock
index ba8b2c270059..e5ea9fee8a6d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3452,7 +3452,7 @@ dependencies = [
[[package]]
name = "run_make_support"
-version = "0.0.0"
+version = "0.1.0"
dependencies = [
"gimli 0.28.1",
"object 0.34.0",
diff --git a/RELEASES.md b/RELEASES.md
index c1311ab14c53..2297924c7f33 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -147,7 +147,7 @@ Language
- [Split `refining_impl_trait` lint into `_reachable`, `_internal` variants](https://github.com/rust-lang/rust/pull/121720/)
- [Remove unnecessary type inference when using associated types inside of higher ranked `where`-bounds](https://github.com/rust-lang/rust/pull/119849)
- [Weaken eager detection of cyclic types during type inference](https://github.com/rust-lang/rust/pull/119989)
-- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Auto`](https://github.com/rust-lang/rust/pull/119338)
+- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Trait + Auto`](https://github.com/rust-lang/rust/pull/119338)
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index b1a17d5a24b6..a6662d4e0e4d 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,7 +1,9 @@
-#![cfg_attr(feature = "nightly", feature(step_trait))]
+// tidy-alphabetical-start
#![cfg_attr(feature = "nightly", allow(internal_features))]
#![cfg_attr(feature = "nightly", doc(rust_logo))]
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
+#![cfg_attr(feature = "nightly", feature(step_trait))]
+// tidy-alphabetical-end
use std::fmt;
use std::num::{NonZeroUsize, ParseIntError};
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index bdbc59821de2..810cb7a9f459 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -7,23 +7,25 @@
//!
//! This crate implements several kinds of arena.
+// tidy-alphabetical-start
+#![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine.
+#![allow(internal_features)]
+#![cfg_attr(test, feature(test))]
+#![deny(unsafe_op_in_unsafe_fn)]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(no_crate_inject, attr(deny(warnings)))
)]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(core_intrinsics)]
-#![feature(dropck_eyepatch)]
-#![feature(new_uninit)]
-#![feature(maybe_uninit_slice)]
#![feature(decl_macro)]
+#![feature(dropck_eyepatch)]
+#![feature(maybe_uninit_slice)]
+#![feature(new_uninit)]
#![feature(rustc_attrs)]
-#![cfg_attr(test, feature(test))]
+#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![allow(internal_features)]
-#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
+// tidy-alphabetical-end
use smallvec::SmallVec;
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 63cde3c6809c..7ca950e50e61 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -4,20 +4,22 @@
//!
//! This API is completely unstable and subject to change.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(deny(warnings)))
)]
#![doc(rust_logo)]
-#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![feature(never_type)]
#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(rustdoc_internals)]
#![feature(stmt_expr_attributes)]
+// tidy-alphabetical-end
pub mod util {
pub mod case;
diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs
index b1a77639b562..1d0c76f6ceae 100644
--- a/compiler/rustc_ast_ir/src/lib.rs
+++ b/compiler/rustc_ast_ir/src/lib.rs
@@ -1,6 +1,8 @@
+// tidy-alphabetical-start
+#![cfg_attr(feature = "nightly", allow(internal_features))]
#![cfg_attr(feature = "nightly", feature(never_type))]
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
-#![cfg_attr(feature = "nightly", allow(internal_features))]
+// tidy-alphabetical-end
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 27f8a6eae02a..d9dd0b3bca53 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -67,7 +67,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
return false;
};
if let Some(local_sig_id) = sig_id.as_local() {
- self.resolver.delegation_fn_sigs[&local_sig_id].has_self
+ // The value may be missing due to recursive delegation.
+ // Error will be emmited later during HIR ty lowering.
+ self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self)
} else {
match self.tcx.def_kind(sig_id) {
DefKind::Fn => false,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1c6b5b9af195..88f6e6c3b780 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -30,12 +30,14 @@
//! get confused if the spans from leaf AST nodes occur in multiple places
//! in the HIR, especially for multiple identifiers.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(let_chains)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
use rustc_ast::node_id::NodeMap;
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 74d0fff2734f..1f4bcd59afa0 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,13 +4,15 @@
//!
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
+// tidy-alphabetical-start
#![allow(internal_features)]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(iter_is_partitioned)]
#![feature(let_chains)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
pub mod ast_validation;
mod errors;
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index b9e217a21e39..84d9ce278a21 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,7 +1,9 @@
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(box_patterns)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
mod helpers;
pub mod pp;
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index f32b63a39f0a..4eb2a103fd8f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -877,18 +877,11 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere
}
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
- match nt {
- token::NtExpr(e) => self.expr_to_string(e),
- token::NtMeta(e) => self.attr_item_to_string(e),
- token::NtTy(e) => self.ty_to_string(e),
- token::NtPath(e) => self.path_to_string(e),
- token::NtItem(e) => self.item_to_string(e),
- token::NtBlock(e) => self.block_to_string(e),
- token::NtStmt(e) => self.stmt_to_string(e),
- token::NtPat(e) => self.pat_to_string(e),
- token::NtLiteral(e) => self.expr_to_string(e),
- token::NtVis(e) => self.vis_to_string(e),
- }
+ // We extract the token stream from the AST fragment and pretty print
+ // it, rather than using AST pretty printing, because `Nonterminal` is
+ // slated for removal in #124141. (This method will also then be
+ // removed.)
+ self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
@@ -1022,6 +1015,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere
Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
}
+ fn tts_to_string(&self, tokens: &TokenStream) -> String {
+ Self::to_string(|s| s.print_tts(tokens, false))
+ }
+
fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
let mut printer = State::new();
f(&mut printer);
@@ -2068,10 +2065,6 @@ impl<'a> State<'a> {
})
}
- pub(crate) fn tts_to_string(&self, tokens: &TokenStream) -> String {
- Self::to_string(|s| s.print_tts(tokens, false))
- }
-
pub(crate) fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
Self::to_string(|s| s.print_path_segment(p, false))
}
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index c61b7ea6d822..9cc53ad7ad8c 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -4,10 +4,12 @@
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
//! to this crate.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(let_chains)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
mod builtin;
mod session_diagnostics;
diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs
index ffcb290685a1..e964a709757c 100644
--- a/compiler/rustc_baked_icu_data/src/lib.rs
+++ b/compiler/rustc_baked_icu_data/src/lib.rs
@@ -20,10 +20,12 @@
//! --cldr-tag latest --icuexport-tag latest -o src/data
//! ```
-#![allow(internal_features)]
-#![feature(rustdoc_internals)]
-#![doc(rust_logo)]
+// tidy-alphabetical-start
#![allow(elided_lifetimes_in_paths)]
+#![allow(internal_features)]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
mod data {
include!("data/mod.rs");
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 97408fa20d79..b54e05b2b34a 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::graph::scc::Sccs;
+use crate::type_check::Locations;
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
@@ -6,8 +6,6 @@ use rustc_span::Span;
use std::fmt;
use std::ops::Index;
-use crate::type_check::Locations;
-
pub(crate) mod graph;
/// A set of NLL region constraints. These include "outlives"
@@ -45,18 +43,6 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars)
}
- /// Computes cycles (SCCs) in the graph of regions. In particular,
- /// find all regions R1, R2 such that R1: R2 and R2: R1 and group
- /// them into an SCC, and find the relationships between SCCs.
- pub(crate) fn compute_sccs(
- &self,
- constraint_graph: &graph::NormalConstraintGraph,
- static_region: RegionVid,
- ) -> Sccs {
- let region_graph = &constraint_graph.region_graph(self, static_region);
- Sccs::new(region_graph)
- }
-
pub(crate) fn outlives(
&self,
) -> &IndexSlice> {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 821a90366547..f32ff57fe88b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -557,8 +557,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// for the branching codepaths that aren't covered, to point at them.
let map = self.infcx.tcx.hir();
let body = map.body_owned_by(self.mir_def_id());
-
- let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
+ let mut visitor =
+ ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] };
visitor.visit_body(&body);
let mut show_assign_sugg = false;
@@ -4372,13 +4372,14 @@ impl<'hir> Visitor<'hir> for BreakFinder {
/// Given a set of spans representing statements initializing the relevant binding, visit all the
/// function expressions looking for branching code paths that *do not* initialize the binding.
-struct ConditionVisitor<'b> {
+struct ConditionVisitor<'b, 'tcx> {
+ tcx: TyCtxt<'tcx>,
spans: &'b [Span],
name: &'b str,
errors: Vec<(Span, String)>,
}
-impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
+impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
match ex.kind {
hir::ExprKind::If(cond, body, None) => {
@@ -4464,6 +4465,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
),
));
} else if let Some(guard) = &arm.guard {
+ if matches!(
+ self.tcx.hir_node(arm.body.hir_id),
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
+ ) {
+ continue;
+ }
self.errors.push((
arm.pat.span.to(guard.span),
format!(
@@ -4473,6 +4480,12 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
),
));
} else {
+ if matches!(
+ self.tcx.hir_node(arm.body.hir_id),
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
+ ) {
+ continue;
+ }
self.errors.push((
arm.pat.span,
format!(
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 1d5801467da8..5c9826ecca73 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,7 +1,7 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@@ -10,8 +10,10 @@
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 0e3140ca98b0..40b585005982 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -4,10 +4,10 @@ use std::rc::Rc;
use rustc_data_structures::binary_search_util;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_data_structures::graph::scc::Sccs;
+use rustc_data_structures::graph::scc::{self, Sccs};
use rustc_errors::Diag;
use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_index::{IndexSlice, IndexVec};
+use rustc_index::IndexVec;
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
@@ -19,7 +19,7 @@ use rustc_middle::mir::{
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_span::Span;
@@ -46,6 +46,97 @@ mod reverse_sccs;
pub mod values;
+pub type ConstraintSccs = Sccs;
+
+/// An annotation for region graph SCCs that tracks
+/// the values of its elements.
+#[derive(Copy, Debug, Clone)]
+pub struct RegionTracker {
+ /// The largest universe of a placeholder reached from this SCC.
+ /// This includes placeholders within this SCC.
+ max_placeholder_universe_reached: UniverseIndex,
+
+ /// The smallest universe index reachable form the nodes of this SCC.
+ min_reachable_universe: UniverseIndex,
+
+ /// The representative Region Variable Id for this SCC. We prefer
+ /// placeholders over existentially quantified variables, otherwise
+ /// it's the one with the smallest Region Variable ID.
+ representative: RegionVid,
+
+ /// Is the current representative a placeholder?
+ representative_is_placeholder: bool,
+
+ /// Is the current representative existentially quantified?
+ representative_is_existential: bool,
+}
+
+impl scc::Annotation for RegionTracker {
+ fn merge_scc(mut self, mut other: Self) -> Self {
+ // Prefer any placeholder over any existential
+ if other.representative_is_placeholder && self.representative_is_existential {
+ other.merge_min_max_seen(&self);
+ return other;
+ }
+
+ if self.representative_is_placeholder && other.representative_is_existential
+ || (self.representative <= other.representative)
+ {
+ self.merge_min_max_seen(&other);
+ return self;
+ }
+ other.merge_min_max_seen(&self);
+ other
+ }
+
+ fn merge_reached(mut self, other: Self) -> Self {
+ // No update to in-component values, only add seen values.
+ self.merge_min_max_seen(&other);
+ self
+ }
+}
+
+impl RegionTracker {
+ fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
+ let (representative_is_placeholder, representative_is_existential) = match definition.origin
+ {
+ rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false),
+ rustc_infer::infer::NllRegionVariableOrigin::Placeholder(_) => (true, false),
+ rustc_infer::infer::NllRegionVariableOrigin::Existential { .. } => (false, true),
+ };
+
+ let placeholder_universe =
+ if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT };
+
+ Self {
+ max_placeholder_universe_reached: placeholder_universe,
+ min_reachable_universe: definition.universe,
+ representative: rvid,
+ representative_is_placeholder,
+ representative_is_existential,
+ }
+ }
+ fn universe(self) -> UniverseIndex {
+ self.min_reachable_universe
+ }
+
+ fn merge_min_max_seen(&mut self, other: &Self) {
+ self.max_placeholder_universe_reached = std::cmp::max(
+ self.max_placeholder_universe_reached,
+ other.max_placeholder_universe_reached,
+ );
+
+ self.min_reachable_universe =
+ std::cmp::min(self.min_reachable_universe, other.min_reachable_universe);
+ }
+
+ /// Returns `true` if during the annotated SCC reaches a placeholder
+ /// with a universe larger than the smallest reachable one, `false` otherwise.
+ pub fn has_incompatible_universes(&self) -> bool {
+ self.universe().cannot_name(self.max_placeholder_universe_reached)
+ }
+}
+
pub struct RegionInferenceContext<'tcx> {
pub var_infos: VarInfos,
@@ -72,7 +163,7 @@ pub struct RegionInferenceContext<'tcx> {
/// The SCC computed from `constraints` and the constraint
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
/// compute the values of each region.
- constraint_sccs: Rc>,
+ constraint_sccs: Rc,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
/// `B: A`. This is used to compute the universal regions that are required
@@ -91,22 +182,6 @@ pub struct RegionInferenceContext<'tcx> {
/// Map universe indexes to information on why we created it.
universe_causes: FxIndexMap>,
- /// Contains the minimum universe of any variable within the same
- /// SCC. We will ensure that no SCC contains values that are not
- /// visible from this index.
- scc_universes: IndexVec,
-
- /// Contains the "representative" region of each SCC.
- /// It is defined as the one with the minimal RegionVid, favoring
- /// free regions, then placeholders, then existential regions.
- ///
- /// It is a hacky way to manage checking regions for equality,
- /// since we can 'canonicalize' each region to the representative
- /// of its SCC and be sure that -- if they have the same repr --
- /// they *must* be equal (though not having the same repr does not
- /// mean they are unequal).
- scc_representatives: IndexVec,
-
/// The final inferred values of the region variables; we compute
/// one value per SCC. To get the value for any given *region*,
/// you first find which scc it is a part of.
@@ -151,7 +226,7 @@ pub(crate) struct AppliedMemberConstraint {
}
#[derive(Debug)]
-pub(crate) struct RegionDefinition<'tcx> {
+pub struct RegionDefinition<'tcx> {
/// What kind of variable is this -- a free region? existential
/// variable? etc. (See the `NllRegionVariableOrigin` for more
/// info.)
@@ -250,7 +325,7 @@ pub enum ExtraConstraintInfo {
}
#[instrument(skip(infcx, sccs), level = "debug")]
-fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc>) {
+fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
use crate::renumber::RegionCtxt;
let var_to_origin = infcx.reg_var_to_origin.borrow();
@@ -264,7 +339,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc>();
+ let edge_representatives = sccs
+ .successors(*scc_idx)
+ .iter()
+ .map(|scc_idx| components_representatives[scc_idx])
+ .collect::>();
scc_node_to_edges.insert((scc_idx, repr), edge_representatives);
}
@@ -320,7 +396,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// The `outlives_constraints` and `type_tests` are an initial set
/// of constraints produced by the MIR type check.
pub(crate) fn new(
- _infcx: &BorrowckInferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'tcx>,
var_infos: VarInfos,
universal_regions: Rc>,
placeholder_indices: Rc,
@@ -343,13 +419,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
+ let fr_static = universal_regions.fr_static;
let constraints = Frozen::freeze(outlives_constraints);
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
- let fr_static = universal_regions.fr_static;
- let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
+ let constraint_sccs = {
+ let constraint_graph = constraints.graph(definitions.len());
+ let region_graph = &constraint_graph.region_graph(&constraints, fr_static);
+ let sccs = ConstraintSccs::new_with_annotation(®ion_graph, |r| {
+ RegionTracker::new(r, &definitions[r])
+ });
+ Rc::new(sccs)
+ };
if cfg!(debug_assertions) {
- sccs_info(_infcx, constraint_sccs.clone());
+ sccs_info(infcx, &constraint_sccs);
}
let mut scc_values =
@@ -360,10 +443,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
scc_values.merge_liveness(scc, region, &liveness_constraints);
}
- let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
-
- let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
-
let member_constraints =
Rc::new(member_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
@@ -378,8 +457,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
member_constraints,
member_constraints_applied: Vec::new(),
universe_causes,
- scc_universes,
- scc_representatives,
scc_values,
type_tests,
universal_regions,
@@ -391,123 +468,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
result
}
- /// Each SCC is the combination of many region variables which
- /// have been equated. Therefore, we can associate a universe with
- /// each SCC which is minimum of all the universes of its
- /// constituent regions -- this is because whatever value the SCC
- /// takes on must be a value that each of the regions within the
- /// SCC could have as well. This implies that the SCC must have
- /// the minimum, or narrowest, universe.
- fn compute_scc_universes(
- constraint_sccs: &Sccs,
- definitions: &IndexSlice>,
- ) -> IndexVec {
- let num_sccs = constraint_sccs.num_sccs();
- let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs);
-
- debug!("compute_scc_universes()");
-
- // For each region R in universe U, ensure that the universe for the SCC
- // that contains R is "no bigger" than U. This effectively sets the universe
- // for each SCC to be the minimum of the regions within.
- for (region_vid, region_definition) in definitions.iter_enumerated() {
- let scc = constraint_sccs.scc(region_vid);
- let scc_universe = &mut scc_universes[scc];
- let scc_min = std::cmp::min(region_definition.universe, *scc_universe);
- if scc_min != *scc_universe {
- *scc_universe = scc_min;
- debug!(
- "compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \
- because it contains {region_vid:?} in {region_universe:?}",
- scc = scc,
- scc_min = scc_min,
- region_vid = region_vid,
- region_universe = region_definition.universe,
- );
- }
- }
-
- // Walk each SCC `A` and `B` such that `A: B`
- // and ensure that universe(A) can see universe(B).
- //
- // This serves to enforce the 'empty/placeholder' hierarchy
- // (described in more detail on `RegionKind`):
- //
- // ```
- // static -----+
- // | |
- // empty(U0) placeholder(U1)
- // | /
- // empty(U1)
- // ```
- //
- // In particular, imagine we have variables R0 in U0 and R1
- // created in U1, and constraints like this;
- //
- // ```
- // R1: !1 // R1 outlives the placeholder in U1
- // R1: R0 // R1 outlives R0
- // ```
- //
- // Here, we wish for R1 to be `'static`, because it
- // cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
- //
- // Thanks to this loop, what happens is that the `R1: R0`
- // constraint lowers the universe of `R1` to `U0`, which in turn
- // means that the `R1: !1` constraint will (later) cause
- // `R1` to become `'static`.
- for scc_a in constraint_sccs.all_sccs() {
- for &scc_b in constraint_sccs.successors(scc_a) {
- let scc_universe_a = scc_universes[scc_a];
- let scc_universe_b = scc_universes[scc_b];
- let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b);
- if scc_universe_a != scc_universe_min {
- scc_universes[scc_a] = scc_universe_min;
-
- debug!(
- "compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \
- because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}",
- scc_a = scc_a,
- scc_b = scc_b,
- scc_universe_min = scc_universe_min,
- scc_universe_b = scc_universe_b
- );
- }
- }
- }
-
- debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes);
-
- scc_universes
- }
-
- /// For each SCC, we compute a unique `RegionVid`. See the
- /// `scc_representatives` field of `RegionInferenceContext` for
- /// more details.
- fn compute_scc_representatives(
- constraints_scc: &Sccs,
- definitions: &IndexSlice>,
- ) -> IndexVec {
- let num_sccs = constraints_scc.num_sccs();
- let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs);
-
- // Iterate over all RegionVids *in-order* and pick the least RegionVid as the
- // representative of its SCC. This naturally prefers free regions over others.
- for (vid, def) in definitions.iter_enumerated() {
- let repr = &mut scc_representatives[constraints_scc.scc(vid)];
- if *repr == ty::RegionVid::MAX {
- *repr = vid;
- } else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_))
- && matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. })
- {
- // Pick placeholders over existentials even if they have a greater RegionVid.
- *repr = vid;
- }
- }
-
- scc_representatives
- }
-
/// Initializes the region variables for each universally
/// quantified region (lifetime parameter). The first N variables
/// always correspond to the regions appearing in the function
@@ -528,12 +488,45 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// and (b) any universally quantified regions that it outlives,
/// which in this case is just itself. R1 (`'b`) in contrast also
/// outlives `'a` and hence contains R0 and R1.
+ ///
+ /// This bit of logic also handles invalid universe relations
+ /// for higher-kinded types.
+ ///
+ /// We Walk each SCC `A` and `B` such that `A: B`
+ /// and ensure that universe(A) can see universe(B).
+ ///
+ /// This serves to enforce the 'empty/placeholder' hierarchy
+ /// (described in more detail on `RegionKind`):
+ ///
+ /// ```ignore (illustrative)
+ /// static -----+
+ /// | |
+ /// empty(U0) placeholder(U1)
+ /// | /
+ /// empty(U1)
+ /// ```
+ ///
+ /// In particular, imagine we have variables R0 in U0 and R1
+ /// created in U1, and constraints like this;
+ ///
+ /// ```ignore (illustrative)
+ /// R1: !1 // R1 outlives the placeholder in U1
+ /// R1: R0 // R1 outlives R0
+ /// ```
+ ///
+ /// Here, we wish for R1 to be `'static`, because it
+ /// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
+ ///
+ /// Thanks to this loop, what happens is that the `R1: R0`
+ /// constraint has lowered the universe of `R1` to `U0`, which in turn
+ /// means that the `R1: !1` constraint here will cause
+ /// `R1` to become `'static`.
fn init_free_and_bound_regions(&mut self) {
// Update the names (if any)
// This iterator has unstable order but we collect it all into an IndexVec
for (external_name, variable) in self.universal_regions.named_universal_regions() {
debug!(
- "init_universal_regions: region {:?} has external name {:?}",
+ "init_free_and_bound_regions: region {:?} has external name {:?}",
variable, external_name
);
self.definitions[variable].external_name = Some(external_name);
@@ -559,7 +552,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// its universe `ui` and its extensions. So we
// can't just add it into `scc` unless the
// universe of the scc can name this region.
- let scc_universe = self.scc_universes[scc];
+ let scc_universe = self.scc_universe(scc);
if scc_universe.can_name(placeholder.universe) {
self.scc_values.add_element(scc, placeholder);
} else {
@@ -640,8 +633,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Returns access to the value of `r` for debugging purposes.
pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
- let scc = self.constraint_sccs.scc(r);
- self.scc_universes[scc]
+ self.scc_universe(self.constraint_sccs.scc(r))
}
/// Once region solving has completed, this function will return the member constraints that
@@ -737,8 +729,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// SCC. For each SCC, we visit its successors and compute
// their values, then we union all those values to get our
// own.
- let constraint_sccs = self.constraint_sccs.clone();
- for scc in constraint_sccs.all_sccs() {
+ for scc in self.constraint_sccs.all_sccs() {
self.compute_value_for_scc(scc);
}
@@ -817,20 +808,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// if one exists.
for c_r in &mut choice_regions {
let scc = self.constraint_sccs.scc(*c_r);
- *c_r = self.scc_representatives[scc];
+ *c_r = self.scc_representative(scc);
}
// If the member region lives in a higher universe, we currently choose
// the most conservative option by leaving it unchanged.
- if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+
+ if !self.constraint_sccs().annotation(scc).universe().is_root() {
return;
}
- debug_assert!(
- self.scc_values.placeholders_contained_in(scc).next().is_none(),
- "scc {:?} in a member constraint has placeholder value: {:?}",
- scc,
- self.scc_values.region_value_str(scc),
- );
// The existing value for `scc` is a lower-bound. This will
// consist of some set `{P} + {LB}` of points `{P}` and
@@ -900,12 +886,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// in `scc_a`. Used during constraint propagation, and only once
/// the value of `scc_b` has been computed.
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
- let universe_a = self.scc_universes[scc_a];
+ let universe_a = self.constraint_sccs().annotation(scc_a).universe();
+ let universe_b = self.constraint_sccs().annotation(scc_b).universe();
// Quick check: if scc_b's declared universe is a subset of
// scc_a's declared universe (typically, both are ROOT), then
// it cannot contain any problematic universe elements.
- if universe_a.can_name(self.scc_universes[scc_b]) {
+ if universe_a.can_name(universe_b) {
return true;
}
@@ -1033,7 +1020,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!(
"lower_bound = {:?} r_scc={:?} universe={:?}",
- lower_bound, r_scc, self.scc_universes[r_scc]
+ lower_bound,
+ r_scc,
+ self.constraint_sccs.annotation(r_scc).universe()
);
// If the type test requires that `T: 'a` where `'a` is a
@@ -1321,7 +1310,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
tcx.fold_regions(value, |r, _db| {
let vid = self.to_region_vid(r);
let scc = self.constraint_sccs.scc(vid);
- let repr = self.scc_representatives[scc];
+ let repr = self.scc_representative(scc);
ty::Region::new_var(tcx, repr)
})
}
@@ -1547,6 +1536,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
+ /// The minimum universe of any variable reachable from this
+ /// SCC, inside or outside of it.
+ fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
+ self.constraint_sccs().annotation(scc).universe()
+ }
/// Checks the final value for the free region `fr` to see if it
/// grew too large. In particular, examine what `end(X)` points
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
@@ -1566,8 +1560,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Because this free region must be in the ROOT universe, we
// know it cannot contain any bound universes.
- assert!(self.scc_universes[longer_fr_scc].is_root());
- debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none());
+ assert!(self.scc_universe(longer_fr_scc).is_root());
// Only check all of the relations for the main representative of each
// SCC, otherwise just check that we outlive said representative. This
@@ -1575,7 +1568,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// closures.
// Note that the representative will be a universal region if there is
// one in this SCC, so we will always check the representative here.
- let representative = self.scc_representatives[longer_fr_scc];
+ let representative = self.scc_representative(longer_fr_scc);
if representative != longer_fr {
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
longer_fr,
@@ -1796,16 +1789,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// `true` if `r1` cannot name that placeholder in its
/// value; otherwise, returns `false`.
pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
- debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
-
match self.definitions[r2].origin {
NllRegionVariableOrigin::Placeholder(placeholder) => {
- let universe1 = self.definitions[r1].universe;
+ let r1_universe = self.definitions[r1].universe;
debug!(
- "cannot_name_value_of: universe1={:?} placeholder={:?}",
- universe1, placeholder
+ "cannot_name_value_of: universe1={r1_universe:?} placeholder={:?}",
+ placeholder
);
- universe1.cannot_name(placeholder.universe)
+ r1_universe.cannot_name(placeholder.universe)
}
NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
@@ -1835,6 +1826,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// Returns: a series of constraints as well as the region `R`
/// that passed the target test.
+ #[instrument(skip(self, target_test), ret)]
pub(crate) fn find_constraint_paths_between_regions(
&self,
from_region: RegionVid,
@@ -1932,7 +1924,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(skip(self), level = "trace", ret)]
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
- trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
+ trace!(universe = ?self.region_universe(fr1));
self.find_constraint_paths_between_regions(fr1, |r| {
// First look for some `r` such that `fr1: r` and `r` is live at `location`
trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r));
@@ -2252,8 +2244,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// This can be used to quickly under-approximate the regions which are equal to each other
/// and their relative orderings.
// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
- pub fn constraint_sccs(&self) -> &Sccs {
- self.constraint_sccs.as_ref()
+ pub fn constraint_sccs(&self) -> &ConstraintSccs {
+ &self.constraint_sccs
}
/// Access to the region graph, built from the outlives constraints.
@@ -2282,6 +2274,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let point = self.liveness_constraints.point_from_location(location);
self.liveness_constraints.is_loan_live_at(loan_idx, point)
}
+
+ /// Returns the representative `RegionVid` for a given SCC.
+ /// See `RegionTracker` for how a region variable ID is chosen.
+ ///
+ /// It is a hacky way to manage checking regions for equality,
+ /// since we can 'canonicalize' each region to the representative
+ /// of its SCC and be sure that -- if they have the same repr --
+ /// they *must* be equal (though not having the same repr does not
+ /// mean they are unequal).
+ fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
+ self.constraint_sccs.annotation(scc).representative
+ }
}
impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 06adb686ed48..51c3648d7307 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -85,7 +85,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Use the SCC representative instead of directly using `region`.
// See [rustc-dev-guide chapter] ยง "Strict lifetime equality".
let scc = self.constraint_sccs.scc(region.as_var());
- let vid = self.scc_representatives[scc];
+ let vid = self.scc_representative(scc);
let named = match self.definitions[vid].origin {
// Iterate over all universal regions in a consistent order and find the
// *first* equal region. This makes sure that equal lifetimes will have
@@ -213,7 +213,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let scc = self.constraint_sccs.scc(vid);
// Special handling of higher-ranked regions.
- if !self.scc_universes[scc].is_root() {
+ if !self.scc_universe(scc).is_root() {
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
// If the region contains a single placeholder then they're equal.
Some((0, placeholder)) => {
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 2c34fc583c83..c531c9b209be 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,9 +1,10 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
-use rustc_infer::infer::relate::{ObligationEmittingRelation, StructurallyRelateAliases};
+use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::{Obligation, PredicateObligations};
+use rustc_infer::traits::solve::Goal;
+use rustc_infer::traits::Obligation;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::span_bug;
use rustc_middle::traits::query::NoSolution;
@@ -153,9 +154,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
"expected at least one opaque type in `relate_opaques`, got {a} and {b}."
),
};
- let cause = ObligationCause::dummy_with_span(self.span());
- let obligations = infcx.handle_opaque_type(a, b, &cause, self.param_env())?.obligations;
- self.register_obligations(obligations);
+ self.register_goals(infcx.handle_opaque_type(a, b, self.span(), self.param_env())?);
Ok(())
}
@@ -533,7 +532,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx
}
}
-impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
+impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
fn span(&self) -> Span {
self.locations.span(self.type_checker.body)
}
@@ -550,22 +549,32 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
&mut self,
obligations: impl IntoIterator, ty::Predicate<'tcx>>>,
) {
- self.register_obligations(
- obligations
- .into_iter()
- .map(|to_pred| {
- Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
- })
- .collect(),
+ let tcx = self.tcx();
+ let param_env = self.param_env();
+ self.register_goals(
+ obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
);
}
- fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+ fn register_goals(
+ &mut self,
+ obligations: impl IntoIterator- >>,
+ ) {
let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
self.locations,
self.category,
InstantiateOpaqueType {
- obligations,
+ obligations: obligations
+ .into_iter()
+ .map(|goal| {
+ Obligation::new(
+ self.tcx(),
+ ObligationCause::dummy_with_span(self.span()),
+ goal.param_env,
+ goal.predicate,
+ )
+ })
+ .collect(),
// These fields are filled in during execution of the operation
base_universe: None,
region_constraints: None,
@@ -573,7 +582,7 @@ impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx
);
}
- fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
a.into(),
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 744c7f9d0900..35b0f43d8af7 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -1,12 +1,12 @@
//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![feature(rustdoc_internals)]
-#![doc(rust_logo)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
@@ -15,7 +15,9 @@
#![feature(lint_reasons)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
+#![feature(rustdoc_internals)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
extern crate proc_macro;
diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
index 166b00600438..2e08fbca8ef2 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
@@ -2,20 +2,23 @@
#![feature(type_alias_impl_trait)]
-trait T {
- type Item;
-}
+mod helper {
+ pub trait T {
+ type Item;
+ }
-type Alias<'a> = impl T
- ;
+ pub type Alias<'a> = impl T
- ;
-struct S;
-impl<'a> T for &'a S {
- type Item = &'a ();
-}
+ struct S;
+ impl<'a> T for &'a S {
+ type Item = &'a ();
+ }
-fn filter_positive<'a>() -> Alias<'a> {
- &S
+ pub fn filter_positive<'a>() -> Alias<'a> {
+ &S
+ }
}
+use helper::*;
fn with_positive(fun: impl Fn(Alias<'_>)) {
fun(filter_positive());
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
index 6af11e54d88a..584dbdb647f6 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-rawdylib-processprng.patch
@@ -12,7 +12,7 @@ diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/wind
index ad8e01bfa9b..9ca8e4c16ce 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
-@@ -323,7 +323,7 @@ pub unsafe fn NtWriteFile(
+@@ -312,7 +312,7 @@ pub unsafe fn NtWriteFile(
// Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
cfg_if::cfg_if! {
@@ -26,8 +26,8 @@ index e427546222a..f2fe42a4d51 100644
--- a/library/std/src/sys/pal/windows/rand.rs
+++ b/library/std/src/sys/pal/windows/rand.rs
@@ -2,7 +2,7 @@
- use core::mem;
- use core::ptr;
+
+ use crate::sys::c;
-#[cfg(not(target_vendor = "win7"))]
+#[cfg(any())]
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 39bbad16b0c0..0fea3fd42539 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,13 +1,16 @@
-#![cfg_attr(doc, allow(internal_features))]
-#![cfg_attr(doc, feature(rustdoc_internals))]
-#![cfg_attr(doc, doc(rust_logo))]
-#![feature(rustc_private)]
-// Note: please avoid adding other feature gates where possible
+// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(doc, allow(internal_features))]
+#![cfg_attr(doc, doc(rust_logo))]
+#![cfg_attr(doc, feature(rustdoc_internals))]
+// Note: please avoid adding other feature gates where possible
+#![feature(rustc_private)]
+// Note: please avoid adding other feature gates where possible
#![warn(rust_2018_idioms)]
-#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]
+#![warn(unused_lifetimes)]
+// tidy-alphabetical-end
extern crate jobserver;
#[macro_use]
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 53a098d178e4..7d92888feeed 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -142,6 +142,14 @@ pub unsafe fn create_module<'ll>(
}
}
+ if llvm_version < (19, 0, 0) {
+ if sess.target.arch == "loongarch64" {
+ // LLVM 19 updates the LoongArch64 data layout.
+ // See https://github.com/llvm/llvm-project/pull/93814
+ target_data_layout = target_data_layout.replace("-n32:64", "-n64");
+ }
+ }
+
// Ensure the data-layout values hardcoded remain the defaults.
{
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 0029ec9d09a2..bb76d3883934 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -4,16 +4,18 @@
//!
//! This API is completely unstable and subject to change.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
-#![doc(rust_logo)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![doc(rust_logo)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(hash_raw_entry)]
+#![feature(impl_trait_in_assoc_type)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
-#![feature(impl_trait_in_assoc_type)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use back::owned_target_machine::OwnedTargetMachine;
use back::write::{create_informational_target_machine, create_target_machine};
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 3b1921d40e6b..e801af400141 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,15 +1,17 @@
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![doc(rust_logo)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(negative_impls)]
+#![feature(rustdoc_internals)]
#![feature(strict_provenance)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 19414c72c6a4..6961e13c2399 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -274,9 +274,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Let's make sure v is sign-extended *if* it has a signed type.
let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
- let v = scalar.to_bits(src_layout.size)?;
- let v = if signed { self.sign_extend(v, src_layout) } else { v };
- trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
+ let v = match src_layout.ty.kind() {
+ Uint(_) | RawPtr(..) | FnPtr(..) => scalar.to_uint(src_layout.size)?,
+ Int(_) => scalar.to_int(src_layout.size)? as u128, // we will cast back to `i128` below if the sign matters
+ Bool => scalar.to_bool()?.into(),
+ Char => scalar.to_char()?.into(),
+ _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty),
+ };
Ok(match *cast_ty.kind() {
// int -> int
@@ -383,7 +387,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => {
let ptr = self.read_pointer(src)?;
- // u64 cast is from usize to u64, which is always good
let val = Immediate::new_slice(
ptr,
length.eval_target_usize(*self.tcx, self.param_env),
@@ -401,13 +404,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (old_data, old_vptr) = val.to_scalar_pair();
let old_data = old_data.to_pointer(self)?;
let old_vptr = old_vptr.to_pointer(self)?;
- let (ty, old_trait) = self.get_ptr_vtable(old_vptr)?;
- if old_trait != data_a.principal() {
- throw_ub!(InvalidVTableTrait {
- expected_trait: data_a,
- vtable_trait: old_trait,
- });
- }
+ let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 7c2100fcbe38..e28cc05cc2a8 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -765,10 +765,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Ok(Some((full_size, full_align)))
}
- ty::Dynamic(_, _, ty::Dyn) => {
+ ty::Dynamic(expected_trait, _, ty::Dyn) => {
let vtable = metadata.unwrap_meta().to_pointer(self)?;
// Read size and align from vtable (already checks size).
- Ok(Some(self.get_vtable_size_and_align(vtable)?))
+ Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
}
ty::Slice(_) | ty::Str => {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index dac5c10addc2..1d54da267eeb 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -197,7 +197,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
let layout_val = self.layout_of(instance_args.type_at(0))?;
let val = self.read_scalar(&args[0])?;
- let val_bits = val.to_bits(layout_val.size)?;
+ let val_bits = val.to_bits(layout_val.size)?; // sign is ignored here
let layout_raw_shift = self.layout_of(self.tcx.types.u32)?;
let raw_shift = self.read_scalar(&args[1])?;
@@ -432,12 +432,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::vtable_size => {
let ptr = self.read_pointer(&args[0])?;
- let (size, _align) = self.get_vtable_size_and_align(ptr)?;
+ // `None` because we don't know which trait to expect here; any vtable is okay.
+ let (size, _align) = self.get_vtable_size_and_align(ptr, None)?;
self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
}
sym::vtable_align => {
let ptr = self.read_pointer(&args[0])?;
- let (_size, align) = self.get_vtable_size_and_align(ptr)?;
+ // `None` because we don't know which trait to expect here; any vtable is okay.
+ let (_size, align) = self.get_vtable_size_and_align(ptr, None)?;
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
}
@@ -484,7 +486,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ret_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, Scalar
> {
assert!(layout.ty.is_integral(), "invalid type for numeric intrinsic: {}", layout.ty);
- let bits = val.to_bits(layout.size)?;
+ let bits = val.to_bits(layout.size)?; // these operations all ignore the sign
let extra = 128 - u128::from(layout.size.bits());
let bits_out = match name {
sym::ctpop => u128::from(bits.count_ones()),
@@ -519,6 +521,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
// First, check x % y != 0 (or if that computation overflows).
let rem = self.binary_op(BinOp::Rem, a, b)?;
+ // sign does not matter for 0 test, so `to_bits` is fine
if rem.to_scalar().to_bits(a.layout.size)? != 0 {
throw_ub_custom!(
fluent::const_eval_exact_div_has_remainder,
@@ -545,22 +548,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair();
Ok(if overflowed.to_bool()? {
let size = l.layout.size;
- let num_bits = size.bits();
if l.layout.abi.is_signed() {
// For signed ints the saturated value depends on the sign of the first
// term since the sign of the second term can be inferred from this and
// the fact that the operation has overflowed (if either is 0 no
// overflow can occur)
- let first_term: u128 = l.to_scalar().to_bits(l.layout.size)?;
- let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
- if first_term_positive {
+ let first_term: i128 = l.to_scalar().to_int(l.layout.size)?;
+ if first_term >= 0 {
// Negative overflow not possible since the positive first term
// can only increase an (in range) negative term for addition
- // or corresponding negated positive term for subtraction
+ // or corresponding negated positive term for subtraction.
Scalar::from_int(size.signed_int_max(), size)
} else {
- // Positive overflow not possible for similar reason
- // max negative
+ // Positive overflow not possible for similar reason.
Scalar::from_int(size.signed_int_min(), size)
}
} else {
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 7eb73e9b52f6..5461e9c6ad3f 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -867,19 +867,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
}
- pub fn get_ptr_vtable(
+ /// Get the dynamic type of the given vtable pointer.
+ /// If `expected_trait` is `Some`, it must be a vtable for the given trait.
+ pub fn get_ptr_vtable_ty(
&self,
ptr: Pointer>,
- ) -> InterpResult<'tcx, (Ty<'tcx>, Option>)> {
+ expected_trait: Option<&'tcx ty::List>>,
+ ) -> InterpResult<'tcx, Ty<'tcx>> {
trace!("get_ptr_vtable({:?})", ptr);
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
}
- match self.tcx.try_get_global_alloc(alloc_id) {
- Some(GlobalAlloc::VTable(ty, trait_ref)) => Ok((ty, trait_ref)),
- _ => throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset))),
+ let Some(GlobalAlloc::VTable(ty, vtable_trait)) = self.tcx.try_get_global_alloc(alloc_id)
+ else {
+ throw_ub!(InvalidVTablePointer(Pointer::new(alloc_id, offset)))
+ };
+ if let Some(expected_trait) = expected_trait {
+ self.check_vtable_for_type(vtable_trait, expected_trait)?;
}
+ Ok(ty)
}
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index c821c98073d7..a6eef9f5662c 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -437,23 +437,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
};
Ok(ImmTy::from_scalar(res, layout))
}
- _ if layout.ty.is_integral() => {
- let val = val.to_scalar();
- let val = val.to_bits(layout.size)?;
+ ty::Int(..) => {
+ let val = val.to_scalar().to_int(layout.size)?;
let res = match un_op {
- Not => self.truncate(!val, layout), // bitwise negation, then truncate
- Neg => {
- // arithmetic negation
- assert!(layout.abi.is_signed());
- let val = self.sign_extend(val, layout) as i128;
- let res = val.wrapping_neg();
- let res = res as u128;
- // Truncate to target type.
- self.truncate(res, layout)
- }
+ Not => !val,
+ Neg => val.wrapping_neg(),
_ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
};
- Ok(ImmTy::from_uint(res, layout))
+ let res = ScalarInt::truncate_from_int(res, layout.size).0;
+ Ok(ImmTy::from_scalar(res.into(), layout))
+ }
+ ty::Uint(..) => {
+ let val = val.to_scalar().to_uint(layout.size)?;
+ let res = match un_op {
+ Not => !val,
+ _ => span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op),
+ };
+ let res = ScalarInt::truncate_from_uint(res, layout.size).0;
+ Ok(ImmTy::from_scalar(res.into(), layout))
}
ty::RawPtr(..) => {
assert_eq!(un_op, PtrMetadata);
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 046ff34e3d07..08d3165867c1 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -9,7 +9,6 @@ use tracing::{instrument, trace};
use rustc_ast::Mutability;
use rustc_middle::mir;
-use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_middle::{bug, span_bug};
@@ -1018,54 +1017,6 @@ where
let layout = self.layout_of(raw.ty)?;
Ok(self.ptr_to_mplace(ptr.into(), layout))
}
-
- /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
- /// Aso returns the vtable.
- pub(super) fn unpack_dyn_trait(
- &self,
- mplace: &MPlaceTy<'tcx, M::Provenance>,
- expected_trait: &'tcx ty::List>,
- ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, Pointer>)> {
- assert!(
- matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
- "`unpack_dyn_trait` only makes sense on `dyn*` types"
- );
- let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
- let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
- if expected_trait.principal() != vtable_trait {
- throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
- }
- // This is a kind of transmute, from a place with unsized type and metadata to
- // a place with sized type and no metadata.
- let layout = self.layout_of(ty)?;
- let mplace =
- MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout };
- Ok((mplace, vtable))
- }
-
- /// Turn a `dyn* Trait` type into an value with the actual dynamic type.
- /// Also returns the vtable.
- pub(super) fn unpack_dyn_star>(
- &self,
- val: &P,
- expected_trait: &'tcx ty::List>,
- ) -> InterpResult<'tcx, (P, Pointer>)> {
- assert!(
- matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
- "`unpack_dyn_star` only makes sense on `dyn*` types"
- );
- let data = self.project_field(val, 0)?;
- let vtable = self.project_field(val, 1)?;
- let vtable = self.read_pointer(&vtable.to_op(self)?)?;
- let (ty, vtable_trait) = self.get_ptr_vtable(vtable)?;
- if expected_trait.principal() != vtable_trait {
- throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
- }
- // `data` is already the right thing but has the wrong type. So we transmute it.
- let layout = self.layout_of(ty)?;
- let data = data.transmute(layout, self)?;
- Ok((data, vtable))
- }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index cbfe25ca8df5..8f76a1486795 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use either::Either;
+use rustc_middle::ty::TyCtxt;
use tracing::trace;
use rustc_middle::span_bug;
@@ -827,20 +828,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
};
// Obtain the underlying trait we are working on, and the adjusted receiver argument.
- let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) =
+ let (dyn_trait, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
receiver_place.layout.ty.kind()
{
- let (recv, vptr) = self.unpack_dyn_star(&receiver_place, data)?;
- let (dyn_ty, _dyn_trait) = self.get_ptr_vtable(vptr)?;
+ let recv = self.unpack_dyn_star(&receiver_place, data)?;
- (vptr, dyn_ty, recv.ptr())
+ (data.principal(), recv.layout.ty, recv.ptr())
} else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail = self
.tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
- let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else {
+ let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!(
self.cur_span(),
"dynamic call on non-`dyn` type {}",
@@ -851,25 +851,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Get the required information from the vtable.
let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
- let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
- if dyn_trait != data.principal() {
- throw_ub!(InvalidVTableTrait {
- expected_trait: data,
- vtable_trait: dyn_trait,
- });
- }
+ let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?;
// It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer.
- (vptr, dyn_ty, receiver_place.ptr())
+ (receiver_trait.principal(), dyn_ty, receiver_place.ptr())
};
// Now determine the actual method to call. We can do that in two different ways and
// compare them to ensure everything fits.
- let Some(ty::VtblEntry::Method(fn_inst)) =
- self.get_vtable_entries(vptr)?.get(idx).copied()
- else {
+ let vtable_entries = if let Some(dyn_trait) = dyn_trait {
+ let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty);
+ let trait_ref = self.tcx.erase_regions(trait_ref);
+ self.tcx.vtable_entries(trait_ref)
+ } else {
+ TyCtxt::COMMON_VTABLE_ENTRIES
+ };
+ let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
};
@@ -898,7 +897,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
args[0] = FnArg::Copy(
ImmTy::from_immediate(
- Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
+ Scalar::from_maybe_pointer(adjusted_recv, self).into(),
self.layout_of(receiver_ty)?,
)
.into(),
@@ -974,11 +973,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let place = match place.layout.ty.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
// Dropping a trait object. Need to find actual drop fn.
- self.unpack_dyn_trait(&place, data)?.0
+ self.unpack_dyn_trait(&place, data)?
}
ty::Dynamic(data, _, ty::DynStar) => {
// Dropping a `dyn*`. Need to find actual drop fn.
- self.unpack_dyn_star(&place, data)?.0
+ self.unpack_dyn_star(&place, data)?
}
_ => {
debug_assert_eq!(
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 244a6ba48a4d..bd2c65194218 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,11 +1,14 @@
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::interpret::{InterpResult, Pointer};
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Align, Size};
+use rustc_trait_selection::traits::ObligationCtxt;
use tracing::trace;
use super::util::ensure_monomorphic_enough;
-use super::{InterpCx, Machine};
+use super::{throw_ub, InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable};
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@@ -33,28 +36,90 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Ok(vtable_ptr.into())
}
- /// Returns a high-level representation of the entries of the given vtable.
- pub fn get_vtable_entries(
- &self,
- vtable: Pointer >,
- ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
- let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
- Ok(if let Some(poly_trait_ref) = poly_trait_ref {
- let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
- let trait_ref = self.tcx.erase_regions(trait_ref);
- self.tcx.vtable_entries(trait_ref)
- } else {
- TyCtxt::COMMON_VTABLE_ENTRIES
- })
- }
-
pub fn get_vtable_size_and_align(
&self,
vtable: Pointer >,
+ expected_trait: Option<&'tcx ty::List>>,
) -> InterpResult<'tcx, (Size, Align)> {
- let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
+ let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
let layout = self.layout_of(ty)?;
assert!(layout.is_sized(), "there are no vtables for unsized types");
Ok((layout.size, layout.align.abi))
}
+
+ /// Check that the given vtable trait is valid for a pointer/reference/place with the given
+ /// expected trait type.
+ pub(super) fn check_vtable_for_type(
+ &self,
+ vtable_trait: Option>,
+ expected_trait: &'tcx ty::List>,
+ ) -> InterpResult<'tcx> {
+ // Fast path: if they are equal, it's all fine.
+ if expected_trait.principal() == vtable_trait {
+ return Ok(());
+ }
+ if let (Some(expected_trait), Some(vtable_trait)) =
+ (expected_trait.principal(), vtable_trait)
+ {
+ // Slow path: spin up an inference context to check if these traits are sufficiently equal.
+ let infcx = self.tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
+ let cause = ObligationCause::dummy_with_span(self.cur_span());
+ // equate the two trait refs after normalization
+ let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait);
+ let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait);
+ if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() {
+ if ocx.select_all_or_error().is_empty() {
+ // All good.
+ return Ok(());
+ }
+ }
+ }
+ throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
+ }
+
+ /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
+ pub(super) fn unpack_dyn_trait(
+ &self,
+ mplace: &MPlaceTy<'tcx, M::Provenance>,
+ expected_trait: &'tcx ty::List>,
+ ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+ assert!(
+ matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
+ "`unpack_dyn_trait` only makes sense on `dyn*` types"
+ );
+ let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
+ let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
+ // This is a kind of transmute, from a place with unsized type and metadata to
+ // a place with sized type and no metadata.
+ let layout = self.layout_of(ty)?;
+ let mplace = mplace.offset_with_meta(
+ Size::ZERO,
+ OffsetMode::Wrapping,
+ MemPlaceMeta::None,
+ layout,
+ self,
+ )?;
+ Ok(mplace)
+ }
+
+ /// Turn a `dyn* Trait` type into an value with the actual dynamic type.
+ pub(super) fn unpack_dyn_star>(
+ &self,
+ val: &P,
+ expected_trait: &'tcx ty::List>,
+ ) -> InterpResult<'tcx, P> {
+ assert!(
+ matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+ "`unpack_dyn_star` only makes sense on `dyn*` types"
+ );
+ let data = self.project_field(val, 0)?;
+ let vtable = self.project_field(val, 1)?;
+ let vtable = self.read_pointer(&vtable.to_op(self)?)?;
+ let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
+ // `data` is already the right thing but has the wrong type. So we transmute it.
+ let layout = self.layout_of(ty)?;
+ let data = data.transmute(layout, self)?;
+ Ok(data)
+ }
}
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index f532f6bbe371..6f75bc2af4ec 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -343,20 +343,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
match tail.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
- // Make sure it is a genuine vtable pointer.
- let (_dyn_ty, dyn_trait) = try_validation!(
- self.ecx.get_ptr_vtable(vtable),
+ // Make sure it is a genuine vtable pointer for the right trait.
+ try_validation!(
+ self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
self.path,
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
- InvalidVTablePtr { value: format!("{vtable}") }
+ InvalidVTablePtr { value: format!("{vtable}") },
+ Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
+ InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
+ },
);
- // Make sure it is for the right trait.
- if dyn_trait != data.principal() {
- throw_validation_failure!(
- self.path,
- InvalidMetaWrongTrait { expected_trait: data, vtable_trait: dyn_trait }
- );
- }
}
ty::Slice(..) | ty::Str => {
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index b812e89854b2..71c057e549b4 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -95,7 +95,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// unsized values are never immediate, so we can assert_mem_place
let op = v.to_op(self.ecx())?;
let dest = op.assert_mem_place();
- let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?.0;
+ let inner_mplace = self.ecx().unpack_dyn_trait(&dest, data)?;
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
// recurse with the inner type
return self.visit_field(v, 0, &inner_mplace.into());
@@ -104,7 +104,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// DynStar types. Very different from a dyn type (but strangely part of the
// same variant in `TyKind`): These are pairs where the 2nd component is the
// vtable, and the first component is the data (which must be ptr-sized).
- let data = self.ecx().unpack_dyn_star(v, data)?.0;
+ let data = self.ecx().unpack_dyn_star(v, data)?;
return self.visit_field(v, 0, &data);
}
// Slices do not need special handling here: they have `Array` field
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 3a7c87c1cad9..45ea3ec08f8f 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,18 +1,20 @@
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
+#![feature(if_let_guard)]
#![feature(let_chains)]
+#![feature(never_type)]
+#![feature(rustdoc_internals)]
#![feature(slice_ptr_get)]
#![feature(strict_provenance)]
-#![feature(never_type)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
-#![feature(if_let_guard)]
+// tidy-alphabetical-end
pub mod check_consts;
pub mod const_eval;
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 7f36e4ca16df..8b96b36a8512 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -4,54 +4,121 @@
//! node in the graph. This uses [Tarjan's algorithm](
//! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
//! that completes in *O*(*n*) time.
+//! Optionally, also annotate the SCC nodes with some commutative data.
+//! Typical examples would include: minimum element in SCC, maximum element
+//! reachable from it, etc.
use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, NumEdges, Successors};
use rustc_index::{Idx, IndexSlice, IndexVec};
+use std::fmt::Debug;
use std::ops::Range;
use tracing::{debug, instrument};
#[cfg(test)]
mod tests;
+/// An annotation for an SCC. This can be a representative,
+/// the max/min element of the SCC, or all of the above.
+///
+/// Concretely, the both merge operations must commute, e.g. where `merge`
+/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)`
+///
+/// In general, what you want is probably always min/max according
+/// to some ordering, potentially with side constraints (min x such
+/// that P holds).
+pub trait Annotation: Debug + Copy {
+ /// Merge two existing annotations into one during
+ /// path compression.o
+ fn merge_scc(self, other: Self) -> Self;
+
+ /// Merge a successor into this annotation.
+ fn merge_reached(self, other: Self) -> Self;
+
+ fn update_scc(&mut self, other: Self) {
+ *self = self.merge_scc(other)
+ }
+
+ fn update_reachable(&mut self, other: Self) {
+ *self = self.merge_reached(other)
+ }
+}
+
+/// The empty annotation, which does nothing.
+impl Annotation for () {
+ fn merge_reached(self, _other: Self) -> Self {
+ ()
+ }
+ fn merge_scc(self, _other: Self) -> Self {
+ ()
+ }
+}
+
/// Strongly connected components (SCC) of a graph. The type `N` is
/// the index type for the graph nodes and `S` is the index type for
/// the SCCs. We can map from each node to the SCC that it
/// participates in, and we also have the successors of each SCC.
-pub struct Sccs {
+pub struct Sccs {
/// For each node, what is the SCC index of the SCC to which it
/// belongs.
scc_indices: IndexVec,
- /// Data about each SCC.
- scc_data: SccData,
+ /// Data about all the SCCs.
+ scc_data: SccData,
}
-pub struct SccData {
- /// For each SCC, the range of `all_successors` where its
+/// Information about an invidividual SCC node.
+struct SccDetails {
+ /// For this SCC, the range of `all_successors` where its
/// successors can be found.
- ranges: IndexVec>,
+ range: Range,
+
+ /// User-specified metadata about the SCC.
+ annotation: A,
+}
+
+// The name of this struct should discourage you from making it public and leaking
+// its representation. This message was left here by one who came before you,
+// who learnt the hard way that making even small changes in representation
+// is difficult when it's publicly inspectable.
+//
+// Obey the law of Demeter!
+struct SccData {
+ /// Maps SCC indices to their metadata, including
+ /// offsets into `all_successors`.
+ scc_details: IndexVec>,
/// Contains the successors for all the Sccs, concatenated. The
/// range of indices corresponding to a given SCC is found in its
- /// SccData.
+ /// `scc_details.range`.
all_successors: Vec,
}
-impl Sccs {
+impl Sccs {
+ /// Compute SCCs without annotations.
pub fn new(graph: &impl Successors) -> Self {
- SccsConstruction::construct(graph)
+ Self::new_with_annotation(graph, |_| ())
+ }
+}
+
+impl Sccs {
+ /// Compute SCCs and annotate them with a user-supplied annotation
+ pub fn new_with_annotation A>(
+ graph: &impl Successors,
+ to_annotation: F,
+ ) -> Self {
+ SccsConstruction::construct(graph, to_annotation)
+ }
+
+ pub fn annotation(&self, scc: S) -> A {
+ self.scc_data.annotation(scc)
}
pub fn scc_indices(&self) -> &IndexSlice {
&self.scc_indices
}
- pub fn scc_data(&self) -> &SccData {
- &self.scc_data
- }
-
/// Returns the number of SCCs in the graph.
pub fn num_sccs(&self) -> usize {
self.scc_data.len()
@@ -90,7 +157,7 @@ impl Sccs {
}
}
-impl DirectedGraph for Sccs {
+impl DirectedGraph for Sccs {
type Node = S;
fn num_nodes(&self) -> usize {
@@ -98,43 +165,33 @@ impl DirectedGraph for Sccs {
}
}
-impl NumEdges for Sccs {
+impl NumEdges for Sccs {
fn num_edges(&self) -> usize {
self.scc_data.all_successors.len()
}
}
-impl Successors for Sccs {
+impl Successors for Sccs {
fn successors(&self, node: S) -> impl Iterator- {
self.successors(node).iter().cloned()
}
}
-impl
SccData {
+impl SccData {
/// Number of SCCs,
fn len(&self) -> usize {
- self.ranges.len()
- }
-
- pub fn ranges(&self) -> &IndexSlice> {
- &self.ranges
- }
-
- pub fn all_successors(&self) -> &Vec {
- &self.all_successors
+ self.scc_details.len()
}
/// Returns the successors of the given SCC.
fn successors(&self, scc: S) -> &[S] {
- // Annoyingly, `range` does not implement `Copy`, so we have
- // to do `range.start..range.end`:
- let range = &self.ranges[scc];
- &self.all_successors[range.start..range.end]
+ &self.all_successors[self.scc_details[scc].range.clone()]
}
/// Creates a new SCC with `successors` as its successors and
+ /// the maximum weight of its internal nodes `scc_max_weight` and
/// returns the resulting index.
- fn create_scc(&mut self, successors: impl IntoIterator- ) -> S {
+ fn create_scc(&mut self, successors: impl IntoIterator
- , annotation: A) -> S {
// Store the successors on `scc_successors_vec`, remembering
// the range of indices.
let all_successors_start = self.all_successors.len();
@@ -142,22 +199,35 @@ impl
SccData {
let all_successors_end = self.all_successors.len();
debug!(
- "create_scc({:?}) successors={:?}",
- self.ranges.len(),
+ "create_scc({:?}) successors={:?}, annotation={:?}",
+ self.len(),
&self.all_successors[all_successors_start..all_successors_end],
+ annotation
);
- self.ranges.push(all_successors_start..all_successors_end)
+ let range = all_successors_start..all_successors_end;
+ let metadata = SccDetails { range, annotation };
+ self.scc_details.push(metadata)
+ }
+
+ fn annotation(&self, scc: S) -> A {
+ self.scc_details[scc].annotation
}
}
-struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> {
+struct SccsConstruction<'c, G, S, A, F>
+where
+ G: DirectedGraph + Successors,
+ S: Idx,
+ A: Annotation,
+ F: Fn(G::Node) -> A,
+{
graph: &'c G,
/// The state of each node; used during walk to record the stack
/// and after walk to record what cycle each node ended up being
/// in.
- node_states: IndexVec>,
+ node_states: IndexVec>,
/// The stack of nodes that we are visiting as part of the DFS.
node_stack: Vec,
@@ -174,26 +244,34 @@ struct SccsConstruction<'c, G: DirectedGraph + Successors, S: Idx> {
/// around between successors to amortize memory allocation costs.
duplicate_set: FxHashSet,
- scc_data: SccData,
+ scc_data: SccData,
+
+ /// A function that constructs an initial SCC annotation
+ /// out of a single node.
+ to_annotation: F,
}
#[derive(Copy, Clone, Debug)]
-enum NodeState {
+enum NodeState {
/// This node has not yet been visited as part of the DFS.
///
/// After SCC construction is complete, this state ought to be
/// impossible.
NotVisited,
- /// This node is currently being walk as part of our DFS. It is on
- /// the stack at the depth `depth`.
+ /// This node is currently being walked as part of our DFS. It is on
+ /// the stack at the depth `depth` and its current annotation is
+ /// `annotation`.
///
/// After SCC construction is complete, this state ought to be
/// impossible.
- BeingVisited { depth: usize },
+ BeingVisited { depth: usize, annotation: A },
- /// Indicates that this node is a member of the given cycle.
- InCycle { scc_index: S },
+ /// Indicates that this node is a member of the given cycle where
+ /// the merged annotation is `annotation`.
+ /// Note that an SCC can have several cycles, so its final annotation
+ /// is the merged value of all its member annotations.
+ InCycle { scc_index: S, annotation: A },
/// Indicates that this node is a member of whatever cycle
/// `parent` is a member of. This state is transient: whenever we
@@ -203,16 +281,27 @@ enum NodeState {
InCycleWith { parent: N },
}
+/// The state of walking a given node.
#[derive(Copy, Clone, Debug)]
-enum WalkReturn {
- Cycle { min_depth: usize },
- Complete { scc_index: S },
+enum WalkReturn {
+ /// The walk found a cycle, but the entire component is not known to have
+ /// been fully walked yet. We only know the minimum depth of this
+ /// component in a minimum spanning tree of the graph. This component
+ /// is tentatively represented by the state of the first node of this
+ /// cycle we met, which is at `min_depth`.
+ Cycle { min_depth: usize, annotation: A },
+ /// The SCC and everything reachable from it have been fully walked.
+ /// At this point we know what is inside the SCC as we have visited every
+ /// node reachable from it. The SCC can now be fully represented by its ID.
+ Complete { scc_index: S, annotation: A },
}
-impl<'c, G, S> SccsConstruction<'c, G, S>
+impl<'c, G, S, A, F> SccsConstruction<'c, G, S, A, F>
where
G: DirectedGraph + Successors,
S: Idx,
+ F: Fn(G::Node) -> A,
+ A: Annotation,
{
/// Identifies SCCs in the graph `G` and computes the resulting
/// DAG. This uses a variant of [Tarjan's
@@ -225,8 +314,10 @@ where
/// D' (i.e., D' < D), we know that N, N', and all nodes in
/// between them on the stack are part of an SCC.
///
+ /// Additionally, we keep track of a current annotation of the SCC.
+ ///
/// [wikipedia]: https://bit.ly/2EZIx84
- fn construct(graph: &'c G) -> Sccs {
+ fn construct(graph: &'c G, to_annotation: F) -> Sccs {
let num_nodes = graph.num_nodes();
let mut this = Self {
@@ -234,15 +325,16 @@ where
node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes),
node_stack: Vec::with_capacity(num_nodes),
successors_stack: Vec::new(),
- scc_data: SccData { ranges: IndexVec::new(), all_successors: Vec::new() },
+ scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() },
duplicate_set: FxHashSet::default(),
+ to_annotation,
};
let scc_indices = (0..num_nodes)
.map(G::Node::new)
.map(|node| match this.start_walk_from(node) {
- WalkReturn::Complete { scc_index } => scc_index,
- WalkReturn::Cycle { min_depth } => {
+ WalkReturn::Complete { scc_index, .. } => scc_index,
+ WalkReturn::Cycle { min_depth, .. } => {
panic!("`start_walk_node({node:?})` returned cycle with depth {min_depth:?}")
}
})
@@ -251,12 +343,8 @@ where
Sccs { scc_indices, scc_data: this.scc_data }
}
- fn start_walk_from(&mut self, node: G::Node) -> WalkReturn {
- if let Some(result) = self.inspect_node(node) {
- result
- } else {
- self.walk_unvisited_node(node)
- }
+ fn start_walk_from(&mut self, node: G::Node) -> WalkReturn {
+ self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node))
}
/// Inspect a node during the DFS. We first examine its current
@@ -271,11 +359,15 @@ where
/// Otherwise, we are looking at a node that has already been
/// completely visited. We therefore return `WalkReturn::Complete`
/// with its associated SCC index.
- fn inspect_node(&mut self, node: G::Node) -> Option> {
+ fn inspect_node(&mut self, node: G::Node) -> Option> {
Some(match self.find_state(node) {
- NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index },
+ NodeState::InCycle { scc_index, annotation } => {
+ WalkReturn::Complete { scc_index, annotation }
+ }
- NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth },
+ NodeState::BeingVisited { depth: min_depth, annotation } => {
+ WalkReturn::Cycle { min_depth, annotation }
+ }
NodeState::NotVisited => return None,
@@ -290,7 +382,7 @@ where
/// of `r2` (and updates `r` to reflect current result). This is
/// basically the "find" part of a standard union-find algorithm
/// (with path compression).
- fn find_state(&mut self, mut node: G::Node) -> NodeState {
+ fn find_state(&mut self, mut node: G::Node) -> NodeState {
// To avoid recursion we temporarily reuse the `parent` of each
// InCycleWith link to encode a downwards link while compressing
// the path. After we have found the root or deepest node being
@@ -306,24 +398,40 @@ where
// found the initial self-loop.
let mut previous_node = node;
- // Ultimately assigned by the parent when following
+ // Ultimately propagated to all the transitive parents when following
// `InCycleWith` upwards.
- let node_state = loop {
- debug!("find_state(r = {:?} in state {:?})", node, self.node_states[node]);
- match self.node_states[node] {
- NodeState::InCycle { scc_index } => break NodeState::InCycle { scc_index },
- NodeState::BeingVisited { depth } => break NodeState::BeingVisited { depth },
- NodeState::NotVisited => break NodeState::NotVisited,
- NodeState::InCycleWith { parent } => {
- // We test this, to be extremely sure that we never
- // ever break our termination condition for the
- // reverse iteration loop.
- assert!(node != parent, "Node can not be in cycle with itself");
- // Store the previous node as an inverted list link
- self.node_states[node] = NodeState::InCycleWith { parent: previous_node };
- // Update to parent node.
- previous_node = node;
- node = parent;
+ // This loop performs the downward link encoding mentioned above. Details below!
+ // Note that there are two different states being assigned: the root state, and
+ // a potentially derived version of the root state for non-root nodes in the chain.
+ let (root_state, assigned_state) = {
+ loop {
+ debug!("find_state(r = {node:?} in state {:?})", self.node_states[node]);
+ match self.node_states[node] {
+ // This must have been the first and only state since it is unexplored*;
+ // no update needed! * Unless there is a bug :')
+ s @ NodeState::NotVisited => return s,
+ // We are in a completely discovered SCC; every node on our path is in that SCC:
+ s @ NodeState::InCycle { .. } => break (s, s),
+ // The Interesting Third Base Case: we are a path back to a root node
+ // still being explored. Now we need that node to keep its state and
+ // every other node to be recorded as being in whatever component that
+ // ends up in.
+ s @ NodeState::BeingVisited { depth, .. } => {
+ break (s, NodeState::InCycleWith { parent: self.node_stack[depth] });
+ }
+ // We are not at the head of a path; keep compressing it!
+ NodeState::InCycleWith { parent } => {
+ // We test this, to be extremely sure that we never
+ // ever break our termination condition for the
+ // reverse iteration loop.
+ assert!(node != parent, "Node can not be in cycle with itself");
+
+ // Store the previous node as an inverted list link
+ self.node_states[node] = NodeState::InCycleWith { parent: previous_node };
+ // Update to parent node.
+ previous_node = node;
+ node = parent;
+ }
}
}
};
@@ -365,10 +473,14 @@ where
// Move backwards until we found the node where we started. We
// will know when we hit the state where previous_node == node.
loop {
- // Back at the beginning, we can return.
+ // Back at the beginning, we can return. Note that we return the root state.
+ // This is becuse for components being explored, we would otherwise get a
+ // `node_state[n] = InCycleWith{ parent: n }` and that's wrong.
if previous_node == node {
- return node_state;
+ return root_state;
}
+ debug!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}");
+
// Update to previous node in the link.
match self.node_states[previous_node] {
NodeState::InCycleWith { parent: previous } => {
@@ -376,34 +488,14 @@ where
previous_node = previous;
}
// Only InCycleWith nodes were added to the reverse linked list.
- other => panic!("Invalid previous link while compressing cycle: {other:?}"),
+ other => unreachable!("Invalid previous link while compressing cycle: {other:?}"),
}
- debug!("find_state: parent_state = {:?}", node_state);
-
- // Update the node state from the parent state. The assigned
- // state is actually a loop invariant but it will only be
- // evaluated if there is at least one backlink to follow.
- // Fully trusting llvm here to find this loop optimization.
- match node_state {
- // Path compression, make current node point to the same root.
- NodeState::InCycle { .. } => {
- self.node_states[node] = node_state;
- }
- // Still visiting nodes, compress to cycle to the node
- // at that depth.
- NodeState::BeingVisited { depth } => {
- self.node_states[node] =
- NodeState::InCycleWith { parent: self.node_stack[depth] };
- }
- // These are never allowed as parent nodes. InCycleWith
- // should have been followed to a real parent and
- // NotVisited can not be part of a cycle since it should
- // have instead gotten explored.
- NodeState::NotVisited | NodeState::InCycleWith { .. } => {
- panic!("invalid parent state: {node_state:?}")
- }
- }
+ // Update the node state to the (potentially derived) state.
+ // If the root is still being explored, this is
+ // `InCycleWith{ parent: }`, otherwise
+ // `assigned_state == root_state`.
+ self.node_states[node] = assigned_state;
}
}
@@ -413,30 +505,36 @@ where
/// caller decide avoids mutual recursion between the two methods and allows
/// us to maintain an allocated stack for nodes on the path between calls.
#[instrument(skip(self, initial), level = "debug")]
- fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn {
- struct VisitingNodeFrame {
+ fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn {
+ debug!("Walk unvisited node: {initial:?}");
+ struct VisitingNodeFrame {
node: G::Node,
- iter: Option,
+ successors: Option,
depth: usize,
min_depth: usize,
successors_len: usize,
min_cycle_root: G::Node,
successor_node: G::Node,
+ /// The annotation for the SCC starting in `node`. It may or may
+ /// not contain other nodes.
+ current_component_annotation: A,
}
// Move the stack to a local variable. We want to utilize the existing allocation and
// mutably borrow it without borrowing self at the same time.
let mut successors_stack = core::mem::take(&mut self.successors_stack);
+
debug_assert_eq!(successors_stack.len(), 0);
- let mut stack: Vec> = vec![VisitingNodeFrame {
+ let mut stack: Vec> = vec![VisitingNodeFrame {
node: initial,
depth: 0,
min_depth: 0,
- iter: None,
+ successors: None,
successors_len: 0,
min_cycle_root: initial,
successor_node: initial,
+ current_component_annotation: (self.to_annotation)(initial),
}];
let mut return_value = None;
@@ -445,18 +543,26 @@ where
let VisitingNodeFrame {
node,
depth,
- iter,
+ successors,
successors_len,
min_depth,
min_cycle_root,
successor_node,
+ current_component_annotation,
} = frame;
-
let node = *node;
let depth = *depth;
- let successors = match iter {
- Some(iter) => iter,
+ // node is definitely in the current component, add it to the annotation.
+ if node != initial {
+ current_component_annotation.update_scc((self.to_annotation)(node));
+ }
+ debug!(
+ "Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}"
+ );
+
+ let successors = match successors {
+ Some(successors) => successors,
None => {
// This None marks that we still have the initialize this node's frame.
debug!(?depth, ?node);
@@ -464,7 +570,10 @@ where
debug_assert!(matches!(self.node_states[node], NodeState::NotVisited));
// Push `node` onto the stack.
- self.node_states[node] = NodeState::BeingVisited { depth };
+ self.node_states[node] = NodeState::BeingVisited {
+ depth,
+ annotation: *current_component_annotation,
+ };
self.node_stack.push(node);
// Walk each successor of the node, looking to see if any of
@@ -472,11 +581,11 @@ where
// so, that means they can also reach us.
*successors_len = successors_stack.len();
// Set and return a reference, this is currently empty.
- iter.get_or_insert(self.graph.successors(node))
+ successors.get_or_insert(self.graph.successors(node))
}
};
- // Now that iter is initialized, this is a constant for this frame.
+ // Now that the successors iterator is initialized, this is a constant for this frame.
let successors_len = *successors_len;
// Construct iterators for the nodes and walk results. There are two cases:
@@ -489,10 +598,17 @@ where
debug!(?node, ?successor_node);
(successor_node, self.inspect_node(successor_node))
});
-
for (successor_node, walk) in returned_walk.chain(successor_walk) {
match walk {
- Some(WalkReturn::Cycle { min_depth: successor_min_depth }) => {
+ // The starting node `node` leads to a cycle whose earliest node,
+ // `successor_node`, is at `min_depth`. There may be more cycles.
+ Some(WalkReturn::Cycle {
+ min_depth: successor_min_depth,
+ annotation: successor_annotation,
+ }) => {
+ debug!(
+ "Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}"
+ );
// Track the minimum depth we can reach.
assert!(successor_min_depth <= depth);
if successor_min_depth < *min_depth {
@@ -500,41 +616,56 @@ where
*min_depth = successor_min_depth;
*min_cycle_root = successor_node;
}
+ current_component_annotation.update_scc(successor_annotation);
}
-
- Some(WalkReturn::Complete { scc_index: successor_scc_index }) => {
+ // The starting node `node` is succeeded by a fully identified SCC
+ // which is now added to the set under `scc_index`.
+ Some(WalkReturn::Complete {
+ scc_index: successor_scc_index,
+ annotation: successor_annotation,
+ }) => {
+ debug!(
+ "Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}"
+ );
// Push the completed SCC indices onto
// the `successors_stack` for later.
debug!(?node, ?successor_scc_index);
successors_stack.push(successor_scc_index);
+ current_component_annotation.update_reachable(successor_annotation);
}
-
+ // `node` has no more (direct) successors; search recursively.
None => {
let depth = depth + 1;
+ debug!("Recursing down into {successor_node:?} at depth {depth:?}");
debug!(?depth, ?successor_node);
// Remember which node the return value will come from.
frame.successor_node = successor_node;
- // Start a new stack frame the step into it.
+ // Start a new stack frame, then step into it.
stack.push(VisitingNodeFrame {
node: successor_node,
depth,
- iter: None,
+ successors: None,
successors_len: 0,
min_depth: depth,
min_cycle_root: successor_node,
successor_node,
+ current_component_annotation: (self.to_annotation)(successor_node),
});
continue 'recurse;
}
}
}
+ debug!("Finished walk from {node:?} with annotation: {current_component_annotation:?}");
+
// Completed walk, remove `node` from the stack.
let r = self.node_stack.pop();
debug_assert_eq!(r, Some(node));
// Remove the frame, it's done.
let frame = stack.pop().unwrap();
+ let current_component_annotation = frame.current_component_annotation;
+ debug_assert_eq!(frame.node, node);
// If `min_depth == depth`, then we are the root of the
// cycle: we can't reach anyone further down the stack.
@@ -543,6 +674,8 @@ where
// We return one frame at a time so there can't be another return value.
debug_assert!(return_value.is_none());
return_value = Some(if frame.min_depth == depth {
+ // We are at the head of the component.
+
// Note that successor stack may have duplicates, so we
// want to remove those:
let deduplicated_successors = {
@@ -552,15 +685,25 @@ where
.drain(successors_len..)
.filter(move |&i| duplicate_set.insert(i))
};
- let scc_index = self.scc_data.create_scc(deduplicated_successors);
- self.node_states[node] = NodeState::InCycle { scc_index };
- WalkReturn::Complete { scc_index }
+
+ debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node);
+
+ let scc_index =
+ self.scc_data.create_scc(deduplicated_successors, current_component_annotation);
+
+ self.node_states[node] =
+ NodeState::InCycle { scc_index, annotation: current_component_annotation };
+
+ WalkReturn::Complete { scc_index, annotation: current_component_annotation }
} else {
// We are not the head of the cycle. Return back to our
// caller. They will take ownership of the
// `self.successors` data that we pushed.
self.node_states[node] = NodeState::InCycleWith { parent: frame.min_cycle_root };
- WalkReturn::Cycle { min_depth: frame.min_depth }
+ WalkReturn::Cycle {
+ min_depth: frame.min_depth,
+ annotation: current_component_annotation,
+ }
});
}
diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs
index 513df666d0da..373f87bfdbcf 100644
--- a/compiler/rustc_data_structures/src/graph/scc/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs
@@ -3,10 +3,53 @@ extern crate test;
use super::*;
use crate::graph::tests::TestGraph;
+#[derive(Copy, Clone, Debug)]
+struct MaxReached(usize);
+type UsizeSccs = Sccs;
+type MaxReachedSccs = Sccs;
+
+impl Annotation for MaxReached {
+ fn merge_scc(self, other: Self) -> Self {
+ Self(std::cmp::max(other.0, self.0))
+ }
+
+ fn merge_reached(self, other: Self) -> Self {
+ self.merge_scc(other)
+ }
+}
+
+impl PartialEq for MaxReached {
+ fn eq(&self, other: &usize) -> bool {
+ &self.0 == other
+ }
+}
+
+impl MaxReached {
+ fn from_usize(nr: usize) -> Self {
+ Self(nr)
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct MinMaxIn {
+ min: usize,
+ max: usize,
+}
+
+impl Annotation for MinMaxIn {
+ fn merge_scc(self, other: Self) -> Self {
+ Self { min: std::cmp::min(self.min, other.min), max: std::cmp::max(self.max, other.max) }
+ }
+
+ fn merge_reached(self, _other: Self) -> Self {
+ self
+ }
+}
+
#[test]
fn diamond() {
let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 4);
assert_eq!(sccs.num_sccs(), 4);
}
@@ -34,7 +77,7 @@ fn test_big_scc() {
+-- 2 <--+
*/
let graph = TestGraph::new(0, &[(0, 1), (1, 2), (1, 3), (2, 0), (3, 2)]);
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 1);
}
@@ -50,7 +93,7 @@ fn test_three_sccs() {
+-- 2 <--+
*/
let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 1), (3, 2)]);
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 3);
assert_eq!(sccs.scc(0), 1);
assert_eq!(sccs.scc(1), 0);
@@ -106,7 +149,7 @@ fn test_find_state_2() {
// 2 InCycleWith { 1 }
// 3 InCycleWith { 0 }
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 1);
assert_eq!(sccs.scc(0), 0);
assert_eq!(sccs.scc(1), 0);
@@ -130,7 +173,7 @@ fn test_find_state_3() {
*/
let graph =
TestGraph::new(0, &[(0, 1), (0, 4), (1, 2), (1, 3), (2, 1), (3, 0), (4, 2), (5, 2)]);
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 2);
assert_eq!(sccs.scc(0), 0);
assert_eq!(sccs.scc(1), 0);
@@ -165,7 +208,7 @@ fn test_deep_linear() {
nodes.push((i - 1, i));
}
let graph = TestGraph::new(0, nodes.as_slice());
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), NR_NODES);
assert_eq!(sccs.scc(0), NR_NODES - 1);
assert_eq!(sccs.scc(NR_NODES - 1), 0);
@@ -210,7 +253,164 @@ fn bench_sccc(b: &mut test::Bencher) {
graph[21] = (7, 4);
let graph = TestGraph::new(0, &graph[..]);
b.iter(|| {
- let sccs: Sccs<_, usize> = Sccs::new(&graph);
+ let sccs: UsizeSccs = Sccs::new(&graph);
assert_eq!(sccs.num_sccs(), 3);
});
}
+
+#[test]
+fn test_max_self_loop() {
+ let graph = TestGraph::new(0, &[(0, 0)]);
+ let sccs: MaxReachedSccs =
+ Sccs::new_with_annotation(&graph, |n| if n == 0 { MaxReached(17) } else { MaxReached(0) });
+ assert_eq!(sccs.annotation(0), 17);
+}
+
+#[test]
+fn test_max_branch() {
+ let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 4)]);
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
+ assert_eq!(sccs.annotation(sccs.scc(0)), 4);
+ assert_eq!(sccs.annotation(sccs.scc(1)), 3);
+ assert_eq!(sccs.annotation(sccs.scc(2)), 4);
+}
+#[test]
+fn test_single_cycle_max() {
+ let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]);
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
+ assert_eq!(sccs.annotation(sccs.scc(2)), 4);
+ assert_eq!(sccs.annotation(sccs.scc(0)), 4);
+}
+
+#[test]
+fn test_simple_cycle_max() {
+ let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 0)]);
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
+ assert_eq!(sccs.num_sccs(), 1);
+}
+
+#[test]
+fn test_double_cycle_max() {
+ let graph =
+ TestGraph::new(0, &[(0, 1), (1, 2), (1, 4), (2, 3), (2, 4), (3, 5), (4, 1), (5, 4)]);
+ let sccs: MaxReachedSccs =
+ Sccs::new_with_annotation(&graph, |n| if n == 5 { MaxReached(2) } else { MaxReached(1) });
+
+ assert_eq!(sccs.annotation(sccs.scc(0)).0, 2);
+}
+
+#[test]
+fn test_bug_minimised() {
+ let graph = TestGraph::new(0, &[(0, 3), (0, 1), (3, 2), (2, 3), (1, 4), (4, 5), (5, 4)]);
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |n| match n {
+ 3 => MaxReached(1),
+ _ => MaxReached(0),
+ });
+ assert_eq!(sccs.annotation(sccs.scc(2)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(1)), 0);
+ assert_eq!(sccs.annotation(sccs.scc(4)), 0);
+}
+
+#[test]
+fn test_bug_max_leak_minimised() {
+ let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3)]);
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
+ 4 => MaxReached(1),
+ _ => MaxReached(0),
+ });
+
+ assert_eq!(sccs.annotation(sccs.scc(2)), 0);
+ assert_eq!(sccs.annotation(sccs.scc(3)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(0)), 1);
+}
+
+#[test]
+fn test_bug_max_leak() {
+ let graph = TestGraph::new(
+ 8,
+ &[
+ (0, 0),
+ (0, 18),
+ (0, 19),
+ (0, 1),
+ (0, 2),
+ (0, 7),
+ (0, 8),
+ (0, 23),
+ (18, 0),
+ (18, 12),
+ (19, 0),
+ (19, 25),
+ (12, 18),
+ (12, 3),
+ (12, 5),
+ (3, 12),
+ (3, 21),
+ (3, 22),
+ (5, 13),
+ (21, 3),
+ (22, 3),
+ (13, 5),
+ (13, 4),
+ (4, 13),
+ (4, 0),
+ (2, 11),
+ (7, 6),
+ (6, 20),
+ (20, 6),
+ (8, 17),
+ (17, 9),
+ (9, 16),
+ (16, 26),
+ (26, 15),
+ (15, 10),
+ (10, 14),
+ (14, 27),
+ (23, 24),
+ ],
+ );
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
+ 22 => MaxReached(1),
+ 24 => MaxReached(2),
+ 27 => MaxReached(2),
+ _ => MaxReached(0),
+ });
+
+ assert_eq!(sccs.annotation(sccs.scc(2)), 0);
+ assert_eq!(sccs.annotation(sccs.scc(7)), 0);
+ assert_eq!(sccs.annotation(sccs.scc(8)), 2);
+ assert_eq!(sccs.annotation(sccs.scc(23)), 2);
+ assert_eq!(sccs.annotation(sccs.scc(3)), 2);
+ assert_eq!(sccs.annotation(sccs.scc(0)), 2);
+}
+
+#[test]
+fn test_bug_max_zero_stick_shape() {
+ let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 2), (3, 4)]);
+
+ let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
+ 4 => MaxReached(1),
+ _ => MaxReached(0),
+ });
+
+ assert_eq!(sccs.annotation(sccs.scc(0)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(1)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(2)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(3)), 1);
+ assert_eq!(sccs.annotation(sccs.scc(4)), 1);
+}
+
+#[test]
+fn test_min_max_in() {
+ let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3), (3, 5)]);
+ let sccs: Sccs =
+ Sccs::new_with_annotation(&graph, |w| MinMaxIn { min: w, max: w });
+
+ assert_eq!(sccs.annotation(sccs.scc(2)).min, 2);
+ assert_eq!(sccs.annotation(sccs.scc(2)).max, 2);
+ assert_eq!(sccs.annotation(sccs.scc(0)).min, 0);
+ assert_eq!(sccs.annotation(sccs.scc(0)).max, 4);
+ assert_eq!(sccs.annotation(sccs.scc(3)).min, 0);
+ assert_eq!(sccs.annotation(sccs.scc(3)).max, 4);
+ assert_eq!(sccs.annotation(sccs.scc(5)).min, 5);
+}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index d477b86da74e..3883b0736db0 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -146,8 +146,6 @@ pub enum ProcessResult {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct ObligationTreeId(usize);
-type ObligationTreeIdGenerator = impl Iterator- ;
-
pub struct ObligationForest
{
/// The list of obligations. In between calls to [Self::process_obligations],
/// this list only contains nodes in the `Pending` or `Waiting` state.
@@ -310,18 +308,25 @@ pub struct Error {
pub backtrace: Vec,
}
-impl ObligationForest {
- pub fn new() -> ObligationForest {
- ObligationForest {
- nodes: vec![],
- done_cache: Default::default(),
- active_cache: Default::default(),
- reused_node_vec: vec![],
- obligation_tree_id_generator: (0..).map(ObligationTreeId),
- error_cache: Default::default(),
+mod helper {
+ use super::*;
+ pub type ObligationTreeIdGenerator = impl Iterator- ;
+ impl
ObligationForest {
+ pub fn new() -> ObligationForest {
+ ObligationForest {
+ nodes: vec![],
+ done_cache: Default::default(),
+ active_cache: Default::default(),
+ reused_node_vec: vec![],
+ obligation_tree_id_generator: (0..).map(ObligationTreeId),
+ error_cache: Default::default(),
+ }
}
}
+}
+use helper::*;
+impl ObligationForest {
/// Returns the total number of nodes in the forest that have not
/// yet been fully resolved.
pub fn len(&self) -> usize {
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index acd93b0b2a60..a03834c519d5 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1,8 +1,10 @@
// This crate is intentionally empty and a re-export of `rustc_driver_impl` to allow the code in
// `rustc_driver_impl` to be compiled in parallel with other crates.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
pub use rustc_driver_impl::*;
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 93a65290602a..9acff4a0a26c 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -4,16 +4,18 @@
//!
//! This API is completely unstable and subject to change.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
#![feature(decl_macro)]
#![feature(let_chains)]
#![feature(panic_backtrace_config)]
#![feature(panic_update_hook)]
#![feature(result_flattening)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use rustc_ast as ast;
use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
@@ -52,7 +54,7 @@ use std::ffi::OsString;
use std::fmt::Write as _;
use std::fs::{self, File};
use std::io::{self, IsTerminal, Read, Write};
-use std::panic::{self, catch_unwind, PanicInfo};
+use std::panic::{self, catch_unwind, PanicHookInfo};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
use std::str;
@@ -1366,11 +1368,10 @@ pub fn install_ice_hook(
let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
let using_internal_features_hook = using_internal_features.clone();
panic::update_hook(Box::new(
- move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static),
- info: &PanicInfo<'_>| {
+ move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
+ info: &PanicHookInfo<'_>| {
// Lock stderr to prevent interleaving of concurrent panics.
let _guard = io::stderr().lock();
-
// If the error was caused by a broken pipe then this is not a bug.
// Write the error and return immediately. See #98700.
#[cfg(windows)]
@@ -1431,7 +1432,7 @@ pub fn install_ice_hook(
/// When `install_ice_hook` is called, this function will be called as the panic
/// hook.
fn report_ice(
- info: &panic::PanicInfo<'_>,
+ info: &panic::PanicHookInfo<'_>,
bug_report_url: &str,
extra_info: fn(&DiagCtxt),
using_internal_features: &AtomicBool,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md
index bad2b5abfe4d..5e3dcc4aa727 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0792.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0792.md
@@ -39,6 +39,8 @@ type Foo = impl std::fmt::Debug;
fn foo() -> Foo {
5u32
}
+
+fn main() {}
```
This means that no matter the generic parameter to `foo`,
@@ -57,4 +59,6 @@ type Foo = impl Debug;
fn foo() -> Foo {
Vec::::new()
}
+
+fn main() {}
```
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index f4a33a05c1b3..d13d5e1bca21 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -1,10 +1,12 @@
//! This library is used to gather all error codes into one place, to make
//! their maintenance easier.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
-#![doc(rust_logo)]
#![deny(rustdoc::invalid_codeblock_attributes)]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
// This higher-order macro defines the error codes that are in use. It is used
// in the `rustc_errors` crate. Removed error codes are listed in the comment
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 4eb4e77d69cb..26a68454ab3b 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -1,8 +1,10 @@
-#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![feature(rustc_attrs)]
-#![feature(type_alias_impl_trait)]
+// tidy-alphabetical-start
#![allow(internal_features)]
+#![doc(rust_logo)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![feature(type_alias_impl_trait)]
+// tidy-alphabetical-end
use fluent_bundle::FluentResource;
use fluent_syntax::parser::ParserError;
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 718129c5b6e2..2e150f7bb279 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -157,7 +157,7 @@ expand_unsupported_key_value =
key-value macro attributes are not supported
expand_var_still_repeating =
- variable '{$ident}' is still repeating at this depth
+ variable `{$ident}` is still repeating at this depth
expand_wrong_fragment_kind =
non-{$kind} macro in {$kind} position: {$name}
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 7c76392858cd..ef141c7c25e5 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -139,7 +139,7 @@ declare_features! (
/// Allows `crate` in paths.
(accepted, crate_in_paths, "1.30.0", Some(45477)),
/// Allows users to provide classes for fenced code block using `class:classname`.
- (accepted, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483)),
+ (accepted, custom_code_classes_in_docs, "1.80.0", Some(79483)),
/// Allows using `#[debugger_visualizer]` attribute.
(accepted, debugger_visualizer, "1.71.0", Some(95939)),
/// Allows rustc to inject a default alloc_error_handler
@@ -165,7 +165,7 @@ declare_features! (
/// Allows using `dyn Trait` as a syntax for trait objects.
(accepted, dyn_trait, "1.27.0", Some(44662)),
/// Allows `X..Y` patterns.
- (accepted, exclusive_range_pattern, "CURRENT_RUSTC_VERSION", Some(37854)),
+ (accepted, exclusive_range_pattern, "1.80.0", Some(37854)),
/// Allows integer match exhaustiveness checking (RFC 2591).
(accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)),
/// Allows explicit generic arguments specification with `impl Trait` present.
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 9db9073e2f02..fb3b7c0a1272 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,9 +11,11 @@
//! even if it is stabilized or removed, *do not remove it*. Instead, move the
//! symbol to the `accepted` or `removed` modules respectively.
+// tidy-alphabetical-start
#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
mod accepted;
mod builtin_attrs;
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 2410019868a1..2d13f430cfce 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -457,7 +457,7 @@ declare_features! (
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
- (incomplete, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
+ (incomplete, expr_fragment_specifier_2024, "1.80.0", Some(123742)),
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
/// for functions with varargs.
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
@@ -488,7 +488,7 @@ declare_features! (
/// Allows generic parameters and where-clauses on free & associated const items.
(incomplete, generic_const_items, "1.73.0", Some(113521)),
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
- (unstable, global_registration, "CURRENT_RUSTC_VERSION", Some(125119)),
+ (unstable, global_registration, "1.80.0", Some(125119)),
/// Allows using `..=X` as a patterns in slices.
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
/// Allows `if let` guard in match arms.
@@ -581,7 +581,7 @@ declare_features! (
(unstable, repr_simd, "1.4.0", Some(27731)),
/// Allows enums like Result to be used across FFI, if T's niche value can
/// be used to describe E or vise-versa.
- (unstable, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
+ (unstable, result_ffi_guarantees, "1.80.0", Some(110503)),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417)),
/// Allows `extern "rust-cold"`.
@@ -623,9 +623,9 @@ declare_features! (
/// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
/// Allows unsafe attributes.
- (unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)),
+ (unstable, unsafe_attributes, "1.80.0", Some(123757)),
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
- (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
+ (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
/// Allows unsized fn parameters.
(unstable, unsized_fn_params, "1.49.0", Some(48055)),
/// Allows unsized rvalues at arguments and parameters.
diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs
index 2303785f94e6..0a04e6743a8b 100644
--- a/compiler/rustc_fluent_macro/src/lib.rs
+++ b/compiler/rustc_fluent_macro/src/lib.rs
@@ -1,10 +1,12 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::default_hash_types)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
-#![allow(rustc::default_hash_types)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use proc_macro::TokenStream;
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index d376c24cb589..5a9b15204d58 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -1,7 +1,9 @@
+// tidy-alphabetical-start
use std::ffi::CString;
use std::fs;
use std::io;
use std::path::{absolute, Path, PathBuf};
+// tidy-alphabetical-end
// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 43bee5c4be02..c0fe98254f08 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -269,13 +269,15 @@
//!
//! * [DOT language](https://www.graphviz.org/doc/info/lang.html)
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(allow(unused_variables), deny(warnings)))
)]
-#![feature(rustdoc_internals)]
#![doc(rust_logo)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use LabelText::*;
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 87ff39a8294c..042894beec22 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1038,6 +1038,7 @@ pub struct Block<'hir> {
pub hir_id: HirId,
/// Distinguishes between `unsafe { ... }` and `{ ... }`.
pub rules: BlockCheckMode,
+ /// The span includes the curly braces `{` and `}` around the block.
pub span: Span,
/// If true, then there may exist `break 'a` values that aim to
/// break out of this block early.
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 600a0dce03b9..e517c3fd07a1 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -2,13 +2,15 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![feature(variant_count)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
extern crate self as rustc_hir;
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 67959d9dfede..8c740d87e953 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -8,6 +8,10 @@ hir_analysis_assoc_item_constraints_not_allowed_here =
associated item constraints are not allowed here
.label = associated item constraint not allowed here
+hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private
+ .label = private {$kind}
+ .defined_here_label = the {$kind} is defined here
+
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
@@ -460,6 +464,10 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
.note = this item must mention the opaque type in its signature in order to be able to register hidden types
+hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature
+ .note = consider moving the opaque type's declaration and defining uses into a separate module
+ .opaque = this opaque type is in the signature
+
hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
hir_analysis_too_large_static = extern static is too large for the current architecture
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index abdf85ad707b..303fa23dbc1e 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -11,6 +11,7 @@ use rustc_session::lint;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span;
+#[instrument(level = "debug", skip(tcx))]
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
use rustc_hir::*;
@@ -66,7 +67,22 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// FIXME(#43408) always enable this once `lazy_normalization` is
// stable enough and does not need a feature gate anymore.
Node::AnonConst(_) => {
- let parent_def_id = tcx.hir().get_parent_item(hir_id);
+ let parent_did = tcx.parent(def_id.to_def_id());
+
+ // We don't do this unconditionally because the `DefId` parent of an anon const
+ // might be an implicitly created closure during `async fn` desugaring. This would
+ // have the wrong generics.
+ //
+ // i.e. `async fn foo<'a>() { let a = [(); { 1 + 2 }]; bar().await() }`
+ // would implicitly have a closure in its body that would be the parent of
+ // the `{ 1 + 2 }` anon const. This closure's generics is simply a witness
+ // instead of `['a]`.
+ let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) {
+ parent_did
+ } else {
+ tcx.hir().get_parent_item(hir_id).to_def_id()
+ };
+ debug!(?parent_did);
let mut in_param_ty = false;
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
@@ -121,7 +137,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
//
// This has some implications for how we get the predicates available to the anon const
// see `explicit_predicates_of` for more information on this
- let generics = tcx.generics_of(parent_def_id.to_def_id());
+ let generics = tcx.generics_of(parent_did);
let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()];
// In the above example this would be .params[..N#0]
let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
@@ -147,7 +163,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
//
// Note that we do not supply the parent generics when using
// `min_const_generics`.
- Some(parent_def_id.to_def_id())
+ Some(parent_did)
}
} else {
let parent_node = tcx.parent_hir_node(hir_id);
@@ -159,7 +175,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
if constant.hir_id() == hir_id =>
{
- Some(parent_def_id.to_def_id())
+ Some(parent_did)
}
// Exclude `GlobalAsm` here which cannot have generics.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -171,7 +187,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
_ => false,
}) =>
{
- Some(parent_def_id.to_def_id())
+ Some(parent_did)
}
_ => None,
}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 40204961e9c4..3421c8da4e9f 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -169,12 +169,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
predicates.insert((trait_ref.upcast(tcx), tcx.def_span(def_id)));
}
- // Collect the predicates that were written inline by the user on each
- // type parameter (e.g., ``). Also add `ConstArgHasType` predicates
- // for each const parameter.
+ // Add implicit predicates that should be treated as if the user has written them,
+ // including the implicit `T: Sized` for all generic parameters, and `ConstArgHasType`
+ // for const params.
for param in hir_generics.params {
match param.kind {
- // We already dealt with early bound lifetimes above.
GenericParamKind::Lifetime { .. } => (),
GenericParamKind::Type { .. } => {
let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
@@ -204,7 +203,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
trace!(?predicates);
- // Add in the bounds that appear in the where-clause.
+ // Add inline `` bounds and bounds in the where clause.
for predicate in hir_generics.predicates {
match predicate {
hir::WherePredicate::BoundPredicate(bound_pred) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 1bec8c496ad1..2b2f07001d2f 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -8,7 +8,7 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
-use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
+use crate::errors::{TaitForwardCompat, TaitForwardCompat2, TypeOf, UnconstrainedOpaqueType};
pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
@@ -229,13 +229,14 @@ impl TaitConstraintLocator<'_> {
return;
}
+ let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+
let mut constrained = false;
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
continue;
}
constrained = true;
- let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
if !opaque_types_defined_by.contains(&self.def_id) {
self.tcx.dcx().emit_err(TaitForwardCompat {
@@ -259,6 +260,16 @@ impl TaitConstraintLocator<'_> {
if !constrained {
debug!("no constraints in typeck results");
+ if opaque_types_defined_by.contains(&self.def_id) {
+ self.tcx.dcx().emit_err(TaitForwardCompat2 {
+ span: self
+ .tcx
+ .def_ident_span(item_def_id)
+ .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
+ opaque_type_span: self.tcx.def_span(self.def_id),
+ opaque_type: self.tcx.def_path_str(self.def_id),
+ });
+ }
return;
};
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 8a9d4cd4ac70..41dceea2e328 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -55,6 +55,18 @@ pub struct AssocKindMismatchWrapInBracesSugg {
pub hi: Span,
}
+#[derive(Diagnostic)]
+#[diag(hir_analysis_assoc_item_is_private, code = E0624)]
+pub struct AssocItemIsPrivate {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub kind: &'static str,
+ pub name: Ident,
+ #[label(hir_analysis_defined_here_label)]
+ pub defined_here_label: Span,
+}
+
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_item_not_found, code = E0220)]
pub struct AssocItemNotFound<'a> {
@@ -390,6 +402,17 @@ pub struct TaitForwardCompat {
pub item_span: Span,
}
+#[derive(Diagnostic)]
+#[diag(hir_analysis_tait_forward_compat2)]
+#[note]
+pub struct TaitForwardCompat2 {
+ #[primary_span]
+ pub span: Span,
+ #[note(hir_analysis_opaque)]
+ pub opaque_type_span: Span,
+ pub opaque_type: String,
+}
+
pub struct MissingTypeParams {
pub span: Span,
pub def_span: Span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 7f6f57907c28..9a6bc8a7b721 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -294,30 +294,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)?
};
- let (assoc_ident, def_scope) =
- tcx.adjust_ident_and_get_scope(constraint.ident, candidate.def_id(), hir_ref_id);
-
- // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
- // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
- // `assoc_ident` again and again.
- let assoc_item = tcx
- .associated_items(candidate.def_id())
- .filter_by_name_unhygienic(assoc_ident.name)
- .find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
- .expect("missing associated item");
-
- if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
- let reported = tcx
- .dcx()
- .struct_span_err(
- constraint.span,
- format!("{} `{}` is private", assoc_item.kind, constraint.ident),
- )
- .with_span_label(constraint.span, format!("private {}", assoc_item.kind))
- .emit();
- self.set_tainted_by_errors(reported);
- }
- tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), constraint.span, None);
+ let assoc_item = self
+ .probe_assoc_item(
+ constraint.ident,
+ assoc_kind,
+ hir_ref_id,
+ constraint.span,
+ candidate.def_id(),
+ )
+ .expect("failed to find associated item");
duplicates
.entry(assoc_item.def_id)
@@ -404,10 +389,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Create the generic arguments for the associated type or constant by joining the
// parent arguments (the arguments of the trait) and the own arguments (the ones of
// the associated item itself) and construct an alias type using them.
- let alias_ty = candidate.map_bound(|trait_ref| {
- let ident = Ident::new(assoc_item.name, constraint.ident.span);
+ let alias_term = candidate.map_bound(|trait_ref| {
let item_segment = hir::PathSegment {
- ident,
+ ident: constraint.ident,
hir_id: constraint.hir_id,
res: Res::Err,
args: Some(constraint.gen_args),
@@ -426,15 +410,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
});
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
- if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(anon_const) } =
- constraint.kind
- {
- let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
- let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, constraint.hir_id);
+ if let Some(anon_const) = constraint.ct() {
+ let ty = alias_term
+ .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
+ let ty =
+ check_assoc_const_binding_type(tcx, constraint.ident, ty, constraint.hir_id);
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
}
- alias_ty
+ alias_term
};
match constraint.kind {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 7ec64f1feda2..5911d5bb4e1e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1151,8 +1151,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
let trait_did = bound.def_id();
- let assoc_ty_did = self.probe_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
- let ty = self.lower_assoc_ty(span, assoc_ty_did, assoc_segment, bound);
+ let assoc_ty = self
+ .probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
+ .expect("failed to find associated type");
+ let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
if let Some(variant_def_id) = variant_resolution {
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@@ -1168,7 +1170,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
could_refer_to(DefKind::Variant, variant_def_id, "");
- could_refer_to(DefKind::AssocTy, assoc_ty_did, " also");
+ could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
lint.span_suggestion(
span,
@@ -1178,7 +1180,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
});
}
- Ok((ty, DefKind::AssocTy, assoc_ty_did))
+ Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
}
fn probe_inherent_assoc_ty(
@@ -1205,7 +1207,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let candidates: Vec<_> = tcx
.inherent_impls(adt_did)?
.iter()
- .filter_map(|&impl_| Some((impl_, self.probe_assoc_ty_unchecked(name, block, impl_)?)))
+ .filter_map(|&impl_| {
+ let (item, scope) =
+ self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?;
+ Some((impl_, (item.def_id, scope)))
+ })
.collect();
if candidates.is_empty() {
@@ -1249,7 +1255,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
},
)?;
- self.check_assoc_ty(assoc_item, name, def_scope, block, span);
+ self.check_assoc_item(assoc_item, name, def_scope, block, span);
// FIXME(fmease): Currently creating throwaway `parent_args` to please
// `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to
@@ -1336,50 +1342,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
- fn probe_assoc_ty(&self, name: Ident, block: HirId, span: Span, scope: DefId) -> Option {
- let (item, def_scope) = self.probe_assoc_ty_unchecked(name, block, scope)?;
- self.check_assoc_ty(item, name, def_scope, block, span);
+ /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
+ ///
+ /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
+ fn probe_assoc_item(
+ &self,
+ ident: Ident,
+ kind: ty::AssocKind,
+ block: HirId,
+ span: Span,
+ scope: DefId,
+ ) -> Option {
+ let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
+ self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item)
}
- fn probe_assoc_ty_unchecked(
+ /// Given name and kind search for the assoc item in the provided scope
+ /// *without* checking if it's accessible[^1].
+ ///
+ /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
+ fn probe_assoc_item_unchecked(
&self,
- name: Ident,
+ ident: Ident,
+ kind: ty::AssocKind,
block: HirId,
scope: DefId,
- ) -> Option<(DefId, DefId)> {
+ ) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
let tcx = self.tcx();
- let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
+ let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
// `ident` again and again.
- let item = tcx.associated_items(scope).in_definition_order().find(|i| {
- i.kind.namespace() == Namespace::TypeNS
- && i.ident(tcx).normalize_to_macros_2_0() == ident
- })?;
+ let item = tcx
+ .associated_items(scope)
+ .filter_by_name_unhygienic(ident.name)
+ .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
- Some((item.def_id, def_scope))
+ Some((*item, def_scope))
}
- fn check_assoc_ty(&self, item: DefId, name: Ident, def_scope: DefId, block: HirId, span: Span) {
+ /// Check if the given assoc item is accessible in the provided scope wrt. visibility and stability.
+ fn check_assoc_item(
+ &self,
+ item_def_id: DefId,
+ ident: Ident,
+ scope: DefId,
+ block: HirId,
+ span: Span,
+ ) {
let tcx = self.tcx();
- let kind = DefKind::AssocTy;
- if !tcx.visibility(item).is_accessible_from(def_scope, tcx) {
- let kind = tcx.def_kind_descr(kind, item);
- let msg = format!("{kind} `{name}` is private");
- let def_span = tcx.def_span(item);
- let reported = tcx
- .dcx()
- .struct_span_err(span, msg)
- .with_code(E0624)
- .with_span_label(span, format!("private {kind}"))
- .with_span_label(def_span, format!("{kind} defined here"))
- .emit();
+ if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) {
+ let reported = tcx.dcx().emit_err(crate::errors::AssocItemIsPrivate {
+ span,
+ kind: tcx.def_descr(item_def_id),
+ name: ident,
+ defined_here_label: tcx.def_span(item_def_id),
+ });
self.set_tainted_by_errors(reported);
}
- tcx.check_stability(item, Some(block), span, None);
+
+ tcx.check_stability(item_def_id, Some(block), span, None);
}
fn probe_traits_that_match_assoc_ty(
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 8fe81851f932..1927359421d0 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -55,21 +55,23 @@ This API is completely unstable and subject to change.
*/
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::potential_query_instability)]
#![allow(rustc::untranslatable_diagnostic)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
#![feature(control_flow_enum)]
#![feature(if_let_guard)]
#![feature(is_sorted)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
+#![feature(rustdoc_internals)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 6f2febd86b0f..d32d0183c4e4 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1,7 +1,9 @@
//! HIR pretty-printing is layered on top of AST pretty-printing. A number of
//! the definitions in this file have equivalents in `rustc_ast_pretty`.
+// tidy-alphabetical-start
#![recursion_limit = "256"]
+// tidy-alphabetical-end
use rustc_ast as ast;
use rustc_ast::util::parser::{self, AssocOp, Fixity};
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index dbaa6e398c88..e54a07786cd1 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -113,7 +113,7 @@ fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec(
adj: Vec>,
target: Ty<'tcx>,
- obligations: traits::PredicateObligations<'tcx>,
+ obligations: Vec>,
) -> CoerceResult<'tcx> {
Ok(InferOk { value: (adj, target), obligations })
}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 5b27ebe3416a..3321f029c8d8 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1342,14 +1342,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(method)
}
Err(error) => {
- if segment.ident.name != kw::Empty {
- if let Some(err) =
- self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)
- {
- err.emit();
- }
+ if segment.ident.name == kw::Empty {
+ span_bug!(rcvr.span, "empty method name")
+ } else {
+ Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
}
- Err(())
}
};
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 7d6fdc9392ea..5ba67c52ef29 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -18,12 +18,12 @@ use rustc_span::{def_id::LocalDefId, Span};
#[derive(Copy, Clone)]
pub enum DivergingFallbackBehavior {
/// Always fallback to `()` (aka "always spontaneous decay")
- FallbackToUnit,
+ ToUnit,
/// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
- FallbackToNiko,
+ ContextDependent,
/// Always fallback to `!` (which should be equivalent to never falling back + not making
/// never-to-any coercions unless necessary)
- FallbackToNever,
+ ToNever,
/// Don't fallback at all
NoFallback,
}
@@ -373,13 +373,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
diverging_fallback.insert(diverging_ty, ty);
};
- use DivergingFallbackBehavior::*;
match behavior {
- FallbackToUnit => {
+ DivergingFallbackBehavior::ToUnit => {
debug!("fallback to () - legacy: {:?}", diverging_vid);
fallback_to(self.tcx.types.unit);
}
- FallbackToNiko => {
+ DivergingFallbackBehavior::ContextDependent => {
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
// This case falls back to () to ensure that the code pattern in
// tests/ui/never_type/fallback-closure-ret.rs continues to
@@ -415,14 +414,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
fallback_to(self.tcx.types.never);
}
}
- FallbackToNever => {
+ DivergingFallbackBehavior::ToNever => {
debug!(
"fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
diverging_vid
);
fallback_to(self.tcx.types.never);
}
- NoFallback => {
+ DivergingFallbackBehavior::NoFallback => {
debug!(
"no fallback - `rustc_never_type_mode = \"no_fallback\"`: {:?}",
diverging_vid
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index e354e1ec59c6..94e879ae9c3e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -660,8 +660,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
}
- pub(crate) fn err_args(&self, len: usize) -> Vec> {
- let ty_error = Ty::new_misc_error(self.tcx);
+ pub(crate) fn err_args(&self, len: usize, guar: ErrorGuaranteed) -> Vec> {
+ let ty_error = Ty::new_error(self.tcx, guar);
vec![ty_error; len]
}
@@ -846,15 +846,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if item_name.name != kw::Empty {
- if let Some(e) = self.report_method_error(
+ self.report_method_error(
hir_id,
ty.normalized,
error,
Expectation::NoExpectation,
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
- ) {
- e.emit();
- }
+ );
}
result
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index b8333d474937..e20a6ef7c133 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -113,17 +113,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
sp: Span,
expr: &'tcx hir::Expr<'tcx>,
- method: Result, ()>,
+ method: Result, ErrorGuaranteed>,
args_no_rcvr: &'tcx [hir::Expr<'tcx>],
tuple_arguments: TupleArgumentsFlag,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let has_error = match method {
- Ok(method) => method.args.references_error() || method.sig.references_error(),
- Err(_) => true,
+ Ok(method) => method.args.error_reported().and(method.sig.error_reported()),
+ Err(guar) => Err(guar),
};
- if has_error {
- let err_inputs = self.err_args(args_no_rcvr.len());
+ if let Err(guar) = has_error {
+ let err_inputs = self.err_args(args_no_rcvr.len(), guar);
let err_inputs = match tuple_arguments {
DontTupleArguments => err_inputs,
@@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tuple_arguments,
method.ok().map(|method| method.def_id),
);
- return Ty::new_misc_error(self.tcx);
+ return Ty::new_error(self.tcx, guar);
}
let method = method.unwrap();
@@ -237,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
// Otherwise, there's a mismatch, so clear out what we're expecting, and set
// our input types to err_args so we don't blow up the error messages
- struct_span_code_err!(
+ let guar = struct_span_code_err!(
tcx.dcx(),
call_span,
E0059,
@@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for the function trait is neither a tuple nor unit"
)
.emit();
- (self.err_args(provided_args.len()), None)
+ (self.err_args(provided_args.len(), guar), None)
}
}
} else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index f02b0f953900..2ef27e6a0ba7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -124,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
body_id: LocalDefId,
) -> FnCtxt<'a, 'tcx> {
let (diverging_fallback_behavior, diverging_block_behavior) =
- parse_never_type_options_attr(root_ctxt.tcx);
+ never_type_behavior(root_ctxt.tcx);
FnCtxt {
body_id,
param_env,
@@ -387,11 +387,33 @@ impl<'tcx> LoweredTy<'tcx> {
}
}
+fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
+ let (fallback, block) = parse_never_type_options_attr(tcx);
+ let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
+ let block = block.unwrap_or_default();
+
+ (fallback, block)
+}
+
+/// Returns the default fallback which is used when there is no explicit override via `#![never_type_options(...)]`.
+fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
+ // Edition 2024: fallback to `!`
+ if tcx.sess.edition().at_least_rust_2024() {
+ return DivergingFallbackBehavior::ToNever;
+ }
+
+ // `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff
+ if tcx.features().never_type_fallback {
+ return DivergingFallbackBehavior::ContextDependent;
+ }
+
+ // Otherwise: fallback to `()`
+ DivergingFallbackBehavior::ToUnit
+}
+
fn parse_never_type_options_attr(
tcx: TyCtxt<'_>,
-) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
- use DivergingFallbackBehavior::*;
-
+) -> (Option, Option) {
// Error handling is dubious here (unwraps), but that's probably fine for an internal attribute.
// Just don't write incorrect attributes <3
@@ -407,10 +429,10 @@ fn parse_never_type_options_attr(
if item.has_name(sym::fallback) && fallback.is_none() {
let mode = item.value_str().unwrap();
match mode {
- sym::unit => fallback = Some(FallbackToUnit),
- sym::niko => fallback = Some(FallbackToNiko),
- sym::never => fallback = Some(FallbackToNever),
- sym::no => fallback = Some(NoFallback),
+ sym::unit => fallback = Some(DivergingFallbackBehavior::ToUnit),
+ sym::niko => fallback = Some(DivergingFallbackBehavior::ContextDependent),
+ sym::never => fallback = Some(DivergingFallbackBehavior::ToNever),
+ sym::no => fallback = Some(DivergingFallbackBehavior::NoFallback),
_ => {
tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
}
@@ -439,11 +461,5 @@ fn parse_never_type_options_attr(
);
}
- let fallback = fallback.unwrap_or_else(|| {
- if tcx.features().never_type_fallback { FallbackToNiko } else { FallbackToUnit }
- });
-
- let block = block.unwrap_or_default();
-
(fallback, block)
}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 86fe2756b59a..b0fd6de34968 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -1,11 +1,13 @@
+// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![feature(if_let_guard)]
-#![feature(let_chains)]
-#![feature(try_blocks)]
-#![feature(never_type)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
+#![feature(if_let_guard)]
+#![feature(let_chains)]
+#![feature(never_type)]
+#![feature(try_blocks)]
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index bbe4a8791c69..28d738c11c8f 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -33,7 +33,7 @@ use rustc_middle::ty::IsSuggestable;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span};
+use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span};
use rustc_span::{Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
@@ -192,7 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: MethodError<'tcx>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
- ) -> Option> {
+ ) -> ErrorGuaranteed {
let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
hir::Node::Expr(&hir::Expr {
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
@@ -226,8 +226,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Avoid suggestions when we don't know what's going on.
- if rcvr_ty.references_error() {
- return None;
+ if let Err(guar) = rcvr_ty.error_reported() {
+ return guar;
}
match error {
@@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut sources,
Some(sugg_span),
);
- err.emit();
+ return err.emit();
}
MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
@@ -286,7 +286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.unwrap_or_else(|| self.tcx.def_span(def_id));
err.span_label(sp, format!("private {kind} defined here"));
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
- err.emit();
+ return err.emit();
}
MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
@@ -343,12 +343,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- err.emit();
+ return err.emit();
}
MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
}
- None
}
fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
@@ -564,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn report_no_match_method_error(
+ fn report_no_match_method_error(
&self,
mut span: Span,
rcvr_ty: Ty<'tcx>,
@@ -576,7 +575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
- ) -> Option> {
+ ) -> ErrorGuaranteed {
let mode = no_match_data.mode;
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
@@ -608,14 +607,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We could pass the file for long types into these two, but it isn't strictly necessary
// given how targeted they are.
- if self.suggest_wrapping_range_with_parens(
+ if let Err(guar) = self.report_failed_method_call_on_range_end(
tcx,
rcvr_ty,
source,
span,
item_name,
&short_ty_str,
- ) || self.suggest_constraining_numerical_ty(
+ ) {
+ return guar;
+ }
+ if let Err(guar) = self.report_failed_method_call_on_numerical_infer_var(
tcx,
rcvr_ty,
source,
@@ -624,7 +626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name,
&short_ty_str,
) {
- return None;
+ return guar;
}
span = item_name.span;
@@ -881,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![(span.shrink_to_lo(), format!("into_iter()."))],
Applicability::MaybeIncorrect,
);
- return Some(err);
+ return err.emit();
} else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
// We special case the situation where we are looking for `_` in
// `::method` because otherwise the machinery will look for blanket
@@ -1606,7 +1608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
- Some(err)
+ err.emit()
}
/// If an appropriate error source is not found, check method chain for possible candidates
@@ -2251,7 +2253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Suggest possible range with adding parentheses, for example:
/// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
- fn suggest_wrapping_range_with_parens(
+ fn report_failed_method_call_on_range_end(
&self,
tcx: TyCtxt<'tcx>,
actual: Ty<'tcx>,
@@ -2259,7 +2261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
item_name: Ident,
ty_str: &str,
- ) -> bool {
+ ) -> Result<(), ErrorGuaranteed> {
if let SelfSource::MethodCall(expr) = source {
for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
if let Node::Expr(parent_expr) = parent {
@@ -2316,7 +2318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
- tcx.dcx().emit_err(errors::MissingParenthesesInRange {
+ return Err(tcx.dcx().emit_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
method_name: item_name.as_str().to_string(),
@@ -2325,16 +2327,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
left: range_span.shrink_to_lo(),
right: range_span.shrink_to_hi(),
}),
- });
- return true;
+ }));
}
}
}
}
- false
+ Ok(())
}
- fn suggest_constraining_numerical_ty(
+ fn report_failed_method_call_on_numerical_infer_var(
&self,
tcx: TyCtxt<'tcx>,
actual: Ty<'tcx>,
@@ -2343,7 +2344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_kind: &str,
item_name: Ident,
ty_str: &str,
- ) -> bool {
+ ) -> Result<(), ErrorGuaranteed> {
let found_candidate = all_traits(self.tcx)
.into_iter()
.any(|info| self.associated_value(info.def_id, item_name).is_some());
@@ -2447,10 +2448,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => {}
}
- err.emit();
- return true;
+ return Err(err.emit());
}
- false
+ Ok(())
}
/// For code `rect::area(...)`,
@@ -3360,14 +3360,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.source_map()
.indentation_before(rcvr.span)
.unwrap_or_else(|| " ".to_string());
- err.multipart_suggestion(
- "consider pinning the expression",
- vec![
- (rcvr.span.shrink_to_lo(), format!("let mut pinned = std::pin::pin!(")),
- (rcvr.span.shrink_to_hi(), format!(");\n{indent}pinned.{pin_call}()")),
- ],
- Applicability::MaybeIncorrect,
- );
+ let mut expr = rcvr;
+ while let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
+ && let hir::ExprKind::MethodCall(hir::PathSegment { .. }, ..) =
+ call_expr.kind
+ {
+ expr = call_expr;
+ }
+ match self.tcx.parent_hir_node(expr.hir_id) {
+ Node::LetStmt(stmt)
+ if let Some(init) = stmt.init
+ && let Ok(code) =
+ self.tcx.sess.source_map().span_to_snippet(rcvr.span) =>
+ {
+ // We need to take care to account for the existing binding when we
+ // suggest the code.
+ err.multipart_suggestion(
+ "consider pinning the expression",
+ vec![
+ (
+ stmt.span.shrink_to_lo(),
+ format!(
+ "let mut pinned = std::pin::pin!({code});\n{indent}"
+ ),
+ ),
+ (
+ init.span.until(rcvr.span.shrink_to_hi()),
+ format!("pinned.{pin_call}()"),
+ ),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ Node::Block(_) | Node::Stmt(_) => {
+ // There's no binding, so we can provide a slightly nicer looking
+ // suggestion.
+ err.multipart_suggestion(
+ "consider pinning the expression",
+ vec![
+ (
+ rcvr.span.shrink_to_lo(),
+ format!("let mut pinned = std::pin::pin!("),
+ ),
+ (
+ rcvr.span.shrink_to_hi(),
+ format!(");\n{indent}pinned.{pin_call}()"),
+ ),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ // We don't quite know what the users' code looks like, so we don't
+ // provide a pinning suggestion.
+ err.span_help(
+ rcvr.span,
+ "consider pinning the expression with `std::pin::pin!()` and \
+ assigning that to a new binding",
+ );
+ }
+ }
// We don't care about the other suggestions.
alt_rcvr_sugg = true;
}
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 960a2d012e0f..76e3c0682deb 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -1,10 +1,12 @@
//! Support for serializing the dep-graph and reloading it.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
mod assert_dep_graph;
mod errors;
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 6fcb3a024ab6..db6b250467e5 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,9 +1,11 @@
+// tidy-alphabetical-start
+#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
#![cfg_attr(
feature = "nightly",
feature(extend_one, min_specialization, new_uninit, step_trait, test)
)]
-#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
+// tidy-alphabetical-end
pub mod bit_set;
#[cfg(feature = "nightly")]
diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs
index 015518ae4d68..3e55dd82a6e8 100644
--- a/compiler/rustc_index_macros/src/lib.rs
+++ b/compiler/rustc_index_macros/src/lib.rs
@@ -1,5 +1,7 @@
-#![cfg_attr(feature = "nightly", feature(allow_internal_unstable))]
+// tidy-alphabetical-start
#![cfg_attr(feature = "nightly", allow(internal_features))]
+#![cfg_attr(feature = "nightly", feature(allow_internal_unstable))]
+// tidy-alphabetical-end
use proc_macro::TokenStream;
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 046d908d148d..01bd732a4cd8 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -31,6 +31,8 @@ use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation};
use rustc_middle::bug;
use rustc_middle::ty::{Const, ImplSubject};
+use crate::traits::Obligation;
+
/// Whether we should define opaque types or just treat them opaquely.
///
/// Currently only used to prevent predicate matching from matching anything
@@ -119,10 +121,8 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
define_opaque_types,
);
- fields
- .sup()
- .relate(expected, actual)
- .map(|_| InferOk { value: (), obligations: fields.obligations })
+ fields.sup().relate(expected, actual)?;
+ Ok(InferOk { value: (), obligations: fields.into_obligations() })
}
/// Makes `expected <: actual`.
@@ -141,10 +141,8 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
define_opaque_types,
);
- fields
- .sub()
- .relate(expected, actual)
- .map(|_| InferOk { value: (), obligations: fields.obligations })
+ fields.sub().relate(expected, actual)?;
+ Ok(InferOk { value: (), obligations: fields.into_obligations() })
}
/// Makes `expected == actual`.
@@ -163,10 +161,22 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
define_opaque_types,
);
- fields
- .equate(StructurallyRelateAliases::No)
- .relate(expected, actual)
- .map(|_| InferOk { value: (), obligations: fields.obligations })
+ fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?;
+ Ok(InferOk {
+ value: (),
+ obligations: fields
+ .goals
+ .into_iter()
+ .map(|goal| {
+ Obligation::new(
+ self.infcx.tcx,
+ fields.trace.cause.clone(),
+ goal.param_env,
+ goal.predicate,
+ )
+ })
+ .collect(),
+ })
}
/// Equates `expected` and `found` while structurally relating aliases.
@@ -187,10 +197,8 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
DefineOpaqueTypes::Yes,
);
- fields
- .equate(StructurallyRelateAliases::Yes)
- .relate(expected, actual)
- .map(|_| InferOk { value: (), obligations: fields.obligations })
+ fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?;
+ Ok(InferOk { value: (), obligations: fields.into_obligations() })
}
pub fn relate(
@@ -237,10 +245,8 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
define_opaque_types,
);
- fields
- .lub()
- .relate(expected, actual)
- .map(|value| InferOk { value, obligations: fields.obligations })
+ let value = fields.lub().relate(expected, actual)?;
+ Ok(InferOk { value, obligations: fields.into_obligations() })
}
/// Computes the greatest-lower-bound, or mutual subtype, of two
@@ -261,10 +267,8 @@ impl<'a, 'tcx> At<'a, 'tcx> {
self.param_env,
define_opaque_types,
);
- fields
- .glb()
- .relate(expected, actual)
- .map(|value| InferOk { value, obligations: fields.obligations })
+ let value = fields.glb().relate(expected, actual)?;
+ Ok(InferOk { value, obligations: fields.into_obligations() })
}
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index c606ab808ef8..32b50053b507 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,6 +1,9 @@
pub use at::DefineOpaqueTypes;
pub use freshen::TypeFreshener;
pub use lexical_region_resolve::RegionResolutionError;
+pub use relate::combine::CombineFields;
+pub use relate::combine::PredicateEmittingRelation;
+pub use relate::StructurallyRelateAliases;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
pub use rustc_middle::ty::IntVarValue;
pub use BoundRegionConversionTime::*;
@@ -8,10 +11,8 @@ pub use RegionVariableOrigin::*;
pub use SubregionOrigin::*;
pub use ValuePairs::*;
-use crate::infer::relate::{CombineFields, RelateResult};
-use crate::traits::{
- self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
-};
+use crate::infer::relate::RelateResult;
+use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
use error_reporting::TypeErrCtxt;
use free_regions::RegionRelations;
use lexical_region_resolve::LexicalRegionResolutions;
@@ -68,7 +69,7 @@ pub mod type_variable;
#[derive(Debug)]
pub struct InferOk<'tcx, T> {
pub value: T,
- pub obligations: PredicateObligations<'tcx>,
+ pub obligations: Vec>,
}
pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>;
@@ -748,7 +749,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
}
impl<'tcx> InferOk<'tcx, ()> {
- pub fn into_obligations(self) -> PredicateObligations<'tcx> {
+ pub fn into_obligations(self) -> Vec> {
self.obligations
}
}
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 8eb3185673b4..7114b888718b 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -1,11 +1,11 @@
-use super::{DefineOpaqueTypes, InferResult};
use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{InferCtxt, InferOk};
-use crate::traits::{self, PredicateObligation};
+use crate::traits::{self, Obligation};
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
+use rustc_middle::traits::solve::Goal;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
@@ -21,6 +21,8 @@ mod table;
pub type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueTypeDecl<'tcx>>;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
+use super::DefineOpaqueTypes;
+
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
@@ -62,11 +64,23 @@ impl<'tcx> InferCtxt<'tcx> {
{
let def_span = self.tcx.def_span(def_id);
let span = if span.contains(def_span) { def_span } else { span };
- let code = traits::ObligationCauseCode::OpaqueReturnType(None);
- let cause = ObligationCause::new(span, body_id, code);
let ty_var = self.next_ty_var(span);
obligations.extend(
- self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
+ self.handle_opaque_type(ty, ty_var, span, param_env)
+ .unwrap()
+ .into_iter()
+ .map(|goal| {
+ Obligation::new(
+ self.tcx,
+ ObligationCause::new(
+ span,
+ body_id,
+ traits::ObligationCauseCode::OpaqueReturnType(None),
+ ),
+ goal.param_env,
+ goal.predicate,
+ )
+ }),
);
ty_var
}
@@ -80,9 +94,9 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
- cause: &ObligationCause<'tcx>,
+ span: Span,
param_env: ty::ParamEnv<'tcx>,
- ) -> InferResult<'tcx, ()> {
+ ) -> Result>>, TypeError<'tcx>> {
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
@@ -90,7 +104,7 @@ impl<'tcx> InferCtxt<'tcx> {
// See comment on `insert_hidden_type` for why this is sufficient in coherence
return Some(self.register_hidden_type(
OpaqueTypeKey { def_id, args },
- cause.clone(),
+ span,
param_env,
b,
));
@@ -143,18 +157,13 @@ impl<'tcx> InferCtxt<'tcx> {
&& self.tcx.is_type_alias_impl_trait(b_def_id)
{
self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
- span: cause.span,
+ span,
hidden_type: self.tcx.def_span(b_def_id),
opaque_type: self.tcx.def_span(def_id),
});
}
}
- Some(self.register_hidden_type(
- OpaqueTypeKey { def_id, args },
- cause.clone(),
- param_env,
- b,
- ))
+ Some(self.register_hidden_type(OpaqueTypeKey { def_id, args }, span, param_env, b))
}
_ => None,
};
@@ -464,24 +473,23 @@ impl<'tcx> InferCtxt<'tcx> {
fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
- cause: ObligationCause<'tcx>,
+ span: Span,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
- ) -> InferResult<'tcx, ()> {
- let mut obligations = Vec::new();
+ ) -> Result>>, TypeError<'tcx>> {
+ let mut goals = Vec::new();
- self.insert_hidden_type(opaque_type_key, &cause, param_env, hidden_ty, &mut obligations)?;
+ self.insert_hidden_type(opaque_type_key, span, param_env, hidden_ty, &mut goals)?;
self.add_item_bounds_for_hidden_type(
opaque_type_key.def_id.to_def_id(),
opaque_type_key.args,
- cause,
param_env,
hidden_ty,
- &mut obligations,
+ &mut goals,
);
- Ok(InferOk { value: (), obligations })
+ Ok(goals)
}
/// Insert a hidden type into the opaque type storage, making sure
@@ -507,27 +515,21 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn insert_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
- cause: &ObligationCause<'tcx>,
+ span: Span,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
- obligations: &mut Vec>,
+ goals: &mut Vec>>,
) -> Result<(), TypeError<'tcx>> {
// Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`.
- let span = cause.span;
if self.intercrate {
// During intercrate we do not define opaque types but instead always
// force ambiguity unless the hidden type is known to not implement
// our trait.
- obligations.push(traits::Obligation::new(
- self.tcx,
- cause.clone(),
- param_env,
- ty::PredicateKind::Ambiguous,
- ))
+ goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous))
} else {
let prev = self
.inner
@@ -535,10 +537,13 @@ impl<'tcx> InferCtxt<'tcx> {
.opaque_types()
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
if let Some(prev) = prev {
- obligations.extend(
- self.at(cause, param_env)
+ goals.extend(
+ self.at(&ObligationCause::dummy_with_span(span), param_env)
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
- .obligations,
+ .obligations
+ .into_iter()
+ // FIXME: Shuttling between obligations and goals is awkward.
+ .map(Goal::from),
);
}
};
@@ -550,10 +555,9 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
- cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
- obligations: &mut Vec>,
+ goals: &mut Vec>>,
) {
let tcx = self.tcx;
// Require that the hidden type is well-formed. We have to
@@ -567,12 +571,7 @@ impl<'tcx> InferCtxt<'tcx> {
// type during MIR borrowck, causing us to infer the wrong
// lifetime for its member constraints which then results in
// unexpected region errors.
- obligations.push(traits::Obligation::new(
- tcx,
- cause.clone(),
- param_env,
- ty::ClauseKind::WellFormed(hidden_ty.into()),
- ));
+ goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
let item_bounds = tcx.explicit_item_bounds(def_id);
for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
@@ -588,13 +587,18 @@ impl<'tcx> InferCtxt<'tcx> {
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id)
&& !self.next_trait_solver() =>
{
- self.projection_ty_to_infer(
+ let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
+ goals.push(Goal::new(
+ self.tcx,
param_env,
- projection_ty,
- cause.clone(),
- 0,
- obligations,
- )
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(
+ ty::ProjectionPredicate {
+ projection_term: projection_ty.into(),
+ term: ty_var.into(),
+ },
+ )),
+ ));
+ ty_var
}
// Replace all other mentions of the same opaque type with the hidden type,
// as the bounds must hold on the hidden type after all.
@@ -611,12 +615,7 @@ impl<'tcx> InferCtxt<'tcx> {
// Require that the predicate holds for the concrete type.
debug!(?predicate);
- obligations.push(traits::Obligation::new(
- self.tcx,
- cause.clone(),
- param_env,
- predicate,
- ));
+ goals.push(Goal::new(self.tcx, param_env, predicate));
}
}
}
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index 167863479806..a1ba43eb1715 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -21,11 +21,12 @@ impl<'tcx> InferCtxt<'tcx> {
obligations: &mut Vec>,
) -> Ty<'tcx> {
debug_assert!(!self.next_trait_solver());
- let def_id = projection_ty.def_id;
- let ty_var = self.next_ty_var(self.tcx.def_span(def_id));
- let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
- ty::ProjectionPredicate { projection_term: projection_ty.into(), term: ty_var.into() },
- )));
+ let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
+ let projection =
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
+ projection_term: projection_ty.into(),
+ term: ty_var.into(),
+ }));
let obligation =
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
obligations.push(obligation);
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 30cb2bab9008..0a2e85cc8919 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -25,9 +25,10 @@ use super::StructurallyRelateAliases;
use super::{RelateResult, TypeRelation};
use crate::infer::relate;
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
-use crate::traits::{Obligation, PredicateObligations};
+use crate::traits::{Obligation, PredicateObligation};
use rustc_middle::bug;
use rustc_middle::infer::unify_key::EffectVarValue;
+use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
use rustc_middle::ty::{IntType, UintType};
@@ -38,7 +39,7 @@ pub struct CombineFields<'infcx, 'tcx> {
pub infcx: &'infcx InferCtxt<'tcx>,
pub trace: TypeTrace<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
- pub obligations: PredicateObligations<'tcx>,
+ pub goals: Vec>>,
pub define_opaque_types: DefineOpaqueTypes,
}
@@ -49,7 +50,21 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
define_opaque_types: DefineOpaqueTypes,
) -> Self {
- Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] }
+ Self { infcx, trace, param_env, define_opaque_types, goals: vec![] }
+ }
+
+ pub(crate) fn into_obligations(self) -> Vec> {
+ self.goals
+ .into_iter()
+ .map(|goal| {
+ Obligation::new(
+ self.infcx.tcx,
+ self.trace.cause.clone(),
+ goal.param_env,
+ goal.predicate,
+ )
+ })
+ .collect()
}
}
@@ -61,7 +76,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>>
where
- R: ObligationEmittingRelation<'tcx>,
+ R: PredicateEmittingRelation<'tcx>,
{
debug_assert!(!a.has_escaping_bound_vars());
debug_assert!(!b.has_escaping_bound_vars());
@@ -125,7 +140,7 @@ impl<'tcx> InferCtxt<'tcx> {
relate::structurally_relate_tys(relation, a, b)
}
StructurallyRelateAliases::No => {
- relation.register_type_relate_obligation(a, b);
+ relation.register_alias_relate_predicate(a, b);
Ok(a)
}
}
@@ -156,7 +171,7 @@ impl<'tcx> InferCtxt<'tcx> {
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>>
where
- R: ObligationEmittingRelation<'tcx>,
+ R: PredicateEmittingRelation<'tcx>,
{
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
debug_assert!(!a.has_escaping_bound_vars());
@@ -290,21 +305,26 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
Glb::new(self)
}
- pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
- self.obligations.extend(obligations);
+ pub fn register_obligations(
+ &mut self,
+ obligations: impl IntoIterator- >>,
+ ) {
+ self.goals.extend(obligations);
}
pub fn register_predicates(
&mut self,
obligations: impl IntoIterator
, ty::Predicate<'tcx>>>,
) {
- self.obligations.extend(obligations.into_iter().map(|to_pred| {
- Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
- }))
+ self.goals.extend(
+ obligations
+ .into_iter()
+ .map(|to_pred| Goal::new(self.infcx.tcx, self.param_env, to_pred)),
+ )
}
}
-pub trait ObligationEmittingRelation<'tcx>: TypeRelation> {
+pub trait PredicateEmittingRelation<'tcx>: TypeRelation> {
fn span(&self) -> Span;
fn param_env(&self) -> ty::ParamEnv<'tcx>;
@@ -315,16 +335,18 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation> {
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
/// Register obligations that must hold in order for this relation to hold
- fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
+ fn register_goals(
+ &mut self,
+ obligations: impl IntoIterator- >>,
+ );
- /// Register predicates that must hold in order for this relation to hold. Uses
- /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
- /// be used if control over the obligation causes is required.
+ /// Register predicates that must hold in order for this relation to hold.
+ /// This uses the default `param_env` of the obligation.
fn register_predicates(
&mut self,
obligations: impl IntoIterator
, ty::Predicate<'tcx>>>,
);
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
- fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
+ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
}
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 5478afda455f..87a2f0b45803 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -1,7 +1,7 @@
use std::mem;
use super::StructurallyRelateAliases;
-use super::{ObligationEmittingRelation, Relate, RelateResult, TypeRelation};
+use super::{PredicateEmittingRelation, Relate, RelateResult, TypeRelation};
use crate::infer::relate;
use crate::infer::type_variable::TypeVariableValue;
use crate::infer::{InferCtxt, RegionVariableOrigin};
@@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
/// other usecases (i.e. setting the value of a type var).
#[instrument(level = "debug", skip(self, relation))]
- pub fn instantiate_ty_var>(
+ pub fn instantiate_ty_var>(
&self,
relation: &mut R,
target_is_expected: bool,
@@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
///
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
#[instrument(level = "debug", skip(self, relation))]
- pub(super) fn instantiate_const_var>(
+ pub(super) fn instantiate_const_var>(
&self,
relation: &mut R,
target_is_expected: bool,
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index 98e8f07c7a21..cc17e60a79b0 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -1,14 +1,15 @@
//! Greatest lower bound. See [`lattice`].
-use super::{Relate, RelateResult, TypeRelation};
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
-use super::combine::{CombineFields, ObligationEmittingRelation};
+use super::combine::{CombineFields, PredicateEmittingRelation};
use super::lattice::{self, LatticeDir};
use super::StructurallyRelateAliases;
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::{ObligationCause, PredicateObligations};
+use crate::traits::ObligationCause;
/// "Greatest lower bound" (common subtype)
pub struct Glb<'combine, 'infcx, 'tcx> {
@@ -127,7 +128,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
}
}
-impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
@@ -147,11 +148,14 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.fields.register_predicates(obligations);
}
- fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+ fn register_goals(
+ &mut self,
+ obligations: impl IntoIterator- >>,
+ ) {
self.fields.register_obligations(obligations);
}
- fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index f05b984142ae..6cc8d6d910ad 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -17,11 +17,11 @@
//!
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
-use super::combine::ObligationEmittingRelation;
+use super::combine::PredicateEmittingRelation;
use crate::infer::{DefineOpaqueTypes, InferCtxt};
use crate::traits::ObligationCause;
-use super::RelateResult;
+use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty};
@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty};
///
/// GLB moves "down" the lattice (to smaller values); LUB moves
/// "up" the lattice (to bigger values).
-pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
+pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> {
fn infcx(&self) -> &'f InferCtxt<'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>;
@@ -108,9 +108,7 @@ where
&& def_id.is_local()
&& !this.infcx().next_trait_solver() =>
{
- this.register_obligations(
- infcx.handle_opaque_type(a, b, this.cause(), this.param_env())?.obligations,
- );
+ this.register_goals(infcx.handle_opaque_type(a, b, this.span(), this.param_env())?);
Ok(a)
}
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 28dbaa94f95d..e9d300d349c6 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -1,12 +1,13 @@
//! Least upper bound. See [`lattice`].
-use super::combine::{CombineFields, ObligationEmittingRelation};
+use super::combine::{CombineFields, PredicateEmittingRelation};
use super::lattice::{self, LatticeDir};
use super::StructurallyRelateAliases;
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::{ObligationCause, PredicateObligations};
+use crate::traits::ObligationCause;
-use super::{Relate, RelateResult, TypeRelation};
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
@@ -127,7 +128,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
}
}
-impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
@@ -147,11 +148,14 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.fields.register_predicates(obligations);
}
- fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+ fn register_goals(
+ &mut self,
+ obligations: impl IntoIterator
- >>,
+ ) {
self.fields.register_obligations(obligations)
}
- fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index 627c527cba15..e7b50479b850 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -6,7 +6,7 @@ pub use rustc_middle::ty::relate::*;
pub use self::_match::MatchAgainstFreshVars;
pub use self::combine::CombineFields;
-pub use self::combine::ObligationEmittingRelation;
+pub use self::combine::PredicateEmittingRelation;
pub mod _match;
pub(super) mod combine;
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index fd0bc9f44f75..f7b2f11e3d70 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -1,11 +1,10 @@
use super::combine::CombineFields;
+use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
use crate::infer::BoundRegionConversionTime::HigherRankedType;
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
-use crate::traits::{Obligation, PredicateObligations};
-
-use super::{
- relate_args_invariantly, relate_args_with_variances, ObligationEmittingRelation, Relate,
- RelateResult, StructurallyRelateAliases, TypeRelation,
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{
+ relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
};
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -88,9 +87,8 @@ impl<'tcx> TypeRelation
> for TypeRelating<'_, '_, 'tcx> {
ty::Covariant => {
// can't make progress on `A <: B` if both A and B are
// type variables, so record an obligation.
- self.fields.obligations.push(Obligation::new(
+ self.fields.goals.push(Goal::new(
self.tcx(),
- self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: true,
@@ -102,9 +100,8 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> {
ty::Contravariant => {
// can't make progress on `B <: A` if both A and B are
// type variables, so record an obligation.
- self.fields.obligations.push(Obligation::new(
+ self.fields.goals.push(Goal::new(
self.tcx(),
- self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: false,
@@ -153,11 +150,12 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> {
&& def_id.is_local()
&& !infcx.next_trait_solver() =>
{
- self.fields.obligations.extend(
- infcx
- .handle_opaque_type(a, b, &self.fields.trace.cause, self.param_env())?
- .obligations,
- );
+ self.fields.goals.extend(infcx.handle_opaque_type(
+ a,
+ b,
+ self.fields.trace.cause.span,
+ self.param_env(),
+ )?);
}
_ => {
@@ -298,7 +296,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> {
}
}
-impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
fn span(&self) -> Span {
self.fields.trace.span()
}
@@ -318,11 +316,14 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
self.fields.register_predicates(obligations);
}
- fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+ fn register_goals(
+ &mut self,
+ obligations: impl IntoIterator- >>,
+ ) {
self.fields.register_obligations(obligations);
}
- fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
a.into(),
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 28d908abf83e..b65ac8596675 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -12,22 +12,24 @@
//!
//! This API is completely unstable and subject to change.
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![doc(rust_logo)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(extend_one)]
-#![feature(let_chains)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(iterator_try_collect)]
+#![feature(let_chains)]
+#![feature(rustdoc_internals)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![recursion_limit = "512"] // For rustdoc
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index ca6c6570e072..556b3bd063da 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -114,8 +114,6 @@ impl<'tcx> PolyTraitObligation<'tcx> {
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(PredicateObligation<'_>, 48);
-pub type PredicateObligations<'tcx> = Vec
>;
-
pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
/// A callback that can be provided to `inspect_typeck`. Invoked on evaluation
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 8b1d9b706cac..0c3d4e19ef82 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,7 +1,9 @@
+// tidy-alphabetical-start
#![feature(decl_macro)]
#![feature(let_chains)]
#![feature(thread_spawn_unchecked)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
mod callbacks;
mod errors;
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 6f8a9792b6ce..d4efb41eed08 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -19,9 +19,11 @@
//!
//! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html
+// tidy-alphabetical-start
// We want to be able to build this crate with a stable compiler,
// so no `#![feature]` attributes should be added.
#![deny(unstable_features)]
+// tidy-alphabetical-end
mod cursor;
pub mod unescape;
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 0c236a4ed11f..733c73bc3d07 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -445,7 +445,8 @@ lint_macro_is_private = macro `{$ident}` is private
lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
lint_macro_use_deprecated =
- deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+ applying the `#[macro_use]` attribute to an `extern crate` item is deprecated
+ .help = remove it and import macros at use sites with a `use` item instead
lint_malformed_attribute = malformed lint attribute input
@@ -456,7 +457,7 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
.map_label = after this call to map, the resulting iterator is `impl Iterator- `, which means the only information carried by the iterator is the number of items
.suggestion = you might have meant to use `Iterator::for_each`
-lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth
+lint_metavariable_still_repeating = variable `{$name}` is still repeating at this depth
lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
@@ -635,8 +636,8 @@ lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies
lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations
.label = pattern not allowed in foreign function
-lint_private_extern_crate_reexport =
- extern crate `{$ident}` is private, and cannot be re-exported, consider declaring with `pub`
+lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported
+ .suggestion = consider making the `extern crate` item publicly accessible
lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
.label = names from parent modules are not accessible without an explicit import
@@ -847,7 +848,8 @@ lint_unused_coroutine =
}{$post} that must be used
.note = coroutines are lazy and do nothing unless resumed
-lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;`
+lint_unused_crate_dependency = extern crate `{$extern_crate}` is unused in crate `{$local_crate}`
+ .help = remove the dependency or add `use {$extern_crate} as _;` to the crate root
lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
.suggestion = use `let _ = ...` to ignore the resulting value
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8c9abeafacfe..98318cd14d9d 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -142,7 +142,7 @@ declare_lint! {
/// ```rust,compile_fail
/// #![deny(box_pointers)]
/// struct Foo {
- /// x: Box
,
+ /// x: Box,
/// }
/// ```
///
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 1dfbe1e93828..83640d7210fa 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -340,8 +340,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
lints::MacroUseDeprecated.decorate_lint(diag);
}
BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag),
- BuiltinLintDiag::PrivateExternCrateReexport(ident) => {
- lints::PrivateExternCrateReexport { ident }.decorate_lint(diag);
+ BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => {
+ lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() }
+ .decorate_lint(diag);
}
BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag),
BuiltinLintDiag::MacroIsPrivate(ident) => {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index bcb714ae4ce2..7dae2de7bfb5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -25,9 +25,10 @@
//!
//! This API is completely unstable and subject to change.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
@@ -35,9 +36,10 @@
#![feature(if_let_guard)]
#![feature(iter_order_by)]
#![feature(let_chains)]
-#![feature(trait_upcasting)]
#![feature(rustc_attrs)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+#![feature(trait_upcasting)]
+// tidy-alphabetical-end
mod async_fn_in_trait;
pub mod builtin;
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index c493a989d913..b377da31a581 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2313,6 +2313,7 @@ pub mod unexpected_cfg_value {
#[derive(LintDiagnostic)]
#[diag(lint_macro_use_deprecated)]
+#[help]
pub struct MacroUseDeprecated;
#[derive(LintDiagnostic)]
@@ -2323,6 +2324,8 @@ pub struct UnusedMacroUse;
#[diag(lint_private_extern_crate_reexport, code = E0365)]
pub struct PrivateExternCrateReexport {
pub ident: Ident,
+ #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")]
+ pub sugg: Span,
}
#[derive(LintDiagnostic)]
@@ -2416,6 +2419,7 @@ pub struct UnknownMacroVariable {
#[derive(LintDiagnostic)]
#[diag(lint_unused_crate_dependency)]
+#[help]
pub struct UnusedCrateDependency {
pub extern_crate: Symbol,
pub local_crate: Symbol,
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 6098da990c04..7aef6321eeb5 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -46,6 +46,8 @@ declare_lint! {
/// fn test() -> impl Trait {
/// 42
/// }
+ ///
+ /// fn main() {}
/// ```
///
/// {{produces}}
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index 41ec84faa783..85006421fdd2 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -49,10 +49,10 @@ declare_lint! {
///
/// ### Explanation
///
- /// Since Rust CURRENT_RUSTC_VERSION, boxed slices implement `IntoIterator`. However, to avoid
+ /// Since Rust 1.80.0, boxed slices implement `IntoIterator`. However, to avoid
/// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still
/// behave as `(&boxed_slice).into_iter()`, returning an iterator over
- /// references, just like in Rust CURRENT_RUSTC_VERSION and earlier.
+ /// references, just like in Rust 1.80.0 and earlier.
/// This only applies to the method call syntax `boxed_slice.into_iter()`, not to
/// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`.
pub BOXED_SLICE_INTO_ITER,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index d0d570db04f8..726bd0de1299 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -511,8 +511,9 @@ declare_lint! {
/// This will produce:
///
/// ```text
- /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;`
+ /// error: extern crate `regex` is unused in crate `lint_example`
/// |
+ /// = help: remove the dependency or add `use regex as _;` to the crate root
/// note: the lint level is defined here
/// --> src/lib.rs:1:9
/// |
@@ -2160,8 +2161,7 @@ declare_lint! {
}
declare_lint! {
- /// The `macro_use_extern_crate` lint detects the use of the
- /// [`macro_use` attribute].
+ /// The `macro_use_extern_crate` lint detects the use of the [`macro_use` attribute].
///
/// ### Example
///
@@ -2179,12 +2179,13 @@ declare_lint! {
/// This will produce:
///
/// ```text
- /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+ /// error: applying the `#[macro_use]` attribute to an `extern crate` item is deprecated
/// --> src/main.rs:3:1
/// |
/// 3 | #[macro_use]
/// | ^^^^^^^^^^^^
/// |
+ /// = help: remove it and import macros at use sites with a `use` item instead
/// note: the lint level is defined here
/// --> src/main.rs:1:9
/// |
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index a2970884af40..1ce95df34041 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -1,3 +1,4 @@
+// tidy-alphabetical-start
pub use self::Level::*;
use rustc_ast::node_id::NodeId;
use rustc_ast::{AttrId, Attribute};
@@ -14,6 +15,7 @@ use rustc_span::edition::Edition;
use rustc_span::symbol::MacroRulesNormalizedIdent;
use rustc_span::{sym, symbol::Ident, Span, Symbol};
use rustc_target::spec::abi::Abi;
+// tidy-alphabetical-end
use serde::{Deserialize, Serialize};
@@ -706,7 +708,10 @@ pub enum BuiltinLintDiag {
},
MacroUseDeprecated,
UnusedMacroUse,
- PrivateExternCrateReexport(Ident),
+ PrivateExternCrateReexport {
+ source: Ident,
+ extern_crate_span: Span,
+ },
UnusedLabel,
MacroIsPrivate(Ident),
UnusedMacroDefinition(Symbol),
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 024f6f89a4b7..cdaabb036c2a 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -23,6 +23,7 @@ const OPTIONAL_COMPONENTS: &[&str] = &[
"nvptx",
"hexagon",
"riscv",
+ "xtensa",
"bpf",
];
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 3fcf3aca8afe..a027ddcc1508 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -155,6 +155,12 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) {
#define SUBTARGET_SPARC
#endif
+#ifdef LLVM_COMPONENT_XTENSA
+#define SUBTARGET_XTENSA SUBTARGET(XTENSA)
+#else
+#define SUBTARGET_XTENSA
+#endif
+
#ifdef LLVM_COMPONENT_HEXAGON
#define SUBTARGET_HEXAGON SUBTARGET(Hexagon)
#else
@@ -180,6 +186,7 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) {
SUBTARGET_MSP430 \
SUBTARGET_SPARC \
SUBTARGET_HEXAGON \
+ SUBTARGET_XTENSA \
SUBTARGET_RISCV \
SUBTARGET_LOONGARCH \
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 6a570c97c888..e5366c9b5183 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,7 +1,9 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
// NOTE: This crate only exists to allow linking on mingw targets.
@@ -188,6 +190,13 @@ pub fn initialize_available_targets() {
LLVMInitializeHexagonAsmPrinter,
LLVMInitializeHexagonAsmParser
);
+ init_target!(
+ llvm_component = "xtensa",
+ LLVMInitializeXtensaTargetInfo,
+ LLVMInitializeXtensaTarget,
+ LLVMInitializeXtensaTargetMC,
+ LLVMInitializeXtensaAsmParser
+ );
init_target!(
llvm_component = "webassembly",
LLVMInitializeWebAssemblyTargetInfo,
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
index 3ff86f700a53..fe399bc77e32 100644
--- a/compiler/rustc_log/Cargo.toml
+++ b/compiler/rustc_log/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
tracing = "0.1.28"
tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.3.0"
+tracing-tree = "0.3.1"
# tidy-alphabetical-end
[dev-dependencies]
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 41b26ecce3c5..01b6e342df04 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -58,6 +58,7 @@ pub struct LoggerConfig {
pub verbose_thread_ids: Result,
pub backtrace: Result,
pub wraptree: Result,
+ pub lines: Result,
}
impl LoggerConfig {
@@ -69,6 +70,7 @@ impl LoggerConfig {
verbose_thread_ids: env::var(format!("{env}_THREAD_IDS")),
backtrace: env::var(format!("{env}_BACKTRACE")),
wraptree: env::var(format!("{env}_WRAPTREE")),
+ lines: env::var(format!("{env}_LINES")),
}
}
}
@@ -101,6 +103,11 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
Err(_) => false,
};
+ let lines = match cfg.lines {
+ Ok(v) => &v == "1",
+ Err(_) => false,
+ };
+
let mut layer = tracing_tree::HierarchicalLayer::default()
.with_writer(io::stderr)
.with_ansi(color_logs)
@@ -108,6 +115,7 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
.with_verbose_exit(verbose_entry_exit)
.with_verbose_entry(verbose_entry_exit)
.with_indent_amount(2)
+ .with_indent_lines(lines)
.with_thread_ids(verbose_thread_ids)
.with_thread_names(verbose_thread_ids);
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index de9c916b4f04..9d7418cd370a 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -1,3 +1,6 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::default_hash_types)]
#![feature(allow_internal_unstable)]
#![feature(if_let_guard)]
#![feature(let_chains)]
@@ -5,8 +8,7 @@
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
#![feature(proc_macro_tracked_env)]
-#![allow(rustc::default_hash_types)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
use synstructure::decl_derive;
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index afee8d5646c8..1cef35f082b9 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -314,6 +314,7 @@ provide! { tcx, def_id, other, cdata,
extern_crate => { cdata.extern_crate.map(|c| &*tcx.arena.alloc(c)) }
is_no_builtins => { cdata.root.no_builtins }
symbol_mangling_version => { cdata.root.symbol_mangling_version }
+ specialization_enabled_in => { cdata.root.specialization_enabled_in }
reachable_non_generics => {
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 67c5bc8c786b..89da0df8575e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -741,6 +741,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
expn_data,
expn_hashes,
def_path_hash_map,
+ specialization_enabled_in: tcx.specialization_enabled_in(LOCAL_CRATE),
})
});
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index c2cf5b6b7125..87900c23d8da 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -290,6 +290,8 @@ pub(crate) struct CrateRoot {
panic_runtime: bool,
profiler_runtime: bool,
symbol_mangling_version: SymbolManglingVersion,
+
+ specialization_enabled_in: bool,
}
/// On-disk representation of `DefId`.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index f95afb199f7f..c8c12e205e11 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -377,9 +377,6 @@ pub struct Terminator<'tcx> {
pub kind: TerminatorKind<'tcx>,
}
-pub type Successors<'a> = impl DoubleEndedIterator- + 'a;
-pub type SuccessorsMut<'a> = impl DoubleEndedIterator
- + 'a;
-
impl<'tcx> Terminator<'tcx> {
#[inline]
pub fn successors(&self) -> Successors<'_> {
@@ -407,81 +404,95 @@ impl<'tcx> TerminatorKind<'tcx> {
pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
}
+}
- #[inline]
- pub fn successors(&self) -> Successors<'_> {
- use self::TerminatorKind::*;
- match *self {
- Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
- | Yield { resume: ref t, drop: Some(u), .. }
- | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
- | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
- | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
- slice::from_ref(t).into_iter().copied().chain(Some(u))
+pub use helper::*;
+
+mod helper {
+ use super::*;
+ pub type Successors<'a> = impl DoubleEndedIterator
- + 'a;
+ pub type SuccessorsMut<'a> = impl DoubleEndedIterator
- + 'a;
+ impl<'tcx> TerminatorKind<'tcx> {
+ #[inline]
+ pub fn successors(&self) -> Successors<'_> {
+ use self::TerminatorKind::*;
+ match *self {
+ Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
+ | Yield { resume: ref t, drop: Some(u), .. }
+ | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
+ | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
+ | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
+ slice::from_ref(t).into_iter().copied().chain(Some(u))
+ }
+ Goto { target: ref t }
+ | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
+ | Call { target: Some(ref t), unwind: _, .. }
+ | Yield { resume: ref t, drop: None, .. }
+ | Drop { target: ref t, unwind: _, .. }
+ | Assert { target: ref t, unwind: _, .. }
+ | FalseUnwind { real_target: ref t, unwind: _ } => {
+ slice::from_ref(t).into_iter().copied().chain(None)
+ }
+ UnwindResume
+ | UnwindTerminate(_)
+ | CoroutineDrop
+ | Return
+ | Unreachable
+ | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
+ InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
+ targets.iter().copied().chain(Some(u))
+ }
+ InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
+ SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
+ FalseEdge { ref real_target, imaginary_target } => {
+ slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
+ }
}
- Goto { target: ref t }
- | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
- | Call { target: Some(ref t), unwind: _, .. }
- | Yield { resume: ref t, drop: None, .. }
- | Drop { target: ref t, unwind: _, .. }
- | Assert { target: ref t, unwind: _, .. }
- | FalseUnwind { real_target: ref t, unwind: _ } => {
- slice::from_ref(t).into_iter().copied().chain(None)
- }
- UnwindResume
- | UnwindTerminate(_)
- | CoroutineDrop
- | Return
- | Unreachable
- | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
- InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
- targets.iter().copied().chain(Some(u))
- }
- InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
- SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
- FalseEdge { ref real_target, imaginary_target } => {
- slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
- }
- }
- }
-
- #[inline]
- pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
- use self::TerminatorKind::*;
- match *self {
- Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
- | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
- | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
- | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
- | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } => {
- slice::from_mut(t).into_iter().chain(Some(u))
- }
- Goto { target: ref mut t }
- | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
- | Call { target: Some(ref mut t), unwind: _, .. }
- | Yield { resume: ref mut t, drop: None, .. }
- | Drop { target: ref mut t, unwind: _, .. }
- | Assert { target: ref mut t, unwind: _, .. }
- | FalseUnwind { real_target: ref mut t, unwind: _ } => {
- slice::from_mut(t).into_iter().chain(None)
- }
- UnwindResume
- | UnwindTerminate(_)
- | CoroutineDrop
- | Return
- | Unreachable
- | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
- InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
- targets.iter_mut().chain(Some(u))
- }
- InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
- SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
- FalseEdge { ref mut real_target, ref mut imaginary_target } => {
- slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
+ }
+
+ #[inline]
+ pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+ use self::TerminatorKind::*;
+ match *self {
+ Call {
+ target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), ..
+ }
+ | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
+ | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
+ | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
+ | FalseUnwind {
+ real_target: ref mut t,
+ unwind: UnwindAction::Cleanup(ref mut u),
+ } => slice::from_mut(t).into_iter().chain(Some(u)),
+ Goto { target: ref mut t }
+ | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
+ | Call { target: Some(ref mut t), unwind: _, .. }
+ | Yield { resume: ref mut t, drop: None, .. }
+ | Drop { target: ref mut t, unwind: _, .. }
+ | Assert { target: ref mut t, unwind: _, .. }
+ | FalseUnwind { real_target: ref mut t, unwind: _ } => {
+ slice::from_mut(t).into_iter().chain(None)
+ }
+ UnwindResume
+ | UnwindTerminate(_)
+ | CoroutineDrop
+ | Return
+ | Unreachable
+ | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
+ InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
+ targets.iter_mut().chain(Some(u))
+ }
+ InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
+ SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
+ FalseEdge { ref mut real_target, ref mut imaginary_target } => {
+ slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
+ }
}
}
}
+}
+impl<'tcx> TerminatorKind<'tcx> {
#[inline]
pub fn unwind(&self) -> Option<&UnwindAction> {
match *self {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 0af32a6a8578..a8bf735fa5a9 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1494,6 +1494,11 @@ rustc_queries! {
separate_provide_extern
}
+ query specialization_enabled_in(cnum: CrateNum) -> bool {
+ desc { "checking whether the crate enabled `specialization`/`min_specialization`" }
+ separate_provide_extern
+ }
+
query specializes(_: (DefId, DefId)) -> bool {
desc { "computing whether impls specialize one another" }
}
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 52320dd141ba..13691b61941b 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -209,8 +209,8 @@ impl ScalarInt {
#[inline]
pub fn try_from_uint(i: impl Into
, size: Size) -> Option {
- let data = i.into();
- if size.truncate(data) == data { Some(Self::raw(data, size)) } else { None }
+ let (r, overflow) = Self::truncate_from_uint(i, size);
+ if overflow { None } else { Some(r) }
}
/// Returns the truncated result, and whether truncation changed the value.
@@ -223,20 +223,15 @@ impl ScalarInt {
#[inline]
pub fn try_from_int(i: impl Into, size: Size) -> Option {
- let i = i.into();
- // `into` performed sign extension, we have to truncate
- let truncated = size.truncate(i as u128);
- if size.sign_extend(truncated) as i128 == i {
- Some(Self::raw(truncated, size))
- } else {
- None
- }
+ let (r, overflow) = Self::truncate_from_int(i, size);
+ if overflow { None } else { Some(r) }
}
/// Returns the truncated result, and whether truncation changed the value.
#[inline]
pub fn truncate_from_int(i: impl Into, size: Size) -> (Self, bool) {
let data = i.into();
+ // `into` performed sign extension, we have to truncate
let r = Self::raw(size.truncate(data as u128), size);
(r, size.sign_extend(r.data) as i128 != data)
}
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 0db541899d20..71a93cc520d5 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,5 +1,5 @@
use super::flags::FlagComputation;
-use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx};
+use super::{DebruijnIndex, TypeFlags};
use crate::arena::Arena;
use rustc_data_structures::aligned::{align_of, Aligned};
use rustc_serialize::{Encodable, Encoder};
@@ -162,14 +162,6 @@ impl fmt::Debug for RawList {
(**self).fmt(f)
}
}
-impl<'tcx, H, T: DebugWithInfcx>> DebugWithInfcx> for RawList {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
- }
-}
impl> Encodable for RawList {
#[inline]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7ff1b7998227..83f8de6b6f93 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -61,7 +61,6 @@ use rustc_span::{ExpnId, ExpnKind, Span};
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::relate::VarianceDiagInfo;
-pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
use tracing::{debug, instrument};
pub use vtable::*;
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index cc6b1d57f870..71e2e3e9f994 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -13,7 +13,7 @@ use rustc_ast_ir::visit::VisitorResult;
use rustc_hir::def::Namespace;
use rustc_span::source_map::Spanned;
use rustc_target::abi::TyAndLayout;
-use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
+use rustc_type_ir::ConstKind;
use std::fmt::{self, Debug};
@@ -83,14 +83,6 @@ impl fmt::Debug for ty::LateParamRegion {
}
}
-impl<'tcx> ty::DebugWithInfcx> for Ty<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- this.data.fmt(f)
- }
-}
impl<'tcx> fmt::Debug for Ty<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths!(fmt::Debug::fmt(self.kind(), f))
@@ -121,70 +113,33 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
}
}
-impl<'tcx> DebugWithInfcx> for Pattern<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- match &**this.data {
- ty::PatternKind::Range { start, end, include_end } => f
- .debug_struct("Pattern::Range")
- .field("start", start)
- .field("end", end)
- .field("include_end", include_end)
- .finish(),
- }
- }
-}
-
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- WithInfcx::with_no_infcx(self).fmt(f)
- }
-}
-impl<'tcx> DebugWithInfcx> for ty::consts::Expr<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- match this.data.kind {
+ match self.kind {
ty::ExprKind::Binop(op) => {
- let (lhs_ty, rhs_ty, lhs, rhs) = this.data.binop_args();
- write!(
- f,
- "({op:?}: ({:?}: {:?}), ({:?}: {:?}))",
- &this.wrap(lhs),
- &this.wrap(lhs_ty),
- &this.wrap(rhs),
- &this.wrap(rhs_ty),
- )
+ let (lhs_ty, rhs_ty, lhs, rhs) = self.binop_args();
+ write!(f, "({op:?}: ({:?}: {:?}), ({:?}: {:?}))", lhs, lhs_ty, rhs, rhs_ty,)
}
ty::ExprKind::UnOp(op) => {
- let (rhs_ty, rhs) = this.data.unop_args();
- write!(f, "({op:?}: ({:?}: {:?}))", &this.wrap(rhs), &this.wrap(rhs_ty))
+ let (rhs_ty, rhs) = self.unop_args();
+ write!(f, "({op:?}: ({:?}: {:?}))", rhs, rhs_ty)
}
ty::ExprKind::FunctionCall => {
- let (func_ty, func, args) = this.data.call_args();
+ let (func_ty, func, args) = self.call_args();
let args = args.collect::>();
- write!(f, "({:?}: {:?})(", &this.wrap(func), &this.wrap(func_ty))?;
+ write!(f, "({:?}: {:?})(", func, func_ty)?;
for arg in args.iter().rev().skip(1).rev() {
- write!(f, "{:?}, ", &this.wrap(arg))?;
+ write!(f, "{:?}, ", arg)?;
}
if let Some(arg) = args.last() {
- write!(f, "{:?}", &this.wrap(arg))?;
+ write!(f, "{:?}", arg)?;
}
write!(f, ")")
}
ty::ExprKind::Cast(kind) => {
- let (value_ty, value, to_ty) = this.data.cast_args();
- write!(
- f,
- "({kind:?}: ({:?}: {:?}), {:?})",
- &this.wrap(value),
- &this.wrap(value_ty),
- &this.wrap(to_ty)
- )
+ let (value_ty, value, to_ty) = self.cast_args();
+ write!(f, "({kind:?}: ({:?}: {:?}), {:?})", value, value_ty, to_ty)
}
}
}
@@ -192,20 +147,12 @@ impl<'tcx> DebugWithInfcx> for ty::consts::Expr<'tcx> {
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- WithInfcx::with_no_infcx(self).fmt(f)
- }
-}
-impl<'tcx> DebugWithInfcx> for ty::Const<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
// If this is a value, we spend some effort to make it look nice.
- if let ConstKind::Value(_, _) = this.data.kind() {
+ if let ConstKind::Value(_, _) = self.kind() {
return ty::tls::with(move |tcx| {
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
// entire constant.
- let lifted = tcx.lift(*this.data).unwrap();
+ let lifted = tcx.lift(*self).unwrap();
let ConstKind::Value(ty, valtree) = lifted.kind() else {
bug!("we checked that this is a valtree")
};
@@ -215,7 +162,7 @@ impl<'tcx> DebugWithInfcx> for ty::Const<'tcx> {
});
}
// Fall back to something verbose.
- write!(f, "{kind:?}", kind = &this.map(|data| data.kind()))
+ write!(f, "{:?}", self.kind())
}
}
@@ -247,32 +194,12 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
}
}
}
-impl<'tcx> DebugWithInfcx> for GenericArg<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- match this.data.unpack() {
- GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)),
- GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)),
- GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)),
- }
- }
-}
impl<'tcx> fmt::Debug for Region<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.kind())
}
}
-impl<'tcx> DebugWithInfcx> for Region<'tcx> {
- fn fmt>>(
- this: WithInfcx<'_, Infcx, &Self>,
- f: &mut core::fmt::Formatter<'_>,
- ) -> core::fmt::Result {
- write!(f, "{:?}", &this.map(|data| data.kind()))
- }
-}
///////////////////////////////////////////////////////////////////////////
// Atomic structs
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index d781fb1c297d..a65586ccdb7e 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -97,6 +97,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
if !span.at_least_rust_2024()
&& self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) =>
{
+ let sm = self.tcx.sess.source_map();
self.tcx.emit_node_span_lint(
DEPRECATED_SAFE,
self.hir_context,
@@ -105,6 +106,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
span,
function: with_no_trimmed_paths!(self.tcx.def_path_str(id)),
sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
+ indent: sm.indentation_before(span).unwrap_or_default(),
+ start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
left: span.shrink_to_lo(),
right: span.shrink_to_hi(),
},
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index cf324c03dc9f..3bd2e47976b5 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -33,6 +33,11 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe {
#[derive(Subdiagnostic)]
#[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")]
pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub {
+ pub(crate) indent: String,
+ #[suggestion_part(
+ code = "{indent}// TODO: Audit that the environment access only happens in single-threaded code.\n" // ignore-tidy-todo
+ )]
+ pub(crate) start_of_line: Span,
#[suggestion_part(code = "unsafe {{ ")]
pub(crate) left: Span,
#[suggestion_part(code = " }}")]
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index a1b8b5783491..66004179b10b 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -1,5 +1,6 @@
//! Construction of MIR from HIR.
+// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![feature(assert_matches)]
@@ -7,6 +8,7 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
mod build;
mod check_unsafety;
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 0b397a67d45c..b0808ba2067e 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,8 +1,10 @@
+// tidy-alphabetical-start
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(exact_size_is_empty)]
#![feature(let_chains)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
use rustc_middle::ty;
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 743f1cc24bee..bb6a666ff73b 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,6 +1,5 @@
-use rustc_middle::bug;
use rustc_middle::mir;
-use rustc_span::{BytePos, Span};
+use rustc_span::Span;
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
use crate::coverage::mappings;
@@ -23,7 +22,7 @@ pub(super) fn extract_refined_covspans(
let sorted_span_buckets =
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
for bucket in sorted_span_buckets {
- let refined_spans = SpansRefiner::refine_sorted_spans(bucket);
+ let refined_spans = refine_sorted_spans(bucket);
code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| {
// Each span produced by the refiner represents an ordinary code region.
mappings::CodeMapping { span, bcb }
@@ -31,58 +30,6 @@ pub(super) fn extract_refined_covspans(
}
}
-#[derive(Debug)]
-struct CurrCovspan {
- span: Span,
- bcb: BasicCoverageBlock,
-}
-
-impl CurrCovspan {
- fn new(span: Span, bcb: BasicCoverageBlock) -> Self {
- Self { span, bcb }
- }
-
- fn into_prev(self) -> PrevCovspan {
- let Self { span, bcb } = self;
- PrevCovspan { span, bcb, merged_spans: vec![span] }
- }
-}
-
-#[derive(Debug)]
-struct PrevCovspan {
- span: Span,
- bcb: BasicCoverageBlock,
- /// List of all the original spans from MIR that have been merged into this
- /// span. Mainly used to precisely skip over gaps when truncating a span.
- merged_spans: Vec,
-}
-
-impl PrevCovspan {
- fn is_mergeable(&self, other: &CurrCovspan) -> bool {
- self.bcb == other.bcb
- }
-
- fn merge_from(&mut self, other: &CurrCovspan) {
- debug_assert!(self.is_mergeable(other));
- self.span = self.span.to(other.span);
- self.merged_spans.push(other.span);
- }
-
- fn cutoff_statements_at(mut self, cutoff_pos: BytePos) -> Option {
- self.merged_spans.retain(|span| span.hi() <= cutoff_pos);
- if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() {
- self.span = self.span.with_hi(max_hi);
- }
-
- if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) }
- }
-
- fn into_refined(self) -> RefinedCovspan {
- let Self { span, bcb, merged_spans: _ } = self;
- RefinedCovspan { span, bcb }
- }
-}
-
#[derive(Debug)]
struct RefinedCovspan {
span: Span,
@@ -100,164 +47,50 @@ impl RefinedCovspan {
}
}
-/// Converts the initial set of coverage spans (one per MIR `Statement` or `Terminator`) into a
-/// minimal set of coverage spans, using the BCB CFG to determine where it is safe and useful to:
-///
-/// * Remove duplicate source code coverage regions
-/// * Merge spans that represent continuous (both in source code and control flow), non-branching
-/// execution
-struct SpansRefiner {
- /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
- /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
- sorted_spans_iter: std::vec::IntoIter,
+/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines"
+/// those spans by removing spans that overlap in unwanted ways, and by merging
+/// compatible adjacent spans.
+#[instrument(level = "debug")]
+fn refine_sorted_spans(sorted_spans: Vec) -> Vec {
+ // Holds spans that have been read from the input vector, but haven't yet
+ // been committed to the output vector.
+ let mut pending = vec![];
+ let mut refined = vec![];
- /// The current coverage span to compare to its `prev`, to possibly merge, discard,
- /// or cause `prev` to be modified or discarded.
- /// If `curr` is not discarded or merged, it becomes `prev` for the next iteration.
- some_curr: Option,
-
- /// The coverage span from a prior iteration; typically assigned from that iteration's `curr`.
- /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
- some_prev: Option,
-
- /// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
- /// will also be injected into the MIR for each BCB that has associated spans.
- refined_spans: Vec,
-}
-
-impl SpansRefiner {
- /// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
- /// them by merging compatible adjacent spans, removing redundant spans,
- /// and carving holes in spans when they overlap in unwanted ways.
- fn refine_sorted_spans(sorted_spans: Vec) -> Vec {
- let sorted_spans_len = sorted_spans.len();
- let this = Self {
- sorted_spans_iter: sorted_spans.into_iter(),
- some_curr: None,
- some_prev: None,
- refined_spans: Vec::with_capacity(sorted_spans_len),
- };
-
- this.to_refined_spans()
- }
-
- /// Iterate through the sorted coverage spans, and return the refined list of merged and
- /// de-duplicated spans.
- fn to_refined_spans(mut self) -> Vec {
- while self.next_coverage_span() {
- // For the first span we don't have `prev` set, so most of the
- // span-processing steps don't make sense yet.
- if self.some_prev.is_none() {
- debug!(" initial span");
- continue;
- }
-
- // The remaining cases assume that `prev` and `curr` are set.
- let prev = self.prev();
- let curr = self.curr();
-
- if prev.is_mergeable(curr) {
- debug!(?prev, "curr will be merged into prev");
- let curr = self.take_curr();
- self.prev_mut().merge_from(&curr);
- } else if prev.span.hi() <= curr.span.lo() {
- debug!(
- " different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
- );
- let prev = self.take_prev().into_refined();
- self.refined_spans.push(prev);
- } else {
- self.cutoff_prev_at_overlapping_curr();
- }
- }
-
- // There is usually a final span remaining in `prev` after the loop ends,
- // so add it to the output as well.
- if let Some(prev) = self.some_prev.take() {
- debug!(" AT END, adding last prev={prev:?}");
- self.refined_spans.push(prev.into_refined());
- }
-
- // Do one last merge pass, to simplify the output.
- self.refined_spans.dedup_by(|b, a| {
- if a.is_mergeable(b) {
- debug!(?a, ?b, "merging list-adjacent refined spans");
- a.merge_from(b);
- true
- } else {
+ for curr in sorted_spans {
+ pending.retain(|prev: &SpanFromMir| {
+ if prev.span.hi() <= curr.span.lo() {
+ // There's no overlap between the previous/current covspans,
+ // so move the previous one into the refined list.
+ refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
false
+ } else {
+ // Otherwise, retain the previous covspan only if it has the
+ // same BCB. This tends to discard long outer spans that enclose
+ // smaller inner spans with different control flow.
+ prev.bcb == curr.bcb
}
});
-
- self.refined_spans
+ pending.push(curr);
}
- #[track_caller]
- fn curr(&self) -> &CurrCovspan {
- self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)"))
+ // Drain the rest of the pending list into the refined list.
+ for prev in pending {
+ refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
}
- /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
- /// `curr` coverage span.
- #[track_caller]
- fn take_curr(&mut self) -> CurrCovspan {
- self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)"))
- }
-
- #[track_caller]
- fn prev(&self) -> &PrevCovspan {
- self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)"))
- }
-
- #[track_caller]
- fn prev_mut(&mut self) -> &mut PrevCovspan {
- self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)"))
- }
-
- #[track_caller]
- fn take_prev(&mut self) -> PrevCovspan {
- self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)"))
- }
-
- /// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
- fn next_coverage_span(&mut self) -> bool {
- if let Some(curr) = self.some_curr.take() {
- self.some_prev = Some(curr.into_prev());
- }
- if let Some(SpanFromMir { span, bcb, .. }) = self.sorted_spans_iter.next() {
- // This code only sees sorted spans after hole-carving, so there should
- // be no way for `curr` to start before `prev`.
- if let Some(prev) = &self.some_prev {
- debug_assert!(prev.span.lo() <= span.lo());
- }
- self.some_curr = Some(CurrCovspan::new(span, bcb));
- debug!(?self.some_prev, ?self.some_curr, "next_coverage_span");
+ // Do one last merge pass, to simplify the output.
+ debug!(?refined, "before merge");
+ refined.dedup_by(|b, a| {
+ if a.is_mergeable(b) {
+ debug!(?a, ?b, "merging list-adjacent refined spans");
+ a.merge_from(b);
true
} else {
false
}
- }
+ });
+ debug!(?refined, "after merge");
- /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
- /// statements that end before `curr.lo()` (if any), and add the portion of the
- /// combined span for those statements. Any other statements have overlapping spans
- /// that can be ignored because `curr` and/or other upcoming statements/spans inside
- /// the overlap area will produce their own counters. This disambiguation process
- /// avoids injecting multiple counters for overlapping spans, and the potential for
- /// double-counting.
- fn cutoff_prev_at_overlapping_curr(&mut self) {
- debug!(
- " different bcbs, overlapping spans, so ignore/drop pending and only add prev \
- if it has statements that end before curr; prev={:?}",
- self.prev()
- );
-
- let curr_span = self.curr().span;
- if let Some(prev) = self.take_prev().cutoff_statements_at(curr_span.lo()) {
- debug!("after cutoff, adding {prev:?}");
- self.refined_spans.push(prev);
- } else {
- debug!("prev was eliminated by cutoff");
- }
- }
+ refined
}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 551760f4703d..3c0f4e9142b1 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,8 +1,10 @@
+// tidy-alphabetical-start
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(const_type_name)]
#![feature(cow_is_borrowed)]
#![feature(decl_macro)]
+#![feature(if_let_guard)]
#![feature(impl_trait_in_assoc_type)]
#![feature(is_sorted)]
#![feature(let_chains)]
@@ -12,7 +14,7 @@
#![feature(round_char_boundary)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
-#![feature(if_let_guard)]
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index eb5f8d92603a..aa3b4cd5b678 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,5 +1,7 @@
+// tidy-alphabetical-start
#![feature(array_windows)]
#![feature(is_sorted)]
+// tidy-alphabetical-end
use rustc_hir::lang_items::LangItem;
use rustc_middle::bug;
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index b316327a262d..25cab7252a36 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -1,5 +1,6 @@
//! The main parser interface.
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
@@ -9,6 +10,7 @@
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
+// tidy-alphabetical-end
use rustc_ast as ast;
use rustc_ast::token;
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index ef71333d1c39..7e22644977d1 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -4,14 +4,16 @@
//! Parsing does not happen at runtime: structures of `std::fmt::rt` are
//! generated instead.
+// tidy-alphabetical-start
+// We want to be able to build this crate with a stable compiler,
+// so no `#![feature]` attributes should be added.
+#![deny(unstable_features)]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings)))
)]
-// We want to be able to build this crate with a stable compiler,
-// so no `#![feature]` attributes should be added.
-#![deny(unstable_features)]
+// tidy-alphabetical-end
use rustc_lexer::unescape;
pub use Alignment::*;
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 2cb3c5d8965c..a72fbdb90215 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -472,7 +472,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
&& let ItemKind::Impl(impl_ref) =
self.tcx.hir().expect_item(local_impl_id).kind
{
- if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
+ if !matches!(trait_item.kind, hir::TraitItemKind::Type(..))
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
.ty_and_all_fields_are_public
{
@@ -802,7 +802,7 @@ fn check_item<'tcx>(
// And we access the Map here to get HirId from LocalDefId
for local_def_id in local_def_ids {
// check the function may construct Self
- let mut may_construct_self = true;
+ let mut may_construct_self = false;
if let Some(fn_sig) =
tcx.hir().fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))
{
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 045a0a1525bf..a0f5f98aafc8 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -4,13 +4,15 @@
//!
//! This API is completely unstable and subject to change.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
#![feature(let_chains)]
#![feature(map_try_insert)]
+#![feature(rustdoc_internals)]
#![feature(try_blocks)]
+// tidy-alphabetical-end
use rustc_middle::query::Providers;
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 74b89546e6f9..6dd8eaf7e673 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -207,18 +207,21 @@ impl<'tcx> ReachableContext<'tcx> {
}
hir::ItemKind::Const(_, _, init) => {
- // Only things actually ending up in the final constant need to be reachable.
- // Everything else is either already available as `mir_for_ctfe`, or can't be used
- // by codegen anyway.
+ // Only things actually ending up in the final constant value are reachable
+ // for codegen. Everything else is only needed during const-eval, so even if
+ // const-eval happens in a downstream crate, all they need is
+ // `mir_for_ctfe`.
match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) {
Ok(alloc) => {
let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory();
self.propagate_from_alloc(alloc);
}
- // Reachable generic constants will be inlined into other crates
- // unconditionally, so we need to make sure that their
- // contents are also reachable.
+ // We can't figure out which value the constant will evaluate to. In
+ // lieu of that, we have to consider everything mentioned in the const
+ // initializer reachable, since it *may* end up in the final value.
Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init),
+ // If there was an error evaluating the const, nothing can be reachable
+ // via it, and anyway compilation will fail.
Err(ErrorHandled::Reported(..)) => {}
}
}
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 4155540886a6..c9590ad06b05 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -1,7 +1,9 @@
//! Analysis of patterns, notably match exhaustiveness checking.
-#![allow(rustc::untranslatable_diagnostic)]
+// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::untranslatable_diagnostic)]
+// tidy-alphabetical-end
pub mod constructor;
#[cfg(feature = "rustc")]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 698b28c626d0..fb57d42f6df1 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,10 +1,12 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
#![feature(associated_type_defaults)]
-#![feature(try_blocks)]
#![feature(let_chains)]
+#![feature(rustdoc_internals)]
+#![feature(try_blocks)]
+// tidy-alphabetical-end
mod errors;
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 85f55553af39..825c1e2e9bce 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,12 +1,14 @@
//! Support for serializing the dep-graph and reloading it.
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::potential_query_instability, unused_parens)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(min_specialization)]
#![feature(rustc_attrs)]
-#![allow(rustc::potential_query_instability, unused_parens)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
use crate::profiling_support::QueryKeyStringCache;
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index fa07877ab9f3..41222e83f7c5 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,9 +1,11 @@
+// tidy-alphabetical-start
+#![allow(rustc::potential_query_instability, internal_features)]
#![feature(assert_matches)]
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
-#![feature(min_specialization)]
#![feature(let_chains)]
-#![allow(rustc::potential_query_instability, internal_features)]
+#![feature(min_specialization)]
+// tidy-alphabetical-end
pub mod cache;
pub mod dep_graph;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 27ea7760f589..6c7afb305ba3 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -259,13 +259,18 @@ struct UnresolvedImportError {
// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
// are permitted for backward-compatibility under a deprecation lint.
-fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: NameBinding<'_>) -> bool {
+fn pub_use_of_private_extern_crate_hack(
+ import: Import<'_>,
+ binding: NameBinding<'_>,
+) -> Option {
match (&import.kind, &binding.kind) {
- (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) => {
- matches!(binding_import.kind, ImportKind::ExternCrate { .. })
- && import.expect_vis().is_public()
+ (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. })
+ if let ImportKind::ExternCrate { id, .. } = binding_import.kind
+ && import.expect_vis().is_public() =>
+ {
+ Some(id)
}
- _ => false,
+ _ => None,
}
}
@@ -275,7 +280,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> {
let import_vis = import.expect_vis().to_def_id();
let vis = if binding.vis.is_at_least(import_vis, self.tcx)
- || pub_use_of_private_extern_crate_hack(import, binding)
+ || pub_use_of_private_extern_crate_hack(import, binding).is_some()
{
import_vis
} else {
@@ -1253,12 +1258,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// All namespaces must be re-exported with extra visibility for an error to occur.
if !any_successful_reexport {
let (ns, binding) = reexport_error.unwrap();
- if pub_use_of_private_extern_crate_hack(import, binding) {
+ if let Some(extern_crate_id) = pub_use_of_private_extern_crate_hack(import, binding) {
self.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
import_id,
import.span,
- BuiltinLintDiag::PrivateExternCrateReexport(ident),
+ BuiltinLintDiag::PrivateExternCrateReexport {
+ source: ident,
+ extern_crate_span: self.tcx.source_span(self.local_def_id(extern_crate_id)),
+ },
);
} else {
if ns == TypeNS {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index ec24eac4a9d0..9eeb0da7ed2f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2041,8 +2041,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
ast::AssocItemKind::Delegation(..)
- if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)]
- .has_self =>
+ if self
+ .r
+ .delegation_fn_sigs
+ .get(&self.r.local_def_id(assoc_item.id))
+ .map_or(false, |sig| sig.has_self) =>
{
AssocSuggestion::MethodWithSelf { called }
}
diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs
index 1f73e255490b..e4792563e71e 100644
--- a/compiler/rustc_sanitizers/src/lib.rs
+++ b/compiler/rustc_sanitizers/src/lib.rs
@@ -1,7 +1,11 @@
-#![feature(let_chains)]
//! Sanitizers support for the Rust compiler.
//!
//! This crate contains the source code for providing support for the sanitizers to the Rust
//! compiler.
+
+// tidy-alphabetical-start
+#![feature(let_chains)]
+// tidy-alphabetical-end
+
pub mod cfi;
pub mod kcfi;
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 532b749f9136..f0e1630c6500 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -1,20 +1,22 @@
//! Support code for encoding and decoding types.
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::internal)]
+#![cfg_attr(test, feature(test))]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(allow(unused_variables), deny(warnings)))
)]
#![doc(rust_logo)]
-#![allow(internal_features)]
-#![feature(rustdoc_internals)]
#![feature(const_option)]
#![feature(core_intrinsics)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(ptr_sub_ptr)]
-#![cfg_attr(test, feature(test))]
-#![allow(rustc::internal)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
pub use self::serialize::{Decodable, Decoder, Encodable, Encoder};
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index cb02fbdfee9e..d93b3eac0804 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,9 +1,11 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![feature(iter_intersperse)]
#![feature(let_chains)]
+#![feature(map_many_mut)]
#![feature(option_get_or_insert_default)]
#![feature(rustc_attrs)]
-#![feature(map_many_mut)]
-#![feature(iter_intersperse)]
-#![allow(internal_features)]
+// tidy-alphabetical-end
pub mod errors;
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index ddd5ea5510a9..9f8888753061 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -6,14 +6,16 @@
//!
//! This API is still completely unstable and subject to change.
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::usage_of_ty_tykind)]
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(allow(unused_variables), deny(warnings)))
)]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
-#![allow(internal_features)]
-#![allow(rustc::usage_of_ty_tykind)]
+// tidy-alphabetical-end
pub mod rustc_internal;
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 745ae41085b2..e65d3080a0a1 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -87,11 +87,13 @@
//! virtually impossible. Thus, symbol hash generation exclusively relies on
//! DefPaths which are much more robust in the face of changes to the code base.
+// tidy-alphabetical-start
+#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
#![feature(let_chains)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index fc79c9232d1b..5713542c17d6 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -29,6 +29,7 @@ mod wasm;
mod x86;
mod x86_64;
mod x86_win64;
+mod xtensa;
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum PassMode {
@@ -903,6 +904,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
}
}
"hexagon" => hexagon::compute_abi_info(self),
+ "xtensa" => xtensa::compute_abi_info(cx, self),
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
"wasm32" | "wasm64" => {
if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm {
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs
index c6b6f66e6be8..ac68e8879f69 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx64.rs
@@ -1,23 +1,54 @@
use crate::abi::call::{ArgAbi, FnAbi, PassMode, Reg, Size, Uniform};
use crate::abi::{HasDataLayout, TyAbiInterface};
+use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
+
fn classify_ret(ret: &mut ArgAbi<'_, Ty>) {
- if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
- ret.make_indirect();
- } else {
- // FIXME: this is wrong! Need to decide which ABI we really want here.
- ret.make_direct_deprecated();
+ if ret.layout.is_aggregate() && ret.layout.is_sized() {
+ classify_aggregate(ret)
+ } else if ret.layout.size.bits() < 32 && ret.layout.is_sized() {
+ ret.extend_integer_width_to(32);
}
}
fn classify_arg(arg: &mut ArgAbi<'_, Ty>) {
- if arg.layout.is_aggregate() {
- arg.make_indirect_byval(None);
- } else if arg.layout.size.bits() < 32 {
+ if arg.layout.is_aggregate() && arg.layout.is_sized() {
+ classify_aggregate(arg)
+ } else if arg.layout.size.bits() < 32 && arg.layout.is_sized() {
arg.extend_integer_width_to(32);
}
}
+/// the pass mode used for aggregates in arg and ret position
+fn classify_aggregate(arg: &mut ArgAbi<'_, Ty>) {
+ let align_bytes = arg.layout.align.abi.bytes();
+ let size = arg.layout.size;
+
+ let reg = match align_bytes {
+ 1 => Reg::i8(),
+ 2 => Reg::i16(),
+ 4 => Reg::i32(),
+ 8 => Reg::i64(),
+ 16 => Reg::i128(),
+ _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"),
+ };
+
+ if align_bytes == size.bytes() {
+ arg.cast_to(CastTarget {
+ prefix: [Some(reg), None, None, None, None, None, None, None],
+ rest: Uniform::new(Reg::i8(), Size::from_bytes(0)),
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
+ });
+ } else {
+ arg.cast_to(Uniform::new(reg, size));
+ }
+}
+
fn classify_arg_kernel<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
Ty: TyAbiInterface<'a, C> + Copy,
diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/abi/call/xtensa.rs
new file mode 100644
index 000000000000..addbe6989254
--- /dev/null
+++ b/compiler/rustc_target/src/abi/call/xtensa.rs
@@ -0,0 +1,123 @@
+//! The Xtensa ABI implementation
+//!
+//! This ABI implementation is based on the following sources:
+//!
+//! Section 8.1.4 & 8.1.5 of the Xtensa ISA reference manual, as well as snippets from
+//! Section 2.3 from the Xtensa programmers guide.
+
+use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
+use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface};
+use crate::spec::HasTargetSpec;
+
+const NUM_ARG_GPRS: u64 = 6;
+const NUM_RET_GPRS: u64 = 4;
+const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32;
+const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32;
+
+fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+{
+ if arg.is_ignore() {
+ return;
+ }
+
+ // The rules for return and argument types are the same,
+ // so defer to `classify_arg_ty`.
+ let mut arg_gprs_left = NUM_RET_GPRS;
+ classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE);
+ // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisble reference
+ match arg.mode {
+ super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => {
+ *on_stack = false;
+ }
+ _ => {}
+ }
+}
+
+fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+{
+ assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");
+
+ // Ignore empty structs/unions.
+ if arg.layout.is_zst() {
+ return;
+ }
+
+ let size = arg.layout.size.bits();
+ let needed_align = arg.layout.align.abi.bits();
+ let mut must_use_stack = false;
+
+ // Determine the number of GPRs needed to pass the current argument
+ // according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
+ // register pairs, so may consume 3 registers.
+ let mut needed_arg_gprs = (size + 32 - 1) / 32;
+ if needed_align == 64 {
+ needed_arg_gprs += *arg_gprs_left % 2;
+ }
+
+ if needed_arg_gprs > *arg_gprs_left
+ || needed_align > 128
+ || (*arg_gprs_left < (max_size / 32) && needed_align == 128)
+ {
+ must_use_stack = true;
+ needed_arg_gprs = *arg_gprs_left;
+ }
+ *arg_gprs_left -= needed_arg_gprs;
+
+ if must_use_stack {
+ arg.make_indirect_byval(None);
+ } else {
+ if is_xtensa_aggregate(arg) {
+ // Aggregates which are <= max_size will be passed in
+ // registers if possible, so coerce to integers.
+
+ // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
+ // is required, and a 2-element `xlen` array if only `xlen` alignment is
+ // required.
+ if size <= 32 {
+ arg.cast_to(Reg::i32());
+ } else {
+ let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() };
+ let total = Size::from_bits(((size + 32 - 1) / 32) * 32);
+ arg.cast_to(Uniform::new(reg, total));
+ }
+ } else {
+ // All integral types are promoted to `xlen`
+ // width.
+ //
+ // We let the LLVM backend handle integral types >= xlen.
+ if size < 32 {
+ arg.extend_integer_width_to(32);
+ }
+ }
+ }
+}
+
+pub fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
+{
+ if !fn_abi.ret.is_ignore() {
+ classify_ret_ty(&mut fn_abi.ret);
+ }
+
+ let mut arg_gprs_left = NUM_ARG_GPRS;
+
+ for arg in fn_abi.args.iter_mut() {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE);
+ }
+}
+
+fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool {
+ match arg.layout.abi {
+ Abi::Vector { .. } => true,
+ _ => arg.layout.is_aggregate(),
+ }
+}
diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs
index d137aaa53585..28d10dcf2ff3 100644
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
@@ -35,3 +35,4 @@ pub(crate) mod windows_gnullvm;
pub(crate) mod windows_msvc;
pub(crate) mod windows_uwp_gnu;
pub(crate) mod windows_uwp_msvc;
+pub(crate) mod xtensa;
diff --git a/compiler/rustc_target/src/spec/base/xtensa.rs b/compiler/rustc_target/src/spec/base/xtensa.rs
new file mode 100644
index 000000000000..31ad09c52e4f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/base/xtensa.rs
@@ -0,0 +1,17 @@
+use crate::abi::Endian;
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+ TargetOptions {
+ os: "none".into(),
+ endian: Endian::Little,
+ c_int_width: "32".into(),
+ linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ executables: true,
+ panic_strategy: PanicStrategy::Abort,
+ relocation_model: RelocModel::Static,
+ emit_debug_gdb_scripts: false,
+ atomic_cas: false,
+ ..Default::default()
+ }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index fe07d116726b..adea2caabbe7 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1766,6 +1766,10 @@ supported_targets! {
("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
+ ("xtensa-esp32-none-elf", xtensa_esp32_none_elf),
+ ("xtensa-esp32s2-none-elf", xtensa_esp32s2_none_elf),
+ ("xtensa-esp32s3-none-elf", xtensa_esp32s3_none_elf),
+
("i686-wrs-vxworks", i686_wrs_vxworks),
("x86_64-wrs-vxworks", x86_64_wrs_vxworks),
("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index f15a87989400..3e88180012e5 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
std: None,
},
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
cpu: "generic".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index 032a29708d14..c45bc4383500 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
std: None,
},
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
cpu: "generic".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index b2bfc8e42723..69533e82c3ce 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
std: None,
},
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
cpu: "generic".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
index 02e44c187abe..bc4c5bcde5ed 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
std: None,
},
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
cpu: "generic".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
index 7cbe9f09e6ca..4c2d222b590e 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
@@ -18,6 +18,7 @@ pub fn target() -> Target {
let mut options = base::wasm::options();
options.os = "wasi".into();
+ options.env = "p1".into();
options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &["--target=wasm32-wasi"]);
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
index c592b944d44a..38af48ab2665 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
@@ -13,6 +13,7 @@ pub fn target() -> Target {
let mut options = base::wasm::options();
options.os = "wasi".into();
+ options.env = "p1".into();
options.add_pre_link_args(
LinkerFlavor::WasmLld(Cc::No),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
new file mode 100644
index 000000000000..bf5237163139
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
@@ -0,0 +1,24 @@
+use crate::spec::{base::xtensa, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "xtensa-none-elf".into(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
+ arch: "xtensa".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("Xtensa ESP32".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(false),
+ },
+
+ options: TargetOptions {
+ cpu: "esp32".into(),
+ linker: Some("xtensa-esp32-elf-gcc".into()),
+ max_atomic_width: Some(32),
+ atomic_cas: true,
+ ..xtensa::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
new file mode 100644
index 000000000000..219b2aa48c1f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
@@ -0,0 +1,23 @@
+use crate::spec::{base::xtensa, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "xtensa-none-elf".into(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
+ arch: "xtensa".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("Xtensa ESP32-S2".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(false),
+ },
+
+ options: TargetOptions {
+ cpu: "esp32-s2".into(),
+ linker: Some("xtensa-esp32s2-elf-gcc".into()),
+ max_atomic_width: Some(32),
+ ..xtensa::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
new file mode 100644
index 000000000000..632eef3a5842
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
@@ -0,0 +1,24 @@
+use crate::spec::{base::xtensa, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "xtensa-none-elf".into(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
+ arch: "xtensa".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("Xtensa ESP32-S3".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(false),
+ },
+
+ options: TargetOptions {
+ cpu: "esp32-s3".into(),
+ linker: Some("xtensa-esp32s3-elf-gcc".into()),
+ max_atomic_width: Some(32),
+ atomic_cas: true,
+ ..xtensa::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 381da6f7e2a7..50c618bb3bde 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -10,12 +10,12 @@
//!
//! This API is completely unstable and subject to change.
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![doc(rust_logo)]
-#![feature(rustdoc_internals)]
+// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
@@ -24,8 +24,10 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(never_type)]
+#![feature(rustdoc_internals)]
#![feature(type_alias_impl_trait)]
#![recursion_limit = "512"] // For rustdoc
+// tidy-alphabetical-end
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index b522022c2067..43013a01069e 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -961,15 +961,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
) -> Result<(), NoSolution> {
- let mut obligations = Vec::new();
+ let mut goals = Vec::new();
self.infcx.insert_hidden_type(
opaque_type_key,
- &ObligationCause::dummy(),
+ DUMMY_SP,
param_env,
hidden_ty,
- &mut obligations,
+ &mut goals,
)?;
- self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, goals);
Ok(())
}
@@ -980,16 +980,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
) {
- let mut obligations = Vec::new();
+ let mut goals = Vec::new();
self.infcx.add_item_bounds_for_hidden_type(
opaque_def_id,
opaque_args,
- ObligationCause::dummy(),
param_env,
hidden_ty,
- &mut obligations,
+ &mut goals,
);
- self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
+ self.add_goals(GoalSource::Misc, goals);
}
// Do something for each opaque/hidden pair defined with `def_id` in the
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 1ef2f26cd09a..fc5c71252e1c 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -12,9 +12,7 @@ use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck;
use crate::traits::{util, FulfillmentErrorCode};
-use crate::traits::{
- Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext,
-};
+use crate::traits::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Diag, EmissionGuarantee};
use rustc_hir::def::DefKind;
@@ -305,7 +303,7 @@ fn equate_impl_headers<'tcx>(
param_env: ty::ParamEnv<'tcx>,
impl1: &ty::ImplHeader<'tcx>,
impl2: &ty::ImplHeader<'tcx>,
-) -> Option> {
+) -> Option>> {
let result =
match (impl1.trait_ref, impl2.trait_ref) {
(Some(impl1_ref), Some(impl2_ref)) => infcx
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index c7da85bd1cc4..087f7fbea00b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4587,6 +4587,47 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_ => "/* value */".to_string(),
})
}
+
+ fn suggest_add_result_as_return_type(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diag<'_>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) {
+ if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
+ return;
+ }
+
+ let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
+ if let hir::Node::Item(item) = node
+ && let hir::ItemKind::Fn(sig, _, body_id) = item.kind
+ && let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
+ && self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id())
+ && let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind()
+ && l.len() == 0
+ && let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind()
+ && self.tcx.is_diagnostic_item(sym::Result, def.did())
+ {
+ let body = self.tcx.hir().body(body_id);
+ let mut sugg_spans =
+ vec![(ret_span, " -> Result<(), Box