diff --git a/Cargo.lock b/Cargo.lock
index dbe5b2ec6b75..117d8c2610e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4354,6 +4354,7 @@ dependencies = [
"rustc_target",
"smallvec",
"tracing",
+ "typed-arena",
]
[[package]]
@@ -5689,6 +5690,12 @@ dependencies = [
"rustc-hash",
]
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
[[package]]
name = "typenum"
version = "1.16.0"
diff --git a/RELEASES.md b/RELEASES.md
index a18b5264bbd6..3fb74b52292c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,128 @@
+Version 1.75.0 (2023-12-28)
+==========================
+
+
+
+Language
+--------
+
+- [Stabilize `async fn` and return-position `impl Trait` in traits.](https://github.com/rust-lang/rust/pull/115822/)
+- [Allow function pointer signatures containing `&mut T` in `const` contexts.](https://github.com/rust-lang/rust/pull/116015/)
+- [Match `usize`/`isize` exhaustively with half-open ranges.](https://github.com/rust-lang/rust/pull/116692/)
+- [Guarantee that `char` has the same size and alignment as `u32`.](https://github.com/rust-lang/rust/pull/116894/)
+- [Document that the null pointer has the 0 address.](https://github.com/rust-lang/rust/pull/116988/)
+- [Allow partially moved values in `match`.](https://github.com/rust-lang/rust/pull/103208/)
+- [Add notes about non-compliant FP behavior on 32bit x86 targets.](https://github.com/rust-lang/rust/pull/113053/)
+- [Stabilize ratified RISC-V target features.](https://github.com/rust-lang/rust/pull/116485/)
+
+
+
+Compiler
+--------
+
+- [Rework negative coherence to properly consider impls that only partly overlap.](https://github.com/rust-lang/rust/pull/112875/)
+- [Bump `COINDUCTIVE_OVERLAP_IN_COHERENCE` to deny, and warn in dependencies.](https://github.com/rust-lang/rust/pull/116493/)
+- [Consider alias bounds when computing liveness in NLL.](https://github.com/rust-lang/rust/pull/116733/)
+- [Add the V (vector) extension to the `riscv64-linux-android` target spec.](https://github.com/rust-lang/rust/pull/116618/)
+- [Automatically enable cross-crate inlining for small functions](https://github.com/rust-lang/rust/pull/116505)
+- Add several new tier 3 targets:
+ - [`csky-unknown-linux-gnuabiv2hf`](https://github.com/rust-lang/rust/pull/117049/)
+ - [`i586-unknown-netbsd`](https://github.com/rust-lang/rust/pull/117170/)
+ - [`mipsel-unknown-netbsd`](https://github.com/rust-lang/rust/pull/117356/)
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+
+
+Libraries
+---------
+
+- [Override `Waker::clone_from` to avoid cloning `Waker`s unnecessarily.](https://github.com/rust-lang/rust/pull/96979/)
+- [Implement `BufRead` for `VecDeque`.](https://github.com/rust-lang/rust/pull/110604/)
+- [Implement `FusedIterator` for `DecodeUtf16` when the inner iterator does.](https://github.com/rust-lang/rust/pull/110729/)
+- [Implement `Not, Bit{And,Or}{,Assign}` for IP addresses.](https://github.com/rust-lang/rust/pull/113747/)
+- [Implement `Default` for `ExitCode`.](https://github.com/rust-lang/rust/pull/114589/)
+- [Guarantee representation of None in NPO](https://github.com/rust-lang/rust/pull/115333/)
+- [Document when atomic loads are guaranteed read-only.](https://github.com/rust-lang/rust/pull/115577/)
+- [Broaden the consequences of recursive TLS initialization.](https://github.com/rust-lang/rust/pull/116172/)
+- [Windows: Support sub-millisecond sleep.](https://github.com/rust-lang/rust/pull/116461/)
+- [Fix generic bound of `str::SplitInclusive`'s `DoubleEndedIterator` impl](https://github.com/rust-lang/rust/pull/100806/)
+- [Fix exit status / wait status on non-Unix `cfg(unix)` platforms.](https://github.com/rust-lang/rust/pull/115108/)
+
+
+
+Stabilized APIs
+---------------
+
+- [`Atomic*::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.from_ptr)
+- [`FileTimes`](https://doc.rust-lang.org/stable/std/fs/struct.FileTimes.html)
+- [`FileTimesExt`](https://doc.rust-lang.org/stable/std/os/windows/fs/trait.FileTimesExt.html)
+- [`File::set_modified`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_modified)
+- [`File::set_times`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_times)
+- [`IpAddr::to_canonical`](https://doc.rust-lang.org/stable/core/net/enum.IpAddr.html#method.to_canonical)
+- [`Ipv6Addr::to_canonical`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.to_canonical)
+- [`Option::as_slice`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.as_slice)
+- [`Option::as_mut_slice`](https://doc.rust-lang.org/stable/core/option/enum.Option.html#method.as_mut_slice)
+- [`pointer::byte_add`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.byte_add)
+- [`pointer::byte_offset`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.byte_offset)
+- [`pointer::byte_offset_from`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.byte_offset_from)
+- [`pointer::byte_sub`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.byte_sub)
+- [`pointer::wrapping_byte_add`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.wrapping_byte_add)
+- [`pointer::wrapping_byte_offset`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.wrapping_byte_offset)
+- [`pointer::wrapping_byte_sub`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.wrapping_byte_sub)
+
+These APIs are now stable in const contexts:
+
+- [`Ipv6Addr::to_ipv4_mapped`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.to_ipv4_mapped)
+- [`MaybeUninit::assume_init_read`](https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#method.assume_init_read)
+- [`MaybeUninit::zeroed`](https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#method.zeroed)
+- [`mem::discriminant`](https://doc.rust-lang.org/stable/core/mem/fn.discriminant.html)
+- [`mem::zeroed`](https://doc.rust-lang.org/stable/core/mem/fn.zeroed.html)
+
+
+
+Cargo
+-----
+
+- [Add new packages to `[workspace.members]` automatically.](https://github.com/rust-lang/cargo/pull/12779/)
+- [Allow version-less `Cargo.toml` manifests.](https://github.com/rust-lang/cargo/pull/12786/)
+- [Make browser links out of HTML file paths.](https://github.com/rust-lang/cargo/pull/12889)
+
+
+
+Rustdoc
+-------
+
+- [Accept less invalid Rust in rustdoc.](https://github.com/rust-lang/rust/pull/117450/)
+- [Document lack of object safety on affected traits.](https://github.com/rust-lang/rust/pull/113241/)
+- [Hide `#[repr(transparent)]` if it isn't part of the public ABI.](https://github.com/rust-lang/rust/pull/115439/)
+- [Show enum discriminant if it is a C-like variant.](https://github.com/rust-lang/rust/pull/116142/)
+
+
+
+Compatibility Notes
+-------------------
+
+- [FreeBSD targets now require at least version 12.](https://github.com/rust-lang/rust/pull/114521/)
+- [Formally demote tier 2 MIPS targets to tier 3.](https://github.com/rust-lang/rust/pull/115238/)
+- [Make misalignment a hard error in `const` contexts.](https://github.com/rust-lang/rust/pull/115524/)
+- [Fix detecting references to packed unsized fields.](https://github.com/rust-lang/rust/pull/115583/)
+- [Remove support for compiler plugins.](https://github.com/rust-lang/rust/pull/116412/)
+
+
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Optimize `librustc_driver.so` with BOLT.](https://github.com/rust-lang/rust/pull/116352/)
+- [Enable parallel rustc front end in dev and nightly builds.](https://github.com/rust-lang/rust/pull/117435/)
+- [Distribute `rustc-codegen-cranelift` as rustup component on the nightly channel.](https://github.com/rust-lang/rust/pull/81746/)
+
Version 1.74.1 (2023-12-07)
===========================
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9d543563c0f9..a121b5a9bed3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2788,7 +2788,11 @@ pub enum VariantData {
/// Struct variant.
///
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
- Struct(ThinVec, bool),
+ Struct {
+ fields: ThinVec,
+ // FIXME: investigate making this a `Option`
+ recovered: bool,
+ },
/// Tuple variant.
///
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -2803,7 +2807,7 @@ impl VariantData {
/// Return the fields of this variant.
pub fn fields(&self) -> &[FieldDef] {
match self {
- VariantData::Struct(fields, ..) | VariantData::Tuple(fields, _) => fields,
+ VariantData::Struct { fields, .. } | VariantData::Tuple(fields, _) => fields,
_ => &[],
}
}
@@ -2811,7 +2815,7 @@ impl VariantData {
/// Return the `NodeId` of this variant's constructor, if it has one.
pub fn ctor_node_id(&self) -> Option {
match *self {
- VariantData::Struct(..) => None,
+ VariantData::Struct { .. } => None,
VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id),
}
}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 10b2025f9378..557ae02a8f9e 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -976,7 +976,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis:
pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) {
match vdata {
- VariantData::Struct(fields, ..) => {
+ VariantData::Struct { fields, .. } => {
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
}
VariantData::Tuple(fields, id) => {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index f042f46e59c9..993ddf00eb5b 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -1,7 +1,6 @@
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
use rustc_hir::intravisit::Visitor;
use rustc_hir::*;
use rustc_index::{Idx, IndexVec};
@@ -17,7 +16,7 @@ struct NodeCollector<'a, 'hir> {
/// Outputs
nodes: IndexVec>>,
- parenting: FxHashMap,
+ parenting: LocalDefIdMap,
/// The parent of this node
parent_node: hir::ItemLocalId,
@@ -30,7 +29,7 @@ pub(super) fn index_hir<'hir>(
tcx: TyCtxt<'hir>,
item: hir::OwnerNode<'hir>,
bodies: &SortedMap>,
-) -> (IndexVec>>, FxHashMap) {
+) -> (IndexVec>>, LocalDefIdMap) {
let mut nodes = IndexVec::new();
// This node's parent should never be accessed: the owner's parent is computed by the
// hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
@@ -42,7 +41,7 @@ pub(super) fn index_hir<'hir>(
parent_node: ItemLocalId::new(0),
nodes,
bodies,
- parenting: FxHashMap::default(),
+ parenting: Default::default(),
};
match item {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 83452c222802..5bddbe5f4177 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -661,11 +661,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
vdata: &VariantData,
) -> hir::VariantData<'hir> {
match vdata {
- VariantData::Struct(fields, recovered) => hir::VariantData::Struct(
- self.arena
+ VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
+ fields: self
+ .arena
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
- *recovered,
- ),
+ recovered: *recovered,
+ },
VariantData::Tuple(fields, id) => {
let ctor_id = self.lower_node_id(*id);
self.alias_attrs(ctor_id, parent_id);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 96ed3eee02ed..47b929816260 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -44,23 +44,23 @@ extern crate tracing;
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use rustc_ast::node_id::NodeMap;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{DiagnosticArgFromDisplay, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
+use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::span_bug;
-use rustc_middle::ty::{ResolverAstLowering, TyCtxt, Visibility};
+use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{DesugaringKind, Span, DUMMY_SP};
@@ -119,13 +119,13 @@ struct LoweringContext<'a, 'hir> {
current_hir_id_owner: hir::OwnerId,
item_local_id_counter: hir::ItemLocalId,
- trait_map: FxHashMap>,
+ trait_map: ItemLocalMap>,
impl_trait_defs: Vec>,
impl_trait_bounds: Vec>,
/// NodeIds that are lowered inside the current HIR owner.
- node_id_to_local_id: FxHashMap,
+ node_id_to_local_id: NodeMap,
allow_try_trait: Lrc<[Symbol]>,
allow_gen_future: Lrc<[Symbol]>,
@@ -135,7 +135,7 @@ struct LoweringContext<'a, 'hir> {
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
/// field from the original parameter 'a to the new parameter 'a1.
- generics_def_id_map: Vec>,
+ generics_def_id_map: Vec>,
host_param_id: Option,
}
@@ -380,7 +380,7 @@ enum AstOwner<'a> {
}
fn index_crate<'a>(
- node_id_to_def_id: &FxHashMap,
+ node_id_to_def_id: &NodeMap,
krate: &'a Crate,
) -> IndexVec> {
let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
@@ -390,7 +390,7 @@ fn index_crate<'a>(
return indexer.index;
struct Indexer<'s, 'a> {
- node_id_to_def_id: &'s FxHashMap,
+ node_id_to_def_id: &'s NodeMap,
index: IndexVec>,
}
@@ -642,7 +642,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// `'a` declared on the TAIT, instead of the function.
fn with_remapping(
&mut self,
- remap: FxHashMap,
+ remap: LocalDefIdMap,
f: impl FnOnce(&mut Self) -> R,
) -> R {
self.generics_def_id_map.push(remap);
@@ -1651,13 +1651,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
debug!(?opaque_ty_def_id);
- // Meaningless, but provided so that all items have visibilities.
- let parent_mod = self.tcx.parent_module_from_def_id(opaque_ty_def_id).to_def_id();
- self.tcx.feed_local_def_id(opaque_ty_def_id).visibility(Visibility::Restricted(parent_mod));
-
// Map from captured (old) lifetime to synthetic (new) lifetime.
// Used to resolve lifetimes in the bounds of the opaque.
- let mut captured_to_synthesized_mapping = FxHashMap::default();
+ let mut captured_to_synthesized_mapping = LocalDefIdMap::default();
// List of (early-bound) synthetic lifetimes that are owned by the opaque.
// This is used to create the `hir::Generics` owned by the opaque.
let mut synthesized_lifetime_definitions = vec![];
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 790b583134c0..1c5ad820bd63 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -117,13 +117,13 @@ ast_passes_fn_without_body =
free function without a body
.suggestion = provide a definition for the function
+ast_passes_forbidden_bound =
+ bounds cannot be used in this context
+
ast_passes_forbidden_default =
`default` is only allowed on items in trait impls
.label = `default` because of this
-ast_passes_forbidden_lifetime_bound =
- lifetime bounds cannot be used in this context
-
ast_passes_forbidden_non_lifetime_param =
only lifetime parameters can be used in this context
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index e0a7b06c0509..887cb434a60c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1000,7 +1000,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
ItemKind::Struct(vdata, generics) => match vdata {
- VariantData::Struct(fields, ..) => {
+ VariantData::Struct { fields, .. } => {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
@@ -1016,7 +1016,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
}
match vdata {
- VariantData::Struct(fields, ..) => {
+ VariantData::Struct { fields, .. } => {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 4283fc7c07d1..304c5c1bde97 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -52,8 +52,8 @@ pub struct TraitFnConst {
}
#[derive(Diagnostic)]
-#[diag(ast_passes_forbidden_lifetime_bound)]
-pub struct ForbiddenLifetimeBound {
+#[diag(ast_passes_forbidden_bound)]
+pub struct ForbiddenBound {
#[primary_span]
pub spans: Vec,
}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 142cdd15e64a..1cc9309c45c0 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -152,8 +152,8 @@ impl<'a> PostExpansionVisitor<'a> {
}
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
- // Check only lifetime parameters are present and that the lifetime
- // parameters that are present have no bounds.
+ // Check only lifetime parameters are present and that the
+ // generic parameters that are present have no bounds.
let non_lt_param_spans = params.iter().filter_map(|param| match param.kind {
ast::GenericParamKind::Lifetime { .. } => None,
_ => Some(param.ident.span),
@@ -164,10 +164,11 @@ impl<'a> PostExpansionVisitor<'a> {
non_lt_param_spans,
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
);
+
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
- self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
+ self.sess.emit_err(errors::ForbiddenBound { spans });
}
}
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index ea5d22a34487..405ccc722d4b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -500,7 +500,7 @@ impl<'a> State<'a> {
self.end();
self.end(); // Close the outer-box.
}
- ast::VariantData::Struct(fields, ..) => {
+ ast::VariantData::Struct { fields, .. } => {
self.print_where_clause(&generics.where_clause);
self.print_record_struct_body(fields, span);
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b308cd82e547..948221e94073 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -674,13 +674,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// eagerly.
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
- self.check_type_tests(
- infcx,
- param_env,
- body,
- outlives_requirements.as_mut(),
- &mut errors_buffer,
- );
+ self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
debug!(?errors_buffer);
debug!(?outlives_requirements);
@@ -938,7 +932,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn check_type_tests(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec>>,
errors_buffer: &mut RegionErrors<'tcx>,
@@ -956,7 +949,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let generic_ty = type_test.generic_kind.to_ty(tcx);
if self.eval_verify_bound(
infcx,
- param_env,
generic_ty,
type_test.lower_bound,
&type_test.verify_bound,
@@ -967,7 +959,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
if self.try_promote_type_test(
infcx,
- param_env,
body,
type_test,
propagated_outlives_requirements,
@@ -1025,7 +1016,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn try_promote_type_test(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
propagated_outlives_requirements: &mut Vec>,
@@ -1087,7 +1077,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// where `ur` is a local bound -- we are sometimes in a
// position to prove things that our caller cannot. See
// #53570 for an example.
- if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
+ if self.eval_verify_bound(infcx, generic_ty, ur, &type_test.verify_bound) {
continue;
}
@@ -1270,7 +1260,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_verify_bound(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>,
@@ -1279,7 +1268,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match verify_bound {
VerifyBound::IfEq(verify_if_eq_b) => {
- self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
+ self.eval_if_eq(infcx, generic_ty, lower_bound, *verify_if_eq_b)
}
VerifyBound::IsEmpty => {
@@ -1293,11 +1282,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
- self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
+ self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound)
}),
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
- self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
+ self.eval_verify_bound(infcx, generic_ty, lower_bound, verify_bound)
}),
}
}
@@ -1305,19 +1294,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_if_eq(
&self,
infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
) -> bool {
let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
- match test_type_match::extract_verify_if_eq(
- infcx.tcx,
- param_env,
- &verify_if_eq_b,
- generic_ty,
- ) {
+ match test_type_match::extract_verify_if_eq(infcx.tcx, &verify_if_eq_b, generic_ty) {
Some(r) => {
let r_vid = self.to_region_vid(r);
self.eval_outlives(r_vid, lower_bound)
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 1649cc76c8d5..467fa5a2b15e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -188,7 +188,7 @@ fn cs_clone(
}
let expr = match *vdata {
- VariantData::Struct(..) => {
+ VariantData::Struct { .. } => {
let fields = all_fields
.iter()
.map(|field| {
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 30c9b35bbacd..50ea86288615 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -71,7 +71,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
(false, 0)
}
ast::VariantData::Tuple(..) => (false, 1),
- ast::VariantData::Struct(..) => (true, 2),
+ ast::VariantData::Struct { .. } => (true, 2),
};
// The number of fields that can be handled without an array.
@@ -226,7 +226,7 @@ fn show_fieldless_enum(
debug_assert!(fields.is_empty());
cx.pat_tuple_struct(span, variant_path, ThinVec::new())
}
- ast::VariantData::Struct(fields, _) => {
+ ast::VariantData::Struct { fields, .. } => {
debug_assert!(fields.is_empty());
cx.pat_struct(span, variant_path, ThinVec::new())
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 23502b6eafc6..841cac781499 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1485,7 +1485,7 @@ impl<'a> TraitDef<'a> {
let struct_path = struct_path.clone();
match *struct_def {
- VariantData::Struct(..) => {
+ VariantData::Struct { .. } => {
let field_pats = pieces_iter
.map(|(sp, ident, pat)| {
if ident.is_none() {
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 1a38d5967f4b..cb7b2454cd5e 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -232,6 +232,13 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
if runner.is_native {
let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
test_cmd.arg("-q");
+ // FIXME remove after portable-simd update
+ test_cmd
+ .arg("--")
+ .arg("--skip")
+ .arg("core_simd::swizzle::simd_swizzle")
+ .arg("--skip")
+ .arg("core_simd::vector::Simd::lanes");
spawn_and_wait(test_cmd);
}
}),
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index afc51a47f140..1d51b499c8ba 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -337,17 +337,6 @@ fn main() {
static REF2: &u8 = REF1;
assert_eq!(*REF1, *REF2);
- extern "C" {
- type A;
- }
-
- fn main() {
- let x: &A = unsafe { &*(1usize as *const A) };
-
- assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0);
- assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1);
- }
-
#[repr(simd)]
struct V([f64; 2]);
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch
new file mode 100644
index 000000000000..b8c0783f5243
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Enable-the-exposed_provenance-feature.patch
@@ -0,0 +1,22 @@
+From a101a43b795431ce617e7782afb451f4853afc00 Mon Sep 17 00:00:00 2001
+From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
+Date: Thu, 7 Dec 2023 14:51:35 +0000
+Subject: [PATCH] Enable the exposed_provenance feature
+
+---
+ crates/core_simd/tests/pointers.rs | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/crates/core_simd/tests/pointers.rs b/crates/core_simd/tests/pointers.rs
+index 0ae8f83..06620d6 100644
+--- a/crates/core_simd/tests/pointers.rs
++++ b/crates/core_simd/tests/pointers.rs
+@@ -1,4 +1,4 @@
+-#![feature(portable_simd, strict_provenance)]
++#![feature(exposed_provenance, portable_simd, strict_provenance)]
+
+ use core_simd::simd::{Simd, SimdConstPtr, SimdMutPtr};
+
+--
+2.34.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
index 8a690bada0df..8e213f71c3f3 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
@@ -36,15 +36,18 @@ dependencies = [
[[package]]
name = "allocator-api2"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9"
+checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "cc"
-version = "1.0.79"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
[[package]]
name = "cfg-if"
@@ -58,9 +61,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
-version = "0.1.103"
+version = "0.1.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3b73c3443a5fd2438d7ba4853c64e4c8efc2404a9e28a9234cc2d5eebc6c242"
+checksum = "99c3f9035afc33f4358773239573f7d121099856753e1bbd2a6a5207098fc741"
dependencies = [
"cc",
"rustc-std-workspace-core",
@@ -124,9 +127,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.28.0"
+version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
@@ -135,9 +138,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.14.0"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"allocator-api2",
"compiler_builtins",
@@ -147,9 +150,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
@@ -167,9 +170,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.5.0"
+version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@@ -189,9 +192,9 @@ dependencies = [
[[package]]
name = "object"
-version = "0.32.0"
+version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"compiler_builtins",
"memchr",
@@ -241,9 +244,9 @@ dependencies = [
[[package]]
name = "r-efi"
-version = "4.2.0"
+version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "575fc2d9b3da54adbdfaddf6eca48fec256d977c8630a1750b8991347d1ac911"
+checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@@ -402,9 +405,9 @@ dependencies = [
[[package]]
name = "unicode-width"
-version = "0.1.10"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@@ -419,6 +422,18 @@ dependencies = [
"compiler_builtins",
"core",
"libc",
+ "unwinding",
+]
+
+[[package]]
+name = "unwinding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b"
+dependencies = [
+ "compiler_builtins",
+ "gimli",
+ "rustc-std-workspace-core",
]
[[package]]
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2997816d96c7..4ba08f1af44b 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-11-25"
+channel = "nightly-2023-12-19"
components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index a299b6de6b1c..7d7ffdadc7f7 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -44,6 +44,7 @@ rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
# vendor intrinsics
rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
+rm tests/ui/simd/masked-load-store.rs
# exotic linkages
rm tests/ui/issues/issue-33992.rs # unsupported linkages
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 8b0dc6110752..df40a5eb475c 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -353,7 +353,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
fx,
rustc_hir::LangItem::PanicBoundsCheck,
&[index, len, location],
- source_info.span,
+ Some(source_info.span),
);
}
AssertKind::MisalignedPointerDereference { ref required, ref found } => {
@@ -365,7 +365,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
fx,
rustc_hir::LangItem::PanicMisalignedPointerDereference,
&[required, found, location],
- source_info.span,
+ Some(source_info.span),
);
}
_ => {
@@ -945,19 +945,19 @@ pub(crate) fn codegen_panic<'tcx>(
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
let args = [msg_ptr, msg_len, location];
- codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
+ codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, Some(source_info.span));
}
pub(crate) fn codegen_panic_nounwind<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
msg_str: &str,
- source_info: mir::SourceInfo,
+ span: Option,
) {
let msg_ptr = fx.anonymous_str(msg_str);
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
let args = [msg_ptr, msg_len];
- codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
+ codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, span);
}
pub(crate) fn codegen_unwind_terminate<'tcx>(
@@ -967,16 +967,16 @@ pub(crate) fn codegen_unwind_terminate<'tcx>(
) {
let args = [];
- codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span);
+ codegen_panic_inner(fx, reason.lang_item(), &args, Some(source_info.span));
}
fn codegen_panic_inner<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
lang_item: rustc_hir::LangItem,
args: &[Value],
- span: Span,
+ span: Option,
) {
- let def_id = fx.tcx.require_lang_item(lang_item, Some(span));
+ let def_id = fx.tcx.require_lang_item(lang_item, span);
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
let symbol_name = fx.tcx.symbol_name(instance).name;
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 63562d335089..bd19a7ed0592 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -98,11 +98,15 @@ fn clif_pair_type_from_ty<'tcx>(
/// Is a pointer to this type a fat ptr?
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
- let ptr_ty = Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
- match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi {
- Abi::Scalar(_) => false,
- Abi::ScalarPair(_, _) => true,
- abi => unreachable!("Abi of ptr to {:?} is {:?}???", ty, abi),
+ if ty.is_sized(tcx, ParamEnv::reveal_all()) {
+ return false;
+ }
+
+ let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all());
+ match tail.kind() {
+ ty::Foreign(..) => false,
+ ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
+ _ => bug!("unexpected unsized tail: {:?}", tail),
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index bfeeb117ff5b..68126f124242 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -487,13 +487,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
- let size = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
- let (_ptr, info) = ptr.load_scalar_pair(fx);
- let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
- size
+ let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
+ Some(ptr.load_scalar_pair(fx).1)
} else {
- fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64)
+ None
};
+ let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta);
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
}
sym::min_align_of_val => {
@@ -502,13 +501,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
- let align = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
- let (_ptr, info) = ptr.load_scalar_pair(fx);
- let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
- align
+ let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
+ Some(ptr.load_scalar_pair(fx).1)
} else {
- fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
+ None
};
+ let (_size, align) = crate::unsize::size_and_align_of(fx, layout, meta);
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
}
@@ -688,7 +686,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
}
})
});
- crate::base::codegen_panic_nounwind(fx, &msg_str, source_info);
+ crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span));
return;
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index c6133f2b35cf..f777e11371f1 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -2,6 +2,9 @@
//!
//! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize`
+use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
+
+use crate::base::codegen_panic_nounwind;
use crate::prelude::*;
// Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/base.rs#L159-L307
@@ -187,63 +190,113 @@ pub(crate) fn coerce_dyn_star<'tcx>(
// Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs
-pub(crate) fn size_and_align_of_dst<'tcx>(
+pub(crate) fn size_and_align_of<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
layout: TyAndLayout<'tcx>,
- info: Value,
+ info: Option,
) -> (Value, Value) {
- assert!(layout.is_unsized() || layout.abi == Abi::Uninhabited);
- match layout.ty.kind() {
+ if layout.is_sized() {
+ return (
+ fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64),
+ fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64),
+ );
+ }
+
+ let ty = layout.ty;
+ match ty.kind() {
ty::Dynamic(..) => {
// load size/align from vtable
- (crate::vtable::size_of_obj(fx, info), crate::vtable::min_align_of_obj(fx, info))
+ (
+ crate::vtable::size_of_obj(fx, info.unwrap()),
+ crate::vtable::min_align_of_obj(fx, info.unwrap()),
+ )
}
ty::Slice(_) | ty::Str => {
let unit = layout.field(fx, 0);
// The info in this case is the length of the str, so the size is that
// times the unit size.
(
- fx.bcx.ins().imul_imm(info, unit.size.bytes() as i64),
+ fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64),
fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64),
)
}
- _ => {
+ ty::Foreign(_) => {
+ let trap_block = fx.bcx.create_block();
+ let true_ = fx.bcx.ins().iconst(types::I8, 1);
+ let next_block = fx.bcx.create_block();
+ fx.bcx.ins().brif(true_, trap_block, &[], next_block, &[]);
+ fx.bcx.seal_block(trap_block);
+ fx.bcx.seal_block(next_block);
+ fx.bcx.switch_to_block(trap_block);
+
+ // `extern` type. We cannot compute the size, so panic.
+ let msg_str = with_no_visible_paths!({
+ with_no_trimmed_paths!({
+ format!("attempted to compute the size or alignment of extern type `{ty}`")
+ })
+ });
+
+ codegen_panic_nounwind(fx, &msg_str, None);
+
+ fx.bcx.switch_to_block(next_block);
+
+ // This function does not return so we can now return whatever we want.
+ let size = fx.bcx.ins().iconst(fx.pointer_type, 42);
+ let align = fx.bcx.ins().iconst(fx.pointer_type, 42);
+ (size, align)
+ }
+ ty::Adt(..) | ty::Tuple(..) => {
// First get the size of all statically known fields.
// Don't use size_of because it also rounds up to alignment, which we
// want to avoid, as the unsized field's alignment could be smaller.
assert!(!layout.ty.is_simd());
let i = layout.fields.count() - 1;
- let sized_size = layout.fields.offset(i).bytes();
+ let unsized_offset_unadjusted = layout.fields.offset(i).bytes();
+ let unsized_offset_unadjusted =
+ fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64);
let sized_align = layout.align.abi.bytes();
let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64);
// Recurse to get the size of the dynamically sized field (must be
// the last field).
let field_layout = layout.field(fx, i);
- let (unsized_size, mut unsized_align) = size_and_align_of_dst(fx, field_layout, info);
+ let (unsized_size, mut unsized_align) = size_and_align_of(fx, field_layout, info);
- // FIXME (#26403, #27023): We should be adding padding
- // to `sized_size` (to accommodate the `unsized_align`
- // required of the unsized field that follows) before
- // summing it with `sized_size`. (Note that since #26403
- // is unfixed, we do not yet add the necessary padding
- // here. But this is where the add would go.)
+ // # First compute the dynamic alignment
- // Return the sum of sizes and max of aligns.
- let size = fx.bcx.ins().iadd_imm(unsized_size, sized_size as i64);
-
- // Packed types ignore the alignment of their fields.
- if let ty::Adt(def, _) = layout.ty.kind() {
- if def.repr().packed() {
- unsized_align = sized_align;
+ // For packed types, we need to cap the alignment.
+ if let ty::Adt(def, _) = ty.kind() {
+ if let Some(packed) = def.repr().pack {
+ if packed.bytes() == 1 {
+ // We know this will be capped to 1.
+ unsized_align = fx.bcx.ins().iconst(fx.pointer_type, 1);
+ } else {
+ // We have to dynamically compute `min(unsized_align, packed)`.
+ let packed = fx.bcx.ins().iconst(fx.pointer_type, packed.bytes() as i64);
+ let cmp = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, unsized_align, packed);
+ unsized_align = fx.bcx.ins().select(cmp, unsized_align, packed);
+ }
}
}
// Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two).
let cmp = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, sized_align, unsized_align);
- let align = fx.bcx.ins().select(cmp, sized_align, unsized_align);
+ let full_align = fx.bcx.ins().select(cmp, sized_align, unsized_align);
+
+ // # Then compute the dynamic size
+
+ // The full formula for the size would be:
+ // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
+ // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
+ // However, `unsized_size` is a multiple of `unsized_align`.
+ // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align);
+ // Furthermore, `align >= unsized_align`, and therefore we only need to do:
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align);
+
+ let full_size = fx.bcx.ins().iadd(unsized_offset_unadjusted, unsized_size);
// Issue #27023: must add any necessary padding to `size`
// (to make it a multiple of `align`) before returning it.
@@ -255,12 +308,13 @@ pub(crate) fn size_and_align_of_dst<'tcx>(
// emulated via the semi-standard fast bit trick:
//
// `(size + (align-1)) & -align`
- let addend = fx.bcx.ins().iadd_imm(align, -1);
- let add = fx.bcx.ins().iadd(size, addend);
- let neg = fx.bcx.ins().ineg(align);
- let size = fx.bcx.ins().band(add, neg);
+ let addend = fx.bcx.ins().iadd_imm(full_align, -1);
+ let add = fx.bcx.ins().iadd(full_size, addend);
+ let neg = fx.bcx.ins().ineg(full_align);
+ let full_size = fx.bcx.ins().band(add, neg);
- (size, align)
+ (full_size, full_align)
}
+ _ => bug!("size_and_align_of_dst: {ty} not supported"),
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index f52f59716a8a..567a5669d496 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -20,34 +20,36 @@ fn codegen_field<'tcx>(
(base.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap()), field_layout)
};
- if let Some(extra) = extra {
- if field_layout.is_sized() {
- return simple(fx);
- }
- match field_layout.ty.kind() {
- ty::Slice(..) | ty::Str | ty::Foreign(..) => simple(fx),
- ty::Adt(def, _) if def.repr().packed() => {
- assert_eq!(layout.align.abi.bytes(), 1);
- simple(fx)
- }
- _ => {
- // We have to align the offset for DST's
- let unaligned_offset = field_offset.bytes();
- let (_, unsized_align) =
- crate::unsize::size_and_align_of_dst(fx, field_layout, extra);
+ if field_layout.is_sized() {
+ return simple(fx);
+ }
+ match field_layout.ty.kind() {
+ ty::Slice(..) | ty::Str => simple(fx),
+ _ => {
+ let unaligned_offset = field_offset.bytes();
- let one = fx.bcx.ins().iconst(fx.pointer_type, 1);
- let align_sub_1 = fx.bcx.ins().isub(unsized_align, one);
- let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64);
- let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
- let and_rhs = fx.bcx.ins().isub(zero, unsized_align);
- let offset = fx.bcx.ins().band(and_lhs, and_rhs);
+ // Get the alignment of the field
+ let (_, mut unsized_align) = crate::unsize::size_and_align_of(fx, field_layout, extra);
- (base.offset_value(fx, offset), field_layout)
+ // For packed types, we need to cap alignment.
+ if let ty::Adt(def, _) = layout.ty.kind() {
+ if let Some(packed) = def.repr().pack {
+ let packed = fx.bcx.ins().iconst(fx.pointer_type, packed.bytes() as i64);
+ let cmp = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, unsized_align, packed);
+ unsized_align = fx.bcx.ins().select(cmp, unsized_align, packed);
+ }
}
+
+ // Bump the unaligned offset up to the appropriate alignment
+ let one = fx.bcx.ins().iconst(fx.pointer_type, 1);
+ let align_sub_1 = fx.bcx.ins().isub(unsized_align, one);
+ let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64);
+ let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
+ let and_rhs = fx.bcx.ins().isub(zero, unsized_align);
+ let offset = fx.bcx.ins().band(and_lhs, and_rhs);
+
+ (base.offset_value(fx, offset), field_layout)
}
- } else {
- simple(fx)
}
}
@@ -731,13 +733,8 @@ impl<'tcx> CPlace<'tcx> {
};
let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
- if field_layout.is_unsized() {
- if let ty::Foreign(_) = field_layout.ty.kind() {
- assert!(extra.is_none());
- CPlace::for_ptr(field_ptr, field_layout)
- } else {
- CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout)
- }
+ if has_ptr_meta(fx.tcx, field_layout.ty) {
+ CPlace::for_ptr_with_extra(field_ptr, extra.unwrap(), field_layout)
} else {
CPlace::for_ptr(field_ptr, field_layout)
}
diff --git a/compiler/rustc_codegen_cranelift/y.cmd b/compiler/rustc_codegen_cranelift/y.cmd
new file mode 100644
index 000000000000..e9b688645a4d
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/y.cmd
@@ -0,0 +1,9 @@
+@echo off
+echo [BUILD] build system >&2
+mkdir build 2>nul
+rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021 || goto :error
+build\y.exe %* || goto :error
+goto :EOF
+
+:error
+exit /b
diff --git a/compiler/rustc_codegen_cranelift/y.ps1 b/compiler/rustc_codegen_cranelift/y.ps1
new file mode 100644
index 000000000000..02ef0fcbd50f
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/y.ps1
@@ -0,0 +1,12 @@
+$ErrorActionPreference = "Stop"
+
+$host.ui.WriteErrorLine("[BUILD] build system")
+New-Item -ItemType Directory -Force -Path build | Out-Null
+& rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+& build\y.exe $args
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 01d1b1059b91..a5bd10ecb34b 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -278,13 +278,13 @@ impl CguReuseTracker {
if error {
let at_least = if at_least { 1 } else { 0 };
- errors::IncorrectCguReuseType {
+ sess.emit_err(errors::IncorrectCguReuseType {
span: *error_span,
cgu_user_name,
actual_reuse,
expected_reuse,
at_least,
- };
+ });
}
} else {
sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index e8c58f6b6f80..794cbd315b79 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -132,7 +132,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
offset: Size,
) -> Self {
let alloc_align = alloc.inner().align;
- assert_eq!(alloc_align, layout.align.abi);
+ assert!(alloc_align >= layout.align.abi);
let read_scalar = |start, size, s: abi::Scalar, ty| {
match alloc.0.read_scalar(
diff --git a/compiler/rustc_error_codes/src/error_codes/E0761.md b/compiler/rustc_error_codes/src/error_codes/E0761.md
index 760c5897698a..975f967d0e17 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0761.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0761.md
@@ -15,7 +15,7 @@ fn foo() {}
mod ambiguous_module; // error: file for module `ambiguous_module`
// found at both ambiguous_module.rs and
- // ambiguous_module.rs/mod.rs
+ // ambiguous_module/mod.rs
```
Please remove this ambiguity by deleting/renaming one of the candidate files.
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index ded0baa9563e..2c4187031cac 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -174,7 +174,7 @@ pub fn placeholder(
}]),
AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
attrs: Default::default(),
- data: ast::VariantData::Struct(Default::default(), false),
+ data: ast::VariantData::Struct { fields: Default::default(), recovered: false },
disr_expr: None,
id,
ident,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 258d6710bc57..81ec7ddb629e 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -3,8 +3,8 @@ use crate::hir;
use rustc_ast as ast;
use rustc_ast::NodeId;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::ToStableHashKey;
+use rustc_data_structures::unord::UnordMap;
use rustc_macros::HashStable_Generic;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::hygiene::MacroKind;
@@ -603,7 +603,7 @@ impl CtorKind {
match *vdata {
ast::VariantData::Tuple(_, node_id) => Some((CtorKind::Fn, node_id)),
ast::VariantData::Unit(node_id) => Some((CtorKind::Const, node_id)),
- ast::VariantData::Struct(..) => None,
+ ast::VariantData::Struct { .. } => None,
}
}
}
@@ -806,4 +806,4 @@ pub enum LifetimeRes {
ElidedAnchor { start: NodeId, end: NodeId },
}
-pub type DocLinkResMap = FxHashMap<(Symbol, Namespace), Option>>;
+pub type DocLinkResMap = UnordMap<(Symbol, Namespace), Option>>;
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index d222325475d3..2ab9a6ef32ce 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -8,8 +8,8 @@ pub use crate::def_id::DefPathHash;
use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::def_path_hash_map::DefPathHashMap;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
+use rustc_data_structures::unord::UnordMap;
use rustc_index::IndexVec;
use rustc_span::symbol::{kw, sym, Symbol};
@@ -95,7 +95,7 @@ impl DefPathTable {
#[derive(Debug)]
pub struct Definitions {
table: DefPathTable,
- next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
+ next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>,
/// The [StableCrateId] of the local crate.
stable_crate_id: StableCrateId,
diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs
index 243014b00270..d4d09f9a4e06 100644
--- a/compiler/rustc_hir/src/diagnostic_items.rs
+++ b/compiler/rustc_hir/src/diagnostic_items.rs
@@ -1,12 +1,13 @@
use crate::def_id::DefId;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_span::def_id::DefIdMap;
use rustc_span::Symbol;
#[derive(Debug, Default)]
pub struct DiagnosticItems {
- pub id_to_name: FxHashMap,
- pub name_to_id: FxHashMap,
+ pub id_to_name: DefIdMap,
+ pub name_to_id: FxIndexMap,
}
impl HashStable for DiagnosticItems {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 760945554f06..3179fd736042 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,6 @@
use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::DefId;
-pub(crate) use crate::hir_id::{HirId, ItemLocalId, OwnerId};
+use crate::def_id::{DefId, LocalDefIdMap};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::FnKind;
use crate::LangItem;
@@ -11,7 +11,6 @@ pub use rustc_ast::{BinOp, BinOpKind, BindingAnnotation, BorrowKind, ByRef, Capt
pub use rustc_ast::{ImplPolarity, IsAuto, Movability, Mutability, UnOp};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_index::IndexVec;
use rustc_macros::HashStable_Generic;
@@ -874,12 +873,12 @@ pub struct OwnerInfo<'hir> {
/// Contents of the HIR.
pub nodes: OwnerNodes<'hir>,
/// Map from each nested owner to its parent's local id.
- pub parenting: FxHashMap,
+ pub parenting: LocalDefIdMap,
/// Collected attributes of the HIR nodes.
pub attrs: AttributeMap<'hir>,
/// Map indicating what traits are in scope for places where this
/// is relevant; generated by resolve.
- pub trait_map: FxHashMap>,
+ pub trait_map: ItemLocalMap>,
}
impl<'tcx> OwnerInfo<'tcx> {
@@ -2849,7 +2848,11 @@ pub enum VariantData<'hir> {
/// A struct variant.
///
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
- Struct(&'hir [FieldDef<'hir>], /* recovered */ bool),
+ Struct {
+ fields: &'hir [FieldDef<'hir>],
+ // FIXME: investigate making this a `Option`
+ recovered: bool,
+ },
/// A tuple variant.
///
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -2864,7 +2867,7 @@ impl<'hir> VariantData<'hir> {
/// Return the fields of this variant.
pub fn fields(&self) -> &'hir [FieldDef<'hir>] {
match *self {
- VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => fields,
+ VariantData::Struct { fields, .. } | VariantData::Tuple(fields, ..) => fields,
_ => &[],
}
}
@@ -2873,7 +2876,7 @@ impl<'hir> VariantData<'hir> {
match *self {
VariantData::Tuple(_, hir_id, def_id) => Some((CtorKind::Fn, hir_id, def_id)),
VariantData::Unit(hir_id, def_id) => Some((CtorKind::Const, hir_id, def_id)),
- VariantData::Struct(..) => None,
+ VariantData::Struct { .. } => None,
}
}
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 838c123f83c8..e60503271862 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -1,7 +1,6 @@
use crate::def::{CtorOf, DefKind, Res};
-use crate::def_id::DefId;
+use crate::def_id::{DefId, DefIdSet};
use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
-use rustc_data_structures::fx::FxHashSet;
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -114,9 +113,9 @@ impl hir::Pat<'_> {
}
_ => true,
});
- // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
+ // We remove duplicates by inserting into a hash set to avoid re-ordering
// the bounds
- let mut duplicates = FxHashSet::default();
+ let mut duplicates = DefIdSet::default();
variants.retain(|def_id| duplicates.insert(*def_id));
variants
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index be73c027fdc8..b495b00ec704 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -262,7 +262,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
// impl const PartialEq for () {}
// ```
//
- // Since this is a const impl, we need to insert `` at the end of
+ // Since this is a const impl, we need to insert a host arg at the end of
// `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
// To work around this, we infer all arguments until we reach the host param.
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 688d32fa32d1..d48535c82f59 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -814,7 +814,7 @@ fn convert_variant(
})
.collect();
let recovered = match def {
- hir::VariantData::Struct(_, r) => *r,
+ hir::VariantData::Struct { recovered, .. } => *recovered,
_ => false,
};
ty::VariantDef::new(
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 15d546537dde..19e7fe388aae 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -481,7 +481,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match def {
- VariantData::Unit(..) | VariantData::Struct(..) => {
+ VariantData::Unit(..) | VariantData::Struct { .. } => {
tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity()
}
VariantData::Tuple(..) => {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 21a50b94a37a..6715d01c9e0b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -741,7 +741,7 @@ impl<'a> State<'a> {
self.end();
self.end() // close the outer-box
}
- hir::VariantData::Struct(..) => {
+ hir::VariantData::Struct { .. } => {
self.print_where_clause(generics);
self.nbsp();
self.bopen();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 24b577fd3c50..4bc237c2383b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1498,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_with_obligations(ty);
if self.next_trait_solver()
- && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind()
+ && let ty::Alias(..) = ty.kind()
{
match self
.at(&self.misc(sp), self.param_env)
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index d0b4889b45fa..3ea1a52ae282 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -9,6 +9,7 @@ use std::slice;
use arrayvec::ArrayVec;
use smallvec::{smallvec, SmallVec};
+#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable};
use crate::{Idx, IndexVec};
@@ -111,7 +112,8 @@ macro_rules! bit_relations_inherent_impls {
/// to or greater than the domain size. All operations that involve two bitsets
/// will panic if the bitsets have differing domain sizes.
///
-#[derive(Eq, PartialEq, Hash, Decodable, Encodable)]
+#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[derive(Eq, PartialEq, Hash)]
pub struct BitSet {
domain_size: usize,
words: SmallVec<[Word; 2]>,
@@ -491,10 +493,21 @@ impl ChunkedBitSet {
match *chunk {
Zeros(chunk_domain_size) => {
if chunk_domain_size > 1 {
- // We take some effort to avoid copying the words.
- let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
- // SAFETY: `words` can safely be all zeroes.
- let mut words = unsafe { words.assume_init() };
+ #[cfg(feature = "nightly")]
+ let mut words = {
+ // We take some effort to avoid copying the words.
+ let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
+ // SAFETY: `words` can safely be all zeroes.
+ unsafe { words.assume_init() }
+ };
+ #[cfg(not(feature = "nightly"))]
+ let mut words = {
+ let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
+ // SAFETY: `words` can safely be all zeroes.
+ let words = unsafe { words.assume_init() };
+ // Unfortunate possibly-large copy
+ Rc::new(words)
+ };
let words_ref = Rc::get_mut(&mut words).unwrap();
let (word_index, mask) = chunk_word_index_and_mask(elem);
@@ -545,10 +558,21 @@ impl ChunkedBitSet {
Zeros(_) => false,
Ones(chunk_domain_size) => {
if chunk_domain_size > 1 {
- // We take some effort to avoid copying the words.
- let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
- // SAFETY: `words` can safely be all zeroes.
- let mut words = unsafe { words.assume_init() };
+ #[cfg(feature = "nightly")]
+ let mut words = {
+ // We take some effort to avoid copying the words.
+ let words = Rc::<[Word; CHUNK_WORDS]>::new_zeroed();
+ // SAFETY: `words` can safely be all zeroes.
+ unsafe { words.assume_init() }
+ };
+ #[cfg(not(feature = "nightly"))]
+ let mut words = {
+ let words = mem::MaybeUninit::<[Word; CHUNK_WORDS]>::zeroed();
+ // SAFETY: `words` can safely be all zeroes.
+ let words = unsafe { words.assume_init() };
+ // Unfortunate possibly-large copy
+ Rc::new(words)
+ };
let words_ref = Rc::get_mut(&mut words).unwrap();
// Set only the bits in use.
@@ -1564,7 +1588,8 @@ impl From> for GrowableBitSet {
///
/// All operations that involve a row and/or column index will panic if the
/// index exceeds the relevant bound.
-#[derive(Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
+#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[derive(Clone, Eq, PartialEq, Hash)]
pub struct BitMatrix {
num_rows: usize,
num_columns: usize,
@@ -1993,7 +2018,8 @@ impl std::fmt::Debug for FiniteBitSet {
/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
/// representable by `T` are considered set.
-#[derive(Copy, Clone, Eq, PartialEq, Decodable, Encodable)]
+#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[derive(Copy, Clone, Eq, PartialEq)]
pub struct FiniteBitSet(pub T);
impl FiniteBitSet {
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index c5602392c538..185e0c7d6989 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -14,7 +14,6 @@
)]
#![cfg_attr(feature = "nightly", allow(internal_features))]
-#[cfg(feature = "nightly")]
pub mod bit_set;
#[cfg(feature = "nightly")]
pub mod interval;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index c118c405c209..d396c41007b1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2653,11 +2653,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
self.0.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- // Unused, only for consts which we treat as always equal
- ty::ParamEnv::empty()
- }
-
fn tag(&self) -> &'static str {
"SameTypeModuloInfer"
}
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index b6e86e2b676d..0fbc4a0ce50e 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -31,13 +31,12 @@ use super::outlives::test_type_match;
/// all the variables as well as a set of errors that must be reported.
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
pub(crate) fn resolve<'tcx>(
- param_env: ty::ParamEnv<'tcx>,
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
) -> (LexicalRegionResolutions<'tcx>, Vec>) {
let mut errors = vec![];
- let mut resolver = LexicalResolver { param_env, region_rels, var_infos, data };
+ let mut resolver = LexicalResolver { region_rels, var_infos, data };
let values = resolver.infer_variable_values(&mut errors);
(values, errors)
}
@@ -120,7 +119,6 @@ struct RegionAndOrigin<'tcx> {
type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
struct LexicalResolver<'cx, 'tcx> {
- param_env: ty::ParamEnv<'tcx>,
region_rels: &'cx RegionRelations<'cx, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
@@ -914,12 +912,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
match bound {
VerifyBound::IfEq(verify_if_eq_b) => {
let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
- match test_type_match::extract_verify_if_eq(
- self.tcx(),
- self.param_env,
- &verify_if_eq_b,
- generic_ty,
- ) {
+ match test_type_match::extract_verify_if_eq(self.tcx(), &verify_if_eq_b, generic_ty)
+ {
Some(r) => {
self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
}
diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
index 52cc107ae52c..42e3d6cad5a9 100644
--- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
+++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs
@@ -84,7 +84,6 @@ where
} else {
test_type_match::extract_verify_if_eq(
tcx,
- param_env,
&outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
VerifyIfEq { ty, bound }
}),
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index f7129a5ad89a..6379f84aa252 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -67,7 +67,7 @@ impl<'tcx> InferCtxt<'tcx> {
let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
let (lexical_region_resolutions, errors) =
- lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
+ lexical_region_resolve::resolve(region_rels, var_infos, data);
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
assert!(old_value.is_none());
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 959b34aa1457..236dc4ec3848 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -36,15 +36,14 @@ use crate::infer::region_constraints::VerifyIfEq;
/// like are used. This is a particular challenge since this function is invoked
/// very late in inference and hence cannot make use of the normal inference
/// machinery.
-#[instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx))]
pub fn extract_verify_if_eq<'tcx>(
tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>,
test_ty: Ty<'tcx>,
) -> Option> {
assert!(!verify_if_eq_b.has_escaping_bound_vars());
- let mut m = MatchAgainstHigherRankedOutlives::new(tcx, param_env);
+ let mut m = MatchAgainstHigherRankedOutlives::new(tcx);
let verify_if_eq = verify_if_eq_b.skip_binder();
m.relate(verify_if_eq.ty, test_ty).ok()?;
@@ -73,10 +72,9 @@ pub fn extract_verify_if_eq<'tcx>(
}
/// True if a (potentially higher-ranked) outlives
-#[instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx))]
pub(super) fn can_match_erased_ty<'tcx>(
tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
erased_ty: Ty<'tcx>,
) -> bool {
@@ -87,25 +85,20 @@ pub(super) fn can_match_erased_ty<'tcx>(
// pointless micro-optimization
true
} else {
- MatchAgainstHigherRankedOutlives::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
+ MatchAgainstHigherRankedOutlives::new(tcx).relate(outlives_ty, erased_ty).is_ok()
}
}
struct MatchAgainstHigherRankedOutlives<'tcx> {
tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
pattern_depth: ty::DebruijnIndex,
map: FxHashMap>,
}
impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
- fn new(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> MatchAgainstHigherRankedOutlives<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstHigherRankedOutlives<'tcx> {
MatchAgainstHigherRankedOutlives {
tcx,
- param_env,
pattern_depth: ty::INNERMOST,
map: FxHashMap::default(),
}
@@ -144,15 +137,13 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> {
fn tag(&self) -> &'static str {
- "Match"
+ "MatchAgainstHigherRankedOutlives"
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
+
fn a_is_expected(&self) -> bool {
true
} // irrelevant
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index bb578a482e4b..90282f58e94f 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,7 +1,7 @@
use crate::infer::outlives::components::{compute_alias_components_recursive, Component};
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
-use crate::infer::VerifyBound;
+use crate::infer::{GenericKind, VerifyBound};
use rustc_data_structures::sso::SsoHashSet;
use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
@@ -240,10 +240,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
"declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
(r, p)
);
+ // Fast path for the common case.
+ match (&p, erased_ty.kind()) {
+ // In outlive routines, all types are expected to be fully normalized.
+ // And therefore we can safely use structural equality for alias types.
+ (GenericKind::Param(p1), ty::Param(p2)) if p1 == p2 => {}
+ (GenericKind::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => {}
+ (GenericKind::Alias(a1), ty::Alias(_, a2)) if a1.def_id == a2.def_id => {}
+ _ => return None,
+ }
+
let p_ty = p.to_ty(tcx);
let erased_p_ty = self.tcx.erase_regions(p_ty);
(erased_p_ty == erased_ty)
- .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r)))
+ .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
});
param_bounds
@@ -312,14 +322,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
) -> impl Iterator- , ty::Region<'tcx>>>>
{
let tcx = self.tcx;
- let param_env = self.param_env;
clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| {
- super::test_type_match::can_match_erased_ty(
- tcx,
- param_env,
- *outlives_predicate,
- erased_ty,
- )
+ super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty)
})
}
}
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index dfaca3458d66..ee911c43284a 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -563,6 +563,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
}
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx>;
+
/// Register obligations that must hold in order for this relation to hold
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
diff --git a/compiler/rustc_infer/src/infer/relate/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs
index 9943c638a91d..cb62f258373f 100644
--- a/compiler/rustc_infer/src/infer/relate/equate.rs
+++ b/compiler/rustc_infer/src/infer/relate/equate.rs
@@ -33,10 +33,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.fields.tcx()
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.fields.param_env
- }
-
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
@@ -174,6 +170,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.fields.param_env
+ }
+
fn register_predicates(&mut self, obligations: impl IntoIterator>) {
self.fields.register_predicates(obligations);
}
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 66f7b08ee12c..665af7381dc7 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -182,10 +182,6 @@ where
self.infcx.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.delegate.param_env()
- }
-
fn tag(&self) -> &'static str {
"Generalizer"
}
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index 6a3413879c40..aa89124301e8 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -32,10 +32,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.fields.tcx()
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.fields.param_env
- }
-
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
@@ -138,6 +134,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.fields.param_env
+ }
+
fn register_predicates(&mut self, obligations: impl IntoIterator>) {
self.fields.register_predicates(obligations);
}
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 41cd98ed0cfc..87d777530c86 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -32,10 +32,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.fields.tcx()
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.fields.param_env
- }
-
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
@@ -138,6 +134,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.fields.param_env
+ }
+
fn register_predicates(&mut self, obligations: impl IntoIterator>) {
self.fields.register_predicates(obligations);
}
diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs
index afc2a8b2f623..1ef865cfc5f8 100644
--- a/compiler/rustc_infer/src/infer/relate/nll.rs
+++ b/compiler/rustc_infer/src/infer/relate/nll.rs
@@ -431,10 +431,6 @@ where
self.infcx.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.delegate.param_env()
- }
-
fn tag(&self) -> &'static str {
"nll::subtype"
}
@@ -670,6 +666,10 @@ impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.delegate.param_env()
+ }
+
fn register_predicates(&mut self, obligations: impl IntoIterator>) {
self.delegate.register_obligations(
obligations
diff --git a/compiler/rustc_infer/src/infer/relate/sub.rs b/compiler/rustc_infer/src/infer/relate/sub.rs
index 5a623e48c930..36876acd7c0d 100644
--- a/compiler/rustc_infer/src/infer/relate/sub.rs
+++ b/compiler/rustc_infer/src/infer/relate/sub.rs
@@ -39,10 +39,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
self.fields.infcx.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.fields.param_env
- }
-
fn a_is_expected(&self) -> bool {
self.a_is_expected
}
@@ -203,6 +199,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
}
impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.fields.param_env
+ }
+
fn register_predicates(&mut self, obligations: impl IntoIterator>) {
self.fields.register_predicates(obligations);
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 24ab4f94d5c5..281a0eafee1a 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::unhash::UnhashMap;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
use rustc_hir::def::Res;
-use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPath, DefPathData};
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_index::Idx;
@@ -1200,7 +1200,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
/// Iterates over the diagnostic items in the given crate.
fn get_diagnostic_items(self) -> DiagnosticItems {
- let mut id_to_name = FxHashMap::default();
+ let mut id_to_name = DefIdMap::default();
let name_to_id = self
.root
.diagnostic_items
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a69bff6ed8ca..3a54f5f6b3d0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -69,7 +69,7 @@ use rustc_hir::def_id::{
CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
};
use rustc_hir::lang_items::{LangItem, LanguageItems};
-use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
+use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
use rustc_index::IndexVec;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState};
@@ -1490,7 +1490,7 @@ rustc_queries! {
desc { "computing whether impls specialize one another" }
}
query in_scope_traits_map(_: hir::OwnerId)
- -> Option<&'tcx FxHashMap>> {
+ -> Option<&'tcx ItemLocalMap>> {
desc { "getting traits in scope at a block" }
}
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 27a1e64a78bd..048df367bd65 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -233,6 +233,27 @@ impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> {
}
}
+/// Why a specific goal has to be proven.
+///
+/// This is necessary as we treat nested goals different depending on
+/// their source.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum GoalSource {
+ Misc,
+ /// We're proving a where-bound of an impl.
+ ///
+ /// FIXME(-Znext-solver=coinductive): Explain how and why this
+ /// changes whether cycles are coinductive.
+ ///
+ /// This also impacts whether we erase constraints on overflow.
+ /// Erasing constraints is generally very useful for perf and also
+ /// results in better error messages by avoiding spurious errors.
+ /// We do not erase overflow constraints in `normalizes-to` goals unless
+ /// they are from an impl where-clause. This is necessary due to
+ /// backwards compatability, cc trait-system-refactor-initiatitive#70.
+ ImplWhereBound,
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 7883cd338bef..77d112d0afcc 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -19,8 +19,8 @@
//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{
- CandidateSource, Canonical, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution,
- QueryInput, QueryResult,
+ CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack,
+ NoSolution, QueryInput, QueryResult,
};
use crate::{infer::canonical::CanonicalVarValues, ty};
use format::ProofTreeFormatter;
@@ -115,7 +115,7 @@ impl Debug for Probe<'_> {
pub enum ProbeStep<'tcx> {
/// We added a goal to the `EvalCtxt` which will get proven
/// the next time `EvalCtxt::try_evaluate_added_goals` is called.
- AddGoal(CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+ AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
/// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
EvaluateGoals(AddedGoalsEvaluation<'tcx>),
/// A call to `probe` while proving the current goal. This is
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index ab9e0283918d..4e2207ed5230 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -123,7 +123,13 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
self.nested(|this| {
for step in &probe.steps {
match step {
- ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
+ ProbeStep::AddGoal(source, goal) => {
+ let source = match source {
+ GoalSource::Misc => "misc",
+ GoalSource::ImplWhereBound => "impl where-bound",
+ };
+ writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
+ }
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index 85181720d17e..a2794a100f14 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -20,12 +20,11 @@ use crate::ty::{self, InferConst, Ty, TyCtxt};
/// affects any type variables or unification state.
pub struct MatchAgainstFreshVars<'tcx> {
tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
}
impl<'tcx> MatchAgainstFreshVars<'tcx> {
- pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> MatchAgainstFreshVars<'tcx> {
- MatchAgainstFreshVars { tcx, param_env }
+ pub fn new(tcx: TyCtxt<'tcx>) -> MatchAgainstFreshVars<'tcx> {
+ MatchAgainstFreshVars { tcx }
}
}
@@ -33,13 +32,11 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> {
fn tag(&self) -> &'static str {
"MatchAgainstFreshVars"
}
+
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
fn a_is_expected(&self) -> bool {
true
} // irrelevant
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 6a6ed59fabfa..b5ca700c2cd5 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1039,17 +1039,34 @@ impl<'tcx> TyCtxtAt<'tcx> {
// This is fine because:
// - those queries are `eval_always` so we won't miss their result changing;
// - this write will have happened before these queries are called.
- let data = def_kind.def_path_data(name);
- let key = self.untracked.definitions.write().create_def(parent, data);
+ let def_id = self.tcx.create_def(parent, name, def_kind);
- let feed = TyCtxtFeed { tcx: self.tcx, key };
- feed.def_kind(def_kind);
+ let feed = self.tcx.feed_local_def_id(def_id);
feed.def_span(self.span);
feed
}
}
impl<'tcx> TyCtxt<'tcx> {
+ /// `tcx`-dependent operations performed for every created definition.
+ pub fn create_def(self, parent: LocalDefId, name: Symbol, def_kind: DefKind) -> LocalDefId {
+ let data = def_kind.def_path_data(name);
+ let def_id = self.untracked.definitions.write().create_def(parent, data);
+
+ let feed = self.feed_local_def_id(def_id);
+ feed.def_kind(def_kind);
+ // Unique types created for closures participate in type privacy checking.
+ // They have visibilities inherited from the module they are defined in.
+ // Visibilities for opaque types are meaningless, but still provided
+ // so that all items have visibilities.
+ if matches!(def_kind, DefKind::Closure | DefKind::OpaqueTy) {
+ let parent_mod = self.parent_module_from_def_id(def_id).to_def_id();
+ feed.visibility(ty::Visibility::Restricted(parent_mod));
+ }
+
+ def_id
+ }
+
pub fn iter_local_def_id(self) -> impl Iterator
- + 'tcx {
// Create a dependency to the red node to be sure we re-execute this when the amount of
// definitions change.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 96de9c447b6f..35c135830c3f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -192,7 +192,7 @@ pub struct ResolverAstLowering {
pub next_node_id: ast::NodeId,
- pub node_id_to_def_id: FxHashMap,
+ pub node_id_to_def_id: NodeMap,
pub def_id_to_node_id: IndexVec,
pub trait_map: NodeMap>,
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index d7d9afc30e7e..9d92f81db0bb 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -23,8 +23,6 @@ pub enum Cause {
pub trait TypeRelation<'tcx>: Sized {
fn tcx(&self) -> TyCtxt<'tcx>;
- fn param_env(&self) -> ty::ParamEnv<'tcx>;
-
/// Returns a static string we can use for printouts.
fn tag(&self) -> &'static str;
@@ -505,13 +503,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Err(err) => {
// Check whether the lengths are both concrete/known values,
// but are unequal, for better diagnostics.
- //
- // It might seem dubious to eagerly evaluate these constants here,
- // we however cannot end up with errors in `Relate` during both
- // `type_of` and `predicates_of`. This means that evaluating the
- // constants should not cause cycle errors here.
- let sz_a = sz_a.try_eval_target_usize(tcx, relation.param_env());
- let sz_b = sz_b.try_eval_target_usize(tcx, relation.param_env());
+ let sz_a = sz_a.try_to_target_usize(tcx);
+ let sz_b = sz_b.try_to_target_usize(tcx);
+
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err(
TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)),
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 541b87af7977..487b1f44b5e2 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1699,59 +1699,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
debug!("untested_candidates: {}", candidates.len());
- // HACK(matthewjasper) This is a closure so that we can let the test
- // create its blocks before the rest of the match. This currently
- // improves the speed of llvm when optimizing long string literal
- // matches
- let make_target_blocks = move |this: &mut Self| -> Vec {
- // The block that we should branch to if none of the
- // `target_candidates` match. This is either the block where we
- // start matching the untested candidates if there are any,
- // otherwise it's the `otherwise_block`.
- let remainder_start = &mut None;
- let remainder_start =
- if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
+ // The block that we should branch to if none of the
+ // `target_candidates` match. This is either the block where we
+ // start matching the untested candidates if there are any,
+ // otherwise it's the `otherwise_block`.
+ let remainder_start = &mut None;
+ let remainder_start =
+ if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
- // For each outcome of test, process the candidates that still
- // apply. Collect a list of blocks where control flow will
- // branch if one of the `target_candidate` sets is not
- // exhaustive.
- let target_blocks: Vec<_> = target_candidates
- .into_iter()
- .map(|mut candidates| {
- if !candidates.is_empty() {
- let candidate_start = this.cfg.start_new_block();
- this.match_candidates(
- span,
- scrutinee_span,
- candidate_start,
- remainder_start,
- &mut *candidates,
- fake_borrows,
- );
- candidate_start
- } else {
- *remainder_start.get_or_insert_with(|| this.cfg.start_new_block())
- }
- })
- .collect();
+ // For each outcome of test, process the candidates that still
+ // apply. Collect a list of blocks where control flow will
+ // branch if one of the `target_candidate` sets is not
+ // exhaustive.
+ let target_blocks: Vec<_> = target_candidates
+ .into_iter()
+ .map(|mut candidates| {
+ if !candidates.is_empty() {
+ let candidate_start = self.cfg.start_new_block();
+ self.match_candidates(
+ span,
+ scrutinee_span,
+ candidate_start,
+ remainder_start,
+ &mut *candidates,
+ fake_borrows,
+ );
+ candidate_start
+ } else {
+ *remainder_start.get_or_insert_with(|| self.cfg.start_new_block())
+ }
+ })
+ .collect();
- if !candidates.is_empty() {
- let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
- this.match_candidates(
- span,
- scrutinee_span,
- remainder_start,
- otherwise_block,
- candidates,
- fake_borrows,
- );
- };
+ if !candidates.is_empty() {
+ let remainder_start = remainder_start.unwrap_or_else(|| self.cfg.start_new_block());
+ self.match_candidates(
+ span,
+ scrutinee_span,
+ remainder_start,
+ otherwise_block,
+ candidates,
+ fake_borrows,
+ );
+ }
- target_blocks
- };
-
- self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks);
+ self.perform_test(span, scrutinee_span, block, &match_place, &test, target_blocks);
}
/// Determine the fake borrows that are needed from a set of places that
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index d1952704da3c..53e5d70f946e 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -147,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
+ #[instrument(skip(self, target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@@ -155,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block: BasicBlock,
place_builder: &PlaceBuilder<'tcx>,
test: &Test<'tcx>,
- make_target_blocks: impl FnOnce(&mut Self) -> Vec,
+ target_blocks: Vec,
) {
let place = place_builder.to_place(self);
let place_ty = place.ty(&self.local_decls, self.tcx);
@@ -164,7 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let source_info = self.source_info(test.span);
match test.kind {
TestKind::Switch { adt_def, ref variants } => {
- let target_blocks = make_target_blocks(self);
// Variants is a BitVec of indexes into adt_def.variants.
let num_enum_variants = adt_def.variants().len();
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
@@ -210,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
TestKind::SwitchInt { switch_ty, ref options } => {
- let target_blocks = make_target_blocks(self);
let terminator = if *switch_ty.kind() == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2);
let [first_bb, second_bb] = *target_blocks else {
@@ -240,6 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestKind::Eq { value, ty } => {
let tcx = self.tcx;
+ let [success_block, fail_block] = *target_blocks else {
+ bug!("`TestKind::Eq` should have two target blocks")
+ };
if let ty::Adt(def, _) = ty.kind()
&& Some(def.did()) == tcx.lang_items().string()
{
@@ -280,38 +281,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
self.non_scalar_compare(
eq_block,
- make_target_blocks,
+ success_block,
+ fail_block,
source_info,
value,
ref_str,
ref_str_ty,
);
- return;
- }
- if !ty.is_scalar() {
+ } else if !ty.is_scalar() {
// Use `PartialEq::eq` instead of `BinOp::Eq`
// (the binop can only handle primitives)
self.non_scalar_compare(
block,
- make_target_blocks,
+ success_block,
+ fail_block,
source_info,
value,
place,
ty,
);
- } else if let [success, fail] = *make_target_blocks(self) {
+ } else {
assert_eq!(value.ty(), ty);
let expect = self.literal_operand(test.span, value);
let val = Operand::Copy(place);
- self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
- } else {
- bug!("`TestKind::Eq` should have two target blocks");
+ self.compare(
+ block,
+ success_block,
+ fail_block,
+ source_info,
+ BinOp::Eq,
+ expect,
+ val,
+ );
}
}
TestKind::Range(ref range) => {
let lower_bound_success = self.cfg.start_new_block();
- let target_blocks = make_target_blocks(self);
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
// FIXME: skip useless comparison when the range is half-open.
@@ -341,8 +347,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
TestKind::Len { len, op } => {
- let target_blocks = make_target_blocks(self);
-
let usize_ty = self.tcx.types.usize;
let actual = self.temp(usize_ty, test.span);
@@ -406,7 +410,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn non_scalar_compare(
&mut self,
block: BasicBlock,
- make_target_blocks: impl FnOnce(&mut Self) -> Vec,
+ success_block: BasicBlock,
+ fail_block: BasicBlock,
source_info: SourceInfo,
value: Const<'tcx>,
mut val: Place<'tcx>,
@@ -531,9 +536,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
self.diverge_from(block);
- let [success_block, fail_block] = *make_target_blocks(self) else {
- bug!("`TestKind::Eq` should have two target blocks")
- };
// check the result
self.cfg.terminate(
eq_block,
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index db2624cac024..c66687330dc4 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
-use rustc_pattern_analysis::{cx::MatchCheckCtxt, errors::Uncovered};
+use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcMatchCheckCtxt};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
@@ -454,7 +454,7 @@ pub enum UnusedUnsafeEnclosing {
}
pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
- pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
+ pub cx: &'m RustcMatchCheckCtxt<'p, 'tcx>,
pub expr_span: Span,
pub span: Span,
pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 792a443c9086..c435f4023af6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,13 +1,13 @@
-use rustc_pattern_analysis::constructor::Constructor;
-use rustc_pattern_analysis::cx::MatchCheckCtxt;
use rustc_pattern_analysis::errors::Uncovered;
-use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
-use rustc_pattern_analysis::usefulness::{Usefulness, UsefulnessReport};
+use rustc_pattern_analysis::rustc::{
+ Constructor, DeconstructedPat, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
+ UsefulnessReport, WitnessPat,
+};
use rustc_pattern_analysis::{analyze_match, MatchArm};
use crate::errors::*;
-use rustc_arena::TypedArena;
+use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::Mutability;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -31,6 +31,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
let (thir, expr) = tcx.thir_body(def_id)?;
let thir = thir.borrow();
let pattern_arena = TypedArena::default();
+ let dropless_arena = DroplessArena::default();
let mut visitor = MatchVisitor {
tcx,
thir: &*thir,
@@ -38,6 +39,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
lint_level: tcx.local_def_id_to_hir_id(def_id),
let_source: LetSource::None,
pattern_arena: &pattern_arena,
+ dropless_arena: &dropless_arena,
error: Ok(()),
};
visitor.visit_expr(&thir[expr]);
@@ -82,6 +84,7 @@ struct MatchVisitor<'thir, 'p, 'tcx> {
lint_level: HirId,
let_source: LetSource,
pattern_arena: &'p TypedArena>,
+ dropless_arena: &'p DroplessArena,
/// Tracks if we encountered an error while checking this body. That the first function to
/// report it stores it here. Some functions return `Result` to allow callers to short-circuit
/// on error, but callers don't need to store it here again.
@@ -382,6 +385,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
param_env: self.param_env,
module: self.tcx.parent_module(self.lint_level).to_def_id(),
pattern_arena: self.pattern_arena,
+ dropless_arena: self.dropless_arena,
match_lint_level: self.lint_level,
whole_match_span,
scrut_span,
@@ -425,7 +429,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
let arm = &self.thir.arms[arm];
let got_error = self.with_lint_level(arm.lint_level, |this| {
let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true };
- let arm = MatchArm { pat, hir_id: this.lint_level, has_guard: arm.guard.is_some() };
+ let arm =
+ MatchArm { pat, arm_data: this.lint_level, has_guard: arm.guard.is_some() };
tarms.push(arm);
false
});
@@ -548,7 +553,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
let cx = self.new_cx(refutability, None, scrut, pat.span);
let pat = self.lower_pattern(&cx, pat)?;
- let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }];
+ let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
let report = analyze_match(&cx, &arms, pat.ty());
Ok((cx, report))
}
@@ -847,34 +852,34 @@ fn report_arm_reachability<'p, 'tcx>(
);
};
- use Usefulness::*;
let mut catchall = None;
for (arm, is_useful) in report.arm_usefulness.iter() {
match is_useful {
- Redundant => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
- Useful(redundant_spans) if redundant_spans.is_empty() => {}
+ Usefulness::Redundant => {
+ report_unreachable_pattern(*arm.pat.data(), arm.arm_data, catchall)
+ }
+ Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
- Useful(redundant_spans) => {
- let mut redundant_spans = redundant_spans.clone();
+ Usefulness::Useful(redundant_subpats) => {
+ let mut redundant_subpats = redundant_subpats.clone();
// Emit lints in the order in which they occur in the file.
- redundant_spans.sort_unstable();
- for span in redundant_spans {
- report_unreachable_pattern(span, arm.hir_id, None);
+ redundant_subpats.sort_unstable_by_key(|pat| pat.data());
+ for pat in redundant_subpats {
+ report_unreachable_pattern(*pat.data(), arm.arm_data, None);
}
}
}
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
- catchall = Some(arm.pat.span());
+ catchall = Some(*arm.pat.data());
}
}
}
/// Checks for common cases of "catchall" patterns that may not be intended as such.
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
- use Constructor::*;
match pat.ctor() {
- Wildcard => true,
- Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
+ Constructor::Wildcard => true,
+ Constructor::Struct | Constructor::Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
_ => false,
}
}
@@ -885,7 +890,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
thir: &Thir<'tcx>,
scrut_ty: Ty<'tcx>,
sp: Span,
- witnesses: Vec>,
+ witnesses: Vec>,
arms: &[ArmId],
expr_span: Span,
) -> ErrorGuaranteed {
@@ -1082,10 +1087,10 @@ fn report_non_exhaustive_match<'p, 'tcx>(
fn joined_uncovered_patterns<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
- witnesses: &[WitnessPat<'tcx>],
+ witnesses: &[WitnessPat<'p, 'tcx>],
) -> String {
const LIMIT: usize = 3;
- let pat_to_str = |pat: &WitnessPat<'tcx>| cx.hoist_witness_pat(pat).to_string();
+ let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string();
match witnesses {
[] => bug!(),
[witness] => format!("`{}`", cx.hoist_witness_pat(witness)),
@@ -1103,7 +1108,7 @@ fn joined_uncovered_patterns<'p, 'tcx>(
fn collect_non_exhaustive_tys<'tcx>(
cx: &MatchCheckCtxt<'_, 'tcx>,
- pat: &WitnessPat<'tcx>,
+ pat: &WitnessPat<'_, 'tcx>,
non_exhaustive_tys: &mut FxIndexSet>,
) {
if matches!(pat.ctor(), Constructor::NonExhaustive) {
@@ -1122,7 +1127,7 @@ fn collect_non_exhaustive_tys<'tcx>(
fn report_adt_defined_here<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
- witnesses: &[WitnessPat<'tcx>],
+ witnesses: &[WitnessPat<'_, 'tcx>],
point_at_non_local_ty: bool,
) -> Option> {
let ty = ty.peel_refs();
@@ -1144,15 +1149,14 @@ fn report_adt_defined_here<'tcx>(
Some(AdtDefinedHere { adt_def_span, ty, variants })
}
-fn maybe_point_at_variant<'a, 'tcx: 'a>(
+fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'p>(
tcx: TyCtxt<'tcx>,
def: AdtDef<'tcx>,
- patterns: impl Iterator
- >,
+ patterns: impl Iterator
- >,
) -> Vec {
- use Constructor::*;
let mut covered = vec![];
for pattern in patterns {
- if let Variant(variant_index) = pattern.ctor() {
+ if let Constructor::Variant(variant_index) = pattern.ctor() {
if let ty::Adt(this_def, _) = pattern.ty().kind()
&& this_def.did() != def.did()
{
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 709d1fdc21a0..c5a3391286ac 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -68,32 +68,21 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
struct Instrumentor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
mir_body: &'a mut mir::Body<'tcx>,
- fn_sig_span: Span,
- body_span: Span,
- function_source_hash: u64,
+ hir_info: ExtractedHirInfo,
basic_coverage_blocks: CoverageGraph,
coverage_counters: CoverageCounters,
}
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
- let hir_info @ ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } =
- extract_hir_info(tcx, mir_body.source.def_id().expect_local());
+ let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local());
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
- Self {
- tcx,
- mir_body,
- fn_sig_span,
- body_span,
- function_source_hash,
- basic_coverage_blocks,
- coverage_counters,
- }
+ Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters }
}
fn inject_counters(&'a mut self) {
@@ -101,8 +90,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
// Compute coverage spans from the `CoverageGraph`.
let Some(coverage_spans) = CoverageSpans::generate_coverage_spans(
self.mir_body,
- self.fn_sig_span,
- self.body_span,
+ &self.hir_info,
&self.basic_coverage_blocks,
) else {
// No relevant spans were found in MIR, so skip instrumenting this function.
@@ -121,7 +109,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
- function_source_hash: self.function_source_hash,
+ function_source_hash: self.hir_info.function_source_hash,
num_counters: self.coverage_counters.num_counters(),
expressions: self.coverage_counters.take_expressions(),
mappings,
@@ -136,7 +124,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
coverage_spans: &CoverageSpans,
) -> Vec {
let source_map = self.tcx.sess.source_map();
- let body_span = self.body_span;
+ let body_span = self.hir_info.body_span;
let source_file = source_map.lookup_source_file(body_span.lo());
use rustc_session::RemapFileNameExt;
@@ -311,6 +299,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
#[derive(Debug)]
struct ExtractedHirInfo {
function_source_hash: u64,
+ is_async_fn: bool,
fn_sig_span: Span,
body_span: Span,
}
@@ -324,6 +313,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
let hir_body = tcx.hir().body(fn_body_id);
+ let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
let body_span = get_body_span(tcx, hir_body, def_id);
// The actual signature span is only used if it has the same context and
@@ -345,7 +335,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
let function_source_hash = hash_mir_source(tcx, hir_body);
- ExtractedHirInfo { function_source_hash, fn_sig_span, body_span }
+ ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
}
fn get_body_span<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 462e54c386c7..ae43a18ad4e4 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -6,6 +6,7 @@ use rustc_middle::mir;
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
+use crate::coverage::ExtractedHirInfo;
mod from_mir;
@@ -21,14 +22,12 @@ impl CoverageSpans {
/// Returns `None` if no coverage-relevant spans could be extracted.
pub(super) fn generate_coverage_spans(
mir_body: &mir::Body<'_>,
- fn_sig_span: Span,
- body_span: Span,
+ hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
) -> Option {
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
mir_body,
- fn_sig_span,
- body_span,
+ hir_info,
basic_coverage_blocks,
);
@@ -230,19 +229,17 @@ impl<'a> CoverageSpansGenerator<'a> {
/// to be).
pub(super) fn generate_coverage_spans(
mir_body: &mir::Body<'_>,
- fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
- body_span: Span,
+ hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &'a CoverageGraph,
) -> Vec {
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
mir_body,
- fn_sig_span,
- body_span,
+ hir_info,
basic_coverage_blocks,
);
let coverage_spans = Self {
- body_span,
+ body_span: hir_info.body_span,
basic_coverage_blocks,
sorted_spans_iter: sorted_spans.into_iter(),
some_curr: None,
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index eab9a9c98f84..a9c4ea33d0e8 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -7,13 +7,22 @@ use rustc_span::Span;
use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use crate::coverage::spans::CoverageSpan;
+use crate::coverage::ExtractedHirInfo;
pub(super) fn mir_to_initial_sorted_coverage_spans(
mir_body: &mir::Body<'_>,
- fn_sig_span: Span,
- body_span: Span,
+ hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
) -> Vec {
+ let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info;
+ if is_async_fn {
+ // An async function desugars into a function that returns a future,
+ // with the user code wrapped in a closure. Any spans in the desugared
+ // outer function will be unhelpful, so just produce a single span
+ // associating the function signature with its entry BCB.
+ return vec![CoverageSpan::for_fn_sig(fn_sig_span)];
+ }
+
let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2);
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
@@ -44,16 +53,6 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
});
- // The desugaring of an async function includes a closure containing the
- // original function body, and a terminator that returns the `impl Future`.
- // That terminator will cause a confusing coverage count for the function's
- // closing brace, so discard everything after the body closure span.
- if let Some(body_closure_index) =
- initial_spans.iter().rposition(|covspan| covspan.is_closure && covspan.span == body_span)
- {
- initial_spans.truncate(body_closure_index + 1);
- }
-
initial_spans
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 9e3637ea9f34..c077e0a83a1b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -10,13 +10,13 @@ use crate::errors::{
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
- HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
- IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
- SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
- StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt,
- SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam,
- UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
- UseEqInstead, WrapType,
+ HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
+ IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
+ QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+ StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
+ SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
+ UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+ UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
};
use crate::fluent_generated as fluent;
use crate::parser;
@@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
}
}
+ // Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
+ // here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
+ // a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
+ // where c-string literals are not allowed. There is the very slight possibility of a false
+ // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
+ // that in the parser requires unbounded lookahead, so we only add a hint to the existing
+ // error rather than replacing it entirely.
+ if ((self.prev_token.kind == TokenKind::Ident(sym::c, false)
+ && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
+ || (self.prev_token.kind == TokenKind::Ident(sym::cr, false)
+ && matches!(
+ &self.token.kind,
+ TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
+ )))
+ && self.prev_token.span.hi() == self.token.span.lo()
+ && !self.token.span.at_least_rust_2021()
+ {
+ err.note("you may be trying to write a c-string literal");
+ err.note("c-string literals require Rust 2021 or later");
+ HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
+ }
+
// `pub` may be used for an item or `pub(crate)`
if self.prev_token.is_ident_named(sym::public)
&& (self.token.can_begin_item()
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index bf619daba501..09ee042ef6b4 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1484,7 +1484,7 @@ impl<'a> Parser<'a> {
(thin_vec![], true)
}
};
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
let body = match this.parse_tuple_struct_body() {
Ok(body) => body,
@@ -1569,7 +1569,7 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
}
// No `where` so: `struct Foo;`
} else if self.eat(&token::Semi) {
@@ -1581,7 +1581,7 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
@@ -1610,14 +1610,14 @@ impl<'a> Parser<'a> {
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
} else if self.token == token::OpenDelim(Delimiter::Brace) {
let (fields, recovered) = self.parse_record_struct_body(
"union",
class_name.span,
generics.where_clause.has_where_token,
)?;
- VariantData::Struct(fields, recovered)
+ VariantData::Struct { fields, recovered }
} else {
let token_str = super::token_descr(&self.token);
let msg = format!("expected `where` or `{{` after union name, found {token_str}");
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 5f767c9acaaa..d8b9f4fae87f 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -83,9 +83,6 @@ fn all_diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems {
// Collect diagnostic items in other crates.
for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) {
- // We are collecting many DiagnosticItems hash maps into one
- // DiagnosticItems hash map. The iteration order does not matter.
- #[allow(rustc::potential_query_instability)]
for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id {
collect_item(tcx, &mut items, name, def_id);
}
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 0639944a45c9..908d00cf1056 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -6,17 +6,40 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
rustc_apfloat = "0.2.0"
-rustc_arena = { path = "../rustc_arena" }
-rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_index = { path = "../rustc_index" }
-rustc_macros = { path = "../rustc_macros" }
-rustc_middle = { path = "../rustc_middle" }
-rustc_session = { path = "../rustc_session" }
-rustc_span = { path = "../rustc_span" }
-rustc_target = { path = "../rustc_target" }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+rustc_arena = { path = "../rustc_arena", optional = true }
+rustc_data_structures = { path = "../rustc_data_structures", optional = true }
+rustc_errors = { path = "../rustc_errors", optional = true }
+rustc_fluent_macro = { path = "../rustc_fluent_macro", optional = true }
+rustc_hir = { path = "../rustc_hir", optional = true }
+rustc_index = { path = "../rustc_index", default-features = false }
+rustc_macros = { path = "../rustc_macros", optional = true }
+rustc_middle = { path = "../rustc_middle", optional = true }
+rustc_session = { path = "../rustc_session", optional = true }
+rustc_span = { path = "../rustc_span", optional = true }
+rustc_target = { path = "../rustc_target", optional = true }
+smallvec = { version = "1.8.1", features = ["union"] }
tracing = "0.1"
+typed-arena = { version = "2.0.2", optional = true }
# tidy-alphabetical-end
+
+[features]
+default = ["rustc"]
+# It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
+# we use another feature instead. The crate won't compile if one of these isn't enabled.
+rustc = [
+ "dep:rustc_arena",
+ "dep:rustc_data_structures",
+ "dep:rustc_errors",
+ "dep:rustc_fluent_macro",
+ "dep:rustc_hir",
+ "dep:rustc_macros",
+ "dep:rustc_middle",
+ "dep:rustc_session",
+ "dep:rustc_span",
+ "dep:rustc_target",
+ "smallvec/may_dangle",
+ "rustc_index/nightly",
+]
+stable = [
+ "dep:typed-arena",
+]
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 6486ad8b483a..af0a7497a34f 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -40,7 +40,7 @@
//! - That have no non-trivial intersection with any of the constructors in the column (i.e. they're
//! each either disjoint with or covered by any given column constructor).
//!
-//! We compute this in two steps: first [`crate::cx::MatchCheckCtxt::ctors_for_ty`] determines the
+//! We compute this in two steps: first [`TypeCx::ctors_for_ty`] determines the
//! set of all possible constructors for the type. Then [`ConstructorSet::split`] looks at the
//! column of constructors and splits the set into groups accordingly. The precise invariants of
//! [`ConstructorSet::split`] is described in [`SplitConstructorSet`].
@@ -136,7 +136,7 @@
//! the algorithm can't distinguish them from a nonempty constructor. The only known case where this
//! could happen is the `[..]` pattern on `[!; N]` with `N > 0` so we must take care to not emit it.
//!
-//! This is all handled by [`crate::cx::MatchCheckCtxt::ctors_for_ty`] and
+//! This is all handled by [`TypeCx::ctors_for_ty`] and
//! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest.
//!
//!
@@ -155,17 +155,15 @@ use std::iter::once;
use smallvec::SmallVec;
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::RangeEnd;
+use rustc_index::bit_set::{BitSet, GrowableBitSet};
use rustc_index::IndexVec;
-use rustc_middle::mir::Const;
-use rustc_target::abi::VariantIdx;
use self::Constructor::*;
use self::MaybeInfiniteInt::*;
use self::SliceKind::*;
-use crate::usefulness::PatCtxt;
+use crate::usefulness::PlaceCtxt;
+use crate::TypeCx;
/// Whether we have seen a constructor in the column or not.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -174,6 +172,21 @@ enum Presence {
Seen,
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum RangeEnd {
+ Included,
+ Excluded,
+}
+
+impl fmt::Display for RangeEnd {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match self {
+ RangeEnd::Included => "..=",
+ RangeEnd::Excluded => "..",
+ })
+ }
+}
+
/// A possibly infinite integer. Values are encoded such that the ordering on `u128` matches the
/// natural order on the original type. For example, `-128i8` is encoded as `0` and `127i8` as
/// `255`. See `signed_bias` for details.
@@ -221,7 +234,7 @@ impl MaybeInfiniteInt {
match self {
Finite(n) => match n.checked_sub(1) {
Some(m) => Finite(m),
- None => bug!(),
+ None => panic!("Called `MaybeInfiniteInt::minus_one` on 0"),
},
JustAfterMax => Finite(u128::MAX),
x => x,
@@ -234,7 +247,7 @@ impl MaybeInfiniteInt {
Some(m) => Finite(m),
None => JustAfterMax,
},
- JustAfterMax => bug!(),
+ JustAfterMax => panic!("Called `MaybeInfiniteInt::plus_one` on u128::MAX+1"),
x => x,
}
}
@@ -253,7 +266,7 @@ pub struct IntRange {
impl IntRange {
/// Best effort; will not know that e.g. `255u8..` is a singleton.
- pub(crate) fn is_singleton(&self) -> bool {
+ pub fn is_singleton(&self) -> bool {
// Since `lo` and `hi` can't be the same `Infinity` and `plus_one` never changes from finite
// to infinite, this correctly only detects ranges that contain exacly one `Finite(x)`.
self.lo.plus_one() == self.hi
@@ -271,7 +284,7 @@ impl IntRange {
}
if lo >= hi {
// This should have been caught earlier by E0030.
- bug!("malformed range pattern: {lo:?}..{hi:?}");
+ panic!("malformed range pattern: {lo:?}..{hi:?}");
}
IntRange { lo, hi }
}
@@ -432,7 +445,7 @@ impl Slice {
let kind = match (array_len, kind) {
// If the middle `..` has length 0, we effectively have a fixed-length pattern.
(Some(len), VarLen(prefix, suffix)) if prefix + suffix == len => FixedLen(len),
- (Some(len), VarLen(prefix, suffix)) if prefix + suffix > len => bug!(
+ (Some(len), VarLen(prefix, suffix)) if prefix + suffix > len => panic!(
"Slice pattern of length {} longer than its array length {len}",
prefix + suffix
),
@@ -532,7 +545,7 @@ impl Slice {
// therefore `Presence::Seen` in the column.
let mut min_var_len = usize::MAX;
// Tracks the fixed-length slices we've seen, to mark them as `Presence::Seen`.
- let mut seen_fixed_lens = FxHashSet::default();
+ let mut seen_fixed_lens = GrowableBitSet::new_empty();
match &mut max_slice {
VarLen(max_prefix_len, max_suffix_len) => {
// A length larger than any fixed-length slice encountered.
@@ -600,7 +613,7 @@ impl Slice {
smaller_lengths.map(FixedLen).chain(once(max_slice)).map(move |kind| {
let arity = kind.arity();
- let seen = if min_var_len <= arity || seen_fixed_lens.contains(&arity) {
+ let seen = if min_var_len <= arity || seen_fixed_lens.contains(arity) {
Presence::Seen
} else {
Presence::Unseen
@@ -630,12 +643,17 @@ impl OpaqueId {
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
/// `Fields`.
#[derive(Clone, Debug, PartialEq)]
-pub enum Constructor<'tcx> {
- /// The constructor for patterns that have a single constructor, like tuples, struct patterns,
- /// and references. Fixed-length arrays are treated separately with `Slice`.
- Single,
+pub enum Constructor {
+ /// Tuples and structs.
+ Struct,
/// Enum variants.
- Variant(VariantIdx),
+ Variant(Cx::VariantIdx),
+ /// References
+ Ref,
+ /// Array and slice patterns.
+ Slice(Slice),
+ /// Union field accesses.
+ UnionField,
/// Booleans
Bool(bool),
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
@@ -644,9 +662,7 @@ pub enum Constructor<'tcx> {
F32Range(IeeeFloat, IeeeFloat, RangeEnd),
F64Range(IeeeFloat, IeeeFloat, RangeEnd),
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
- Str(Const<'tcx>),
- /// Array and slice patterns.
- Slice(Slice),
+ Str(Cx::StrLit),
/// Constants that must not be matched structurally. They are treated as black boxes for the
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
/// match exhaustive.
@@ -669,12 +685,12 @@ pub enum Constructor<'tcx> {
Missing,
}
-impl<'tcx> Constructor<'tcx> {
+impl Constructor {
pub(crate) fn is_non_exhaustive(&self) -> bool {
matches!(self, NonExhaustive)
}
- pub(crate) fn as_variant(&self) -> Option {
+ pub(crate) fn as_variant(&self) -> Option {
match self {
Variant(i) => Some(*i),
_ => None,
@@ -701,8 +717,8 @@ impl<'tcx> Constructor<'tcx> {
/// The number of fields for this constructor. This must be kept in sync with
/// `Fields::wildcards`.
- pub(crate) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
- pcx.cx.ctor_arity(self, pcx.ty)
+ pub(crate) fn arity(&self, pcx: &PlaceCtxt<'_, '_, Cx>) -> usize {
+ pcx.ctor_arity(self)
}
/// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
@@ -710,20 +726,20 @@ impl<'tcx> Constructor<'tcx> {
/// this checks for inclusion.
// We inline because this has a single call site in `Matrix::specialize_constructor`.
#[inline]
- pub(crate) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+ pub(crate) fn is_covered_by<'p>(&self, pcx: &PlaceCtxt<'_, 'p, Cx>, other: &Self) -> bool {
match (self, other) {
- (Wildcard, _) => {
- span_bug!(
- pcx.cx.scrut_span,
- "Constructor splitting should not have returned `Wildcard`"
- )
- }
+ (Wildcard, _) => pcx
+ .mcx
+ .tycx
+ .bug(format_args!("Constructor splitting should not have returned `Wildcard`")),
// Wildcards cover anything
(_, Wildcard) => true,
// Only a wildcard pattern can match these special constructors.
(Missing { .. } | NonExhaustive | Hidden, _) => false,
- (Single, Single) => true,
+ (Struct, Struct) => true,
+ (Ref, Ref) => true,
+ (UnionField, UnionField) => true,
(Variant(self_id), Variant(other_id)) => self_id == other_id,
(Bool(self_b), Bool(other_b)) => self_b == other_b,
@@ -756,12 +772,9 @@ impl<'tcx> Constructor<'tcx> {
(Opaque(self_id), Opaque(other_id)) => self_id == other_id,
(Opaque(..), _) | (_, Opaque(..)) => false,
- _ => span_bug!(
- pcx.cx.scrut_span,
- "trying to compare incompatible constructors {:?} and {:?}",
- self,
- other
- ),
+ _ => pcx.mcx.tycx.bug(format_args!(
+ "trying to compare incompatible constructors {self:?} and {other:?}"
+ )),
}
}
}
@@ -785,13 +798,16 @@ pub enum VariantVisibility {
/// In terms of division of responsibility, [`ConstructorSet::split`] handles all of the
/// `exhaustive_patterns` feature.
#[derive(Debug)]
-pub enum ConstructorSet {
- /// The type has a single constructor, e.g. `&T` or a struct. `empty` tracks whether the
- /// constructor is empty.
- Single { empty: bool },
+pub enum ConstructorSet {
+ /// The type is a tuple or struct. `empty` tracks whether the type is empty.
+ Struct { empty: bool },
/// This type has the following list of constructors. If `variants` is empty and
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
- Variants { variants: IndexVec, non_exhaustive: bool },
+ Variants { variants: IndexVec, non_exhaustive: bool },
+ /// The type is `&T`.
+ Ref,
+ /// The type is a union.
+ Union,
/// Booleans.
Bool,
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
@@ -830,25 +846,25 @@ pub enum ConstructorSet {
/// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
/// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4.
#[derive(Debug)]
-pub(crate) struct SplitConstructorSet<'tcx> {
- pub(crate) present: SmallVec<[Constructor<'tcx>; 1]>,
- pub(crate) missing: Vec>,
- pub(crate) missing_empty: Vec>,
+pub(crate) struct SplitConstructorSet {
+ pub(crate) present: SmallVec<[Constructor; 1]>,
+ pub(crate) missing: Vec>,
+ pub(crate) missing_empty: Vec>,
}
-impl ConstructorSet {
+impl ConstructorSet {
/// This analyzes a column of constructors to 1/ determine which constructors of the type (if
/// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
/// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
/// and its invariants.
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
- pub(crate) fn split<'a, 'tcx>(
+ pub(crate) fn split<'a>(
&self,
- pcx: &PatCtxt<'_, '_, 'tcx>,
- ctors: impl Iterator
- > + Clone,
- ) -> SplitConstructorSet<'tcx>
+ pcx: &PlaceCtxt<'_, '_, Cx>,
+ ctors: impl Iterator
- > + Clone,
+ ) -> SplitConstructorSet
where
- 'tcx: 'a,
+ Cx: 'a,
{
let mut present: SmallVec<[_; 1]> = SmallVec::new();
// Empty constructors found missing.
@@ -866,22 +882,39 @@ impl ConstructorSet {
}
match self {
- ConstructorSet::Single { empty } => {
+ ConstructorSet::Struct { empty } => {
if !seen.is_empty() {
- present.push(Single);
+ present.push(Struct);
} else if *empty {
- missing_empty.push(Single);
+ missing_empty.push(Struct);
} else {
- missing.push(Single);
+ missing.push(Struct);
+ }
+ }
+ ConstructorSet::Ref => {
+ if !seen.is_empty() {
+ present.push(Ref);
+ } else {
+ missing.push(Ref);
+ }
+ }
+ ConstructorSet::Union => {
+ if !seen.is_empty() {
+ present.push(UnionField);
+ } else {
+ missing.push(UnionField);
}
}
ConstructorSet::Variants { variants, non_exhaustive } => {
- let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect();
+ let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len());
+ for idx in seen.iter().map(|c| c.as_variant().unwrap()) {
+ seen_set.insert(idx);
+ }
let mut skipped_a_hidden_variant = false;
for (idx, visibility) in variants.iter_enumerated() {
let ctor = Variant(idx);
- if seen_set.contains(&idx) {
+ if seen_set.contains(idx) {
present.push(ctor);
} else {
// We only put visible variants directly into `missing`.
@@ -975,8 +1008,8 @@ impl ConstructorSet {
// We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
- if !pcx.cx.tcx.features().exhaustive_patterns
- && !(pcx.is_top_level && matches!(self, Self::NoConstructors))
+ if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
+ && !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
{
// Treat all missing constructors as nonempty.
// This clears `missing_empty`.
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 0efa8a0ec084..88770b0c43b3 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -1,11 +1,11 @@
-use crate::{cx::MatchCheckCtxt, pat::WitnessPat};
-
use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::thir::Pat;
use rustc_middle::ty::Ty;
use rustc_span::Span;
+use crate::rustc::{RustcMatchCheckCtxt, WitnessPat};
+
#[derive(Subdiagnostic)]
#[label(pattern_analysis_uncovered)]
pub struct Uncovered<'tcx> {
@@ -21,8 +21,8 @@ pub struct Uncovered<'tcx> {
impl<'tcx> Uncovered<'tcx> {
pub fn new<'p>(
span: Span,
- cx: &MatchCheckCtxt<'p, 'tcx>,
- witnesses: Vec>,
+ cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+ witnesses: Vec>,
) -> Self {
let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap());
Self {
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 07730aa49d3f..785a60e99784 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -1,54 +1,133 @@
//! Analysis of patterns, notably match exhaustiveness checking.
pub mod constructor;
-pub mod cx;
+#[cfg(feature = "rustc")]
pub mod errors;
+#[cfg(feature = "rustc")]
pub(crate) mod lints;
pub mod pat;
+#[cfg(feature = "rustc")]
+pub mod rustc;
pub mod usefulness;
#[macro_use]
extern crate tracing;
+#[cfg(feature = "rustc")]
#[macro_use]
extern crate rustc_middle;
+#[cfg(feature = "rustc")]
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
-use lints::PatternColumn;
-use rustc_hir::HirId;
-use rustc_middle::ty::Ty;
-use usefulness::{compute_match_usefulness, UsefulnessReport};
+use std::fmt;
-use crate::cx::MatchCheckCtxt;
-use crate::lints::{lint_nonexhaustive_missing_variants, lint_overlapping_range_endpoints};
+use rustc_index::Idx;
+#[cfg(feature = "rustc")]
+use rustc_middle::ty::Ty;
+
+use crate::constructor::{Constructor, ConstructorSet};
+#[cfg(feature = "rustc")]
+use crate::lints::{
+ lint_nonexhaustive_missing_variants, lint_overlapping_range_endpoints, PatternColumn,
+};
use crate::pat::DeconstructedPat;
+#[cfg(feature = "rustc")]
+use crate::rustc::RustcMatchCheckCtxt;
+#[cfg(feature = "rustc")]
+use crate::usefulness::{compute_match_usefulness, ValidityConstraint};
+
+// It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
+// we use another feature instead. The crate won't compile if one of these isn't enabled.
+#[cfg(feature = "rustc")]
+pub(crate) use rustc_arena::TypedArena;
+#[cfg(feature = "stable")]
+pub(crate) use typed_arena::Arena as TypedArena;
+
+pub trait Captures<'a> {}
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+/// Context that provides type information about constructors.
+///
+/// Most of the crate is parameterized on a type that implements this trait.
+pub trait TypeCx: Sized + Clone + fmt::Debug {
+ /// The type of a pattern.
+ type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
+ /// The index of an enum variant.
+ type VariantIdx: Clone + Idx;
+ /// A string literal
+ type StrLit: Clone + PartialEq + fmt::Debug;
+ /// Extra data to store in a match arm.
+ type ArmData: Copy + Clone + fmt::Debug;
+ /// Extra data to store in a pattern. `Default` needed when we create fictitious wildcard
+ /// patterns during analysis.
+ type PatData: Clone + Default;
+
+ fn is_opaque_ty(ty: Self::Ty) -> bool;
+ fn is_exhaustive_patterns_feature_on(&self) -> bool;
+
+ /// The number of fields for this constructor.
+ fn ctor_arity(&self, ctor: &Constructor, ty: Self::Ty) -> usize;
+
+ /// The types of the fields for this constructor. The result must have a length of
+ /// `ctor_arity()`.
+ fn ctor_sub_tys(&self, ctor: &Constructor, ty: Self::Ty) -> &[Self::Ty];
+
+ /// The set of all the constructors for `ty`.
+ ///
+ /// This must follow the invariants of `ConstructorSet`
+ fn ctors_for_ty(&self, ty: Self::Ty) -> ConstructorSet;
+
+ /// Best-effort `Debug` implementation.
+ fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
+
+ /// Raise a bug.
+ fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
+}
+
+/// Context that provides information global to a match.
+#[derive(Clone)]
+pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
+ /// The context for type information.
+ pub tycx: &'a Cx,
+ /// An arena to store the wildcards we produce during analysis.
+ pub wildcard_arena: &'a TypedArena>,
+}
+
+impl<'a, 'p, Cx: TypeCx> Copy for MatchCtxt<'a, 'p, Cx> {}
/// The arm of a match expression.
-#[derive(Clone, Copy, Debug)]
-pub struct MatchArm<'p, 'tcx> {
- /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
- pub pat: &'p DeconstructedPat<'p, 'tcx>,
- pub hir_id: HirId,
+#[derive(Clone, Debug)]
+pub struct MatchArm<'p, Cx: TypeCx> {
+ pub pat: &'p DeconstructedPat<'p, Cx>,
pub has_guard: bool,
+ pub arm_data: Cx::ArmData,
}
+impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
+
/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
/// useful, and runs some lints.
+#[cfg(feature = "rustc")]
pub fn analyze_match<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- arms: &[MatchArm<'p, 'tcx>],
+ tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
+ arms: &[rustc::MatchArm<'p, 'tcx>],
scrut_ty: Ty<'tcx>,
-) -> UsefulnessReport<'p, 'tcx> {
- let pat_column = PatternColumn::new(arms);
+) -> rustc::UsefulnessReport<'p, 'tcx> {
+ // Arena to store the extra wildcards we construct during analysis.
+ let wildcard_arena = tycx.pattern_arena;
+ let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
+ let cx = MatchCtxt { tycx, wildcard_arena };
- let report = compute_match_usefulness(cx, arms, scrut_ty);
+ let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
+
+ let pat_column = PatternColumn::new(arms);
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
lint_overlapping_range_endpoints(cx, &pat_column);
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
- if cx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
+ if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
}
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 8ab559c9e7a4..072ef4836a84 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -6,15 +6,16 @@ use rustc_session::lint;
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::Span;
-use crate::constructor::{Constructor, IntRange, MaybeInfiniteInt, SplitConstructorSet};
-use crate::cx::MatchCheckCtxt;
+use crate::constructor::{IntRange, MaybeInfiniteInt};
use crate::errors::{
NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap,
OverlappingRangeEndpoints, Uncovered,
};
-use crate::pat::{DeconstructedPat, WitnessPat};
-use crate::usefulness::PatCtxt;
-use crate::MatchArm;
+use crate::rustc::{
+ Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RustcMatchCheckCtxt,
+ SplitConstructorSet, WitnessPat,
+};
+use crate::TypeCx;
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
/// inspect the same subvalue/place".
@@ -27,11 +28,11 @@ use crate::MatchArm;
///
/// This is not used in the main algorithm; only in lints.
#[derive(Debug)]
-pub(crate) struct PatternColumn<'p, 'tcx> {
- patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>,
+pub(crate) struct PatternColumn<'a, 'p, 'tcx> {
+ patterns: Vec<&'a DeconstructedPat<'p, 'tcx>>,
}
-impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
+impl<'a, 'p, 'tcx> PatternColumn<'a, 'p, 'tcx> {
pub(crate) fn new(arms: &[MatchArm<'p, 'tcx>]) -> Self {
let mut patterns = Vec::with_capacity(arms.len());
for arm in arms {
@@ -53,12 +54,11 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
}
// If the type is opaque and it is revealed anywhere in the column, we take the revealed
// version. Otherwise we could encounter constructors for the revealed type and crash.
- let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..));
let first_ty = self.patterns[0].ty();
- if is_opaque(first_ty) {
+ if RustcMatchCheckCtxt::is_opaque_ty(first_ty) {
for pat in &self.patterns {
let ty = pat.ty();
- if !is_opaque(ty) {
+ if !RustcMatchCheckCtxt::is_opaque_ty(ty) {
return Some(ty);
}
}
@@ -67,12 +67,12 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
}
/// Do constructor splitting on the constructors of the column.
- fn analyze_ctors(&self, pcx: &PatCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'tcx> {
+ fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> {
let column_ctors = self.patterns.iter().map(|p| p.ctor());
- pcx.cx.ctors_for_ty(pcx.ty).split(pcx, column_ctors)
+ pcx.ctors_for_ty().split(pcx, column_ctors)
}
- fn iter<'a>(&'a self) -> impl Iterator
- > + Captures<'a> {
+ fn iter<'b>(&'b self) -> impl Iterator
- > + Captures<'b> {
self.patterns.iter().copied()
}
@@ -81,7 +81,11 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
/// This returns one column per field of the constructor. They usually all have the same length
/// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns
/// which may change the lengths.
- fn specialize(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Vec {
+ fn specialize(
+ &self,
+ pcx: &PlaceCtxt<'a, 'p, 'tcx>,
+ ctor: &Constructor<'p, 'tcx>,
+ ) -> Vec> {
let arity = ctor.arity(pcx);
if arity == 0 {
return Vec::new();
@@ -117,14 +121,14 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
/// in a given column.
#[instrument(level = "debug", skip(cx), ret)]
-fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- column: &PatternColumn<'p, 'tcx>,
-) -> Vec> {
+fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
+ cx: MatchCtxt<'a, 'p, 'tcx>,
+ column: &PatternColumn<'a, 'p, 'tcx>,
+) -> Vec> {
let Some(ty) = column.head_ty() else {
return Vec::new();
};
- let pcx = &PatCtxt::new_dummy(cx, ty);
+ let pcx = &PlaceCtxt::new_dummy(cx, ty);
let set = column.analyze_ctors(pcx);
if set.present.is_empty() {
@@ -135,7 +139,7 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
}
let mut witnesses = Vec::new();
- if cx.is_foreign_non_exhaustive_enum(ty) {
+ if cx.tycx.is_foreign_non_exhaustive_enum(ty) {
witnesses.extend(
set.missing
.into_iter()
@@ -164,14 +168,15 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
witnesses
}
-pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
+pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
+ cx: MatchCtxt<'a, 'p, 'tcx>,
arms: &[MatchArm<'p, 'tcx>],
- pat_column: &PatternColumn<'p, 'tcx>,
+ pat_column: &PatternColumn<'a, 'p, 'tcx>,
scrut_ty: Ty<'tcx>,
) {
+ let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
if !matches!(
- cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, cx.match_lint_level).0,
+ rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
rustc_session::lint::Level::Allow
) {
let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column);
@@ -180,13 +185,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
// is not exhaustive enough.
//
// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
- cx.tcx.emit_spanned_lint(
+ rcx.tcx.emit_spanned_lint(
NON_EXHAUSTIVE_OMITTED_PATTERNS,
- cx.match_lint_level,
- cx.scrut_span,
+ rcx.match_lint_level,
+ rcx.scrut_span,
NonExhaustiveOmittedPattern {
scrut_ty,
- uncovered: Uncovered::new(cx.scrut_span, cx, witnesses),
+ uncovered: Uncovered::new(rcx.scrut_span, rcx, witnesses),
},
);
}
@@ -196,17 +201,17 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
// usage of the lint.
for arm in arms {
let (lint_level, lint_level_source) =
- cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.hir_id);
+ rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data);
if !matches!(lint_level, rustc_session::lint::Level::Allow) {
let decorator = NonExhaustiveOmittedPatternLintOnArm {
lint_span: lint_level_source.span(),
- suggest_lint_on_match: cx.whole_match_span.map(|span| span.shrink_to_lo()),
+ suggest_lint_on_match: rcx.whole_match_span.map(|span| span.shrink_to_lo()),
lint_level: lint_level.as_str(),
lint_name: "non_exhaustive_omitted_patterns",
};
use rustc_errors::DecorateLint;
- let mut err = cx.tcx.sess.struct_span_warn(arm.pat.span(), "");
+ let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data(), "");
err.set_primary_message(decorator.msg());
decorator.decorate_lint(&mut err);
err.emit();
@@ -217,28 +222,29 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
#[instrument(level = "debug", skip(cx))]
-pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
- cx: &MatchCheckCtxt<'p, 'tcx>,
- column: &PatternColumn<'p, 'tcx>,
+pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
+ cx: MatchCtxt<'a, 'p, 'tcx>,
+ column: &PatternColumn<'a, 'p, 'tcx>,
) {
let Some(ty) = column.head_ty() else {
return;
};
- let pcx = &PatCtxt::new_dummy(cx, ty);
+ let pcx = &PlaceCtxt::new_dummy(cx, ty);
+ let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
let set = column.analyze_ctors(pcx);
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
- let overlap_as_pat = cx.hoist_pat_range(overlap, ty);
+ let overlap_as_pat = rcx.hoist_pat_range(overlap, ty);
let overlaps: Vec<_> = overlapped_spans
.iter()
.copied()
.map(|span| Overlap { range: overlap_as_pat.clone(), span })
.collect();
- cx.tcx.emit_spanned_lint(
+ rcx.tcx.emit_spanned_lint(
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
- cx.match_lint_level,
+ rcx.match_lint_level,
this_span,
OverlappingRangeEndpoints { overlap: overlaps, range: this_span },
);
@@ -255,7 +261,7 @@ pub(crate) fn lint_overlapping_range_endpoints<'p, 'tcx>(
let mut suffixes: SmallVec<[_; 1]> = Default::default();
// Iterate on patterns that contained `overlap`.
for pat in column.iter() {
- let this_span = pat.span();
+ let this_span = *pat.data();
let Constructor::IntRange(this_range) = pat.ctor() else { continue };
if this_range.is_singleton() {
// Don't lint when one of the ranges is a singleton.
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 404651124ad3..0cc8477b7cdc 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -5,16 +5,11 @@ use std::fmt;
use smallvec::{smallvec, SmallVec};
-use rustc_data_structures::captures::Captures;
-use rustc_middle::ty::{self, Ty};
-use rustc_span::{Span, DUMMY_SP};
+use crate::constructor::{Constructor, Slice, SliceKind};
+use crate::usefulness::PlaceCtxt;
+use crate::{Captures, TypeCx};
use self::Constructor::*;
-use self::SliceKind::*;
-
-use crate::constructor::{Constructor, SliceKind};
-use crate::cx::MatchCheckCtxt;
-use crate::usefulness::PatCtxt;
/// Values and patterns can be represented as a constructor applied to some fields. This represents
/// a pattern in this form.
@@ -27,34 +22,34 @@ use crate::usefulness::PatCtxt;
/// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
/// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
/// be taken when converting to/from `thir::Pat`.
-pub struct DeconstructedPat<'p, 'tcx> {
- ctor: Constructor<'tcx>,
- fields: &'p [DeconstructedPat<'p, 'tcx>],
- ty: Ty<'tcx>,
- span: Span,
+pub struct DeconstructedPat<'p, Cx: TypeCx> {
+ ctor: Constructor,
+ fields: &'p [DeconstructedPat<'p, Cx>],
+ ty: Cx::Ty,
+ data: Cx::PatData,
/// Whether removing this arm would change the behavior of the match expression.
useful: Cell,
}
-impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
- pub fn wildcard(ty: Ty<'tcx>, span: Span) -> Self {
- Self::new(Wildcard, &[], ty, span)
+impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
+ pub fn wildcard(ty: Cx::Ty, data: Cx::PatData) -> Self {
+ Self::new(Wildcard, &[], ty, data)
}
pub fn new(
- ctor: Constructor<'tcx>,
- fields: &'p [DeconstructedPat<'p, 'tcx>],
- ty: Ty<'tcx>,
- span: Span,
+ ctor: Constructor,
+ fields: &'p [DeconstructedPat<'p, Cx>],
+ ty: Cx::Ty,
+ data: Cx::PatData,
) -> Self {
- DeconstructedPat { ctor, fields, ty, span, useful: Cell::new(false) }
+ DeconstructedPat { ctor, fields, ty, data, useful: Cell::new(false) }
}
pub(crate) fn is_or_pat(&self) -> bool {
matches!(self.ctor, Or)
}
/// Expand this (possibly-nested) or-pattern into its alternatives.
- pub(crate) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> {
+ pub(crate) fn flatten_or_pat(&self) -> SmallVec<[&Self; 1]> {
if self.is_or_pat() {
self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect()
} else {
@@ -62,66 +57,64 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
}
- pub fn ctor(&self) -> &Constructor<'tcx> {
+ pub fn ctor(&self) -> &Constructor {
&self.ctor
}
- pub fn ty(&self) -> Ty<'tcx> {
+ pub fn ty(&self) -> Cx::Ty {
self.ty
}
- pub fn span(&self) -> Span {
- self.span
+ pub fn data(&self) -> &Cx::PatData {
+ &self.data
}
pub fn iter_fields<'a>(
&'a self,
- ) -> impl Iterator
- > + Captures<'a> {
+ ) -> impl Iterator
- > + Captures<'a> {
self.fields.iter()
}
/// Specialize this pattern with a constructor.
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
pub(crate) fn specialize<'a>(
- &'a self,
- pcx: &PatCtxt<'_, 'p, 'tcx>,
- other_ctor: &Constructor<'tcx>,
- ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
+ &self,
+ pcx: &PlaceCtxt<'a, 'p, Cx>,
+ other_ctor: &Constructor,
+ ) -> SmallVec<[&'a DeconstructedPat<'p, Cx>; 2]> {
+ let wildcard_sub_tys = || {
+ let tys = pcx.ctor_sub_tys(other_ctor);
+ tys.iter()
+ .map(|ty| DeconstructedPat::wildcard(*ty, Cx::PatData::default()))
+ .map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
+ .collect()
+ };
match (&self.ctor, other_ctor) {
- (Wildcard, _) => {
- // We return a wildcard for each field of `other_ctor`.
- pcx.cx.ctor_wildcard_fields(other_ctor, pcx.ty).iter().collect()
- }
- (Slice(self_slice), Slice(other_slice))
- if self_slice.arity() != other_slice.arity() =>
- {
- // The only tricky case: two slices of different arity. Since `self_slice` covers
- // `other_slice`, `self_slice` must be `VarLen`, i.e. of the form
- // `[prefix, .., suffix]`. Moreover `other_slice` is guaranteed to have a larger
- // arity. So we fill the middle part with enough wildcards to reach the length of
- // the new, larger slice.
- match self_slice.kind {
- FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice),
- VarLen(prefix, suffix) => {
- let (ty::Slice(inner_ty) | ty::Array(inner_ty, _)) = *self.ty.kind() else {
- bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty);
- };
- let prefix = &self.fields[..prefix];
- let suffix = &self.fields[self_slice.arity() - suffix..];
- let wildcard: &_ = pcx
- .cx
- .pattern_arena
- .alloc(DeconstructedPat::wildcard(inner_ty, DUMMY_SP));
- let extra_wildcards = other_slice.arity() - self_slice.arity();
- let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
- prefix.iter().chain(extra_wildcards).chain(suffix).collect()
- }
+ // Return a wildcard for each field of `other_ctor`.
+ (Wildcard, _) => wildcard_sub_tys(),
+ // The only non-trivial case: two slices of different arity. `other_slice` is
+ // guaranteed to have a larger arity, so we fill the middle part with enough
+ // wildcards to reach the length of the new, larger slice.
+ (
+ &Slice(self_slice @ Slice { kind: SliceKind::VarLen(prefix, suffix), .. }),
+ &Slice(other_slice),
+ ) if self_slice.arity() != other_slice.arity() => {
+ // Start with a slice of wildcards of the appropriate length.
+ let mut fields: SmallVec<[_; 2]> = wildcard_sub_tys();
+ // Fill in the fields from both ends.
+ let new_arity = fields.len();
+ for i in 0..prefix {
+ fields[i] = &self.fields[i];
}
+ for i in 0..suffix {
+ fields[new_arity - 1 - i] = &self.fields[self.fields.len() - 1 - i];
+ }
+ fields
}
_ => self.fields.iter().collect(),
}
}
- /// We keep track for each pattern if it was ever useful during the analysis. This is used
- /// with `redundant_spans` to report redundant subpatterns arising from or patterns.
+ /// We keep track for each pattern if it was ever useful during the analysis. This is used with
+ /// `redundant_subpatterns` to report redundant subpatterns arising from or patterns.
pub(crate) fn set_useful(&self) {
self.useful.set(true)
}
@@ -139,19 +132,19 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
}
- /// Report the spans of subpatterns that were not useful, if any.
- pub(crate) fn redundant_spans(&self) -> Vec {
- let mut spans = Vec::new();
- self.collect_redundant_spans(&mut spans);
- spans
+ /// Report the subpatterns that were not useful, if any.
+ pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
+ let mut subpats = Vec::new();
+ self.collect_redundant_subpatterns(&mut subpats);
+ subpats
}
- fn collect_redundant_spans(&self, spans: &mut Vec) {
+ fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
// We don't look at subpatterns if we already reported the whole pattern as redundant.
if !self.is_useful() {
- spans.push(self.span);
+ subpats.push(self);
} else {
for p in self.iter_fields() {
- p.collect_redundant_spans(spans);
+ p.collect_redundant_subpatterns(subpats);
}
}
}
@@ -159,47 +152,46 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
/// `Display` impl.
-impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
+impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- MatchCheckCtxt::debug_pat(f, self)
+ Cx::debug_pat(f, self)
}
}
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
/// purposes. As such they don't use interning and can be cloned.
#[derive(Debug, Clone)]
-pub struct WitnessPat<'tcx> {
- ctor: Constructor<'tcx>,
- pub(crate) fields: Vec>,
- ty: Ty<'tcx>,
+pub struct WitnessPat {
+ ctor: Constructor,
+ pub(crate) fields: Vec>,
+ ty: Cx::Ty,
}
-impl<'tcx> WitnessPat<'tcx> {
- pub(crate) fn new(ctor: Constructor<'tcx>, fields: Vec, ty: Ty<'tcx>) -> Self {
+impl WitnessPat {
+ pub(crate) fn new(ctor: Constructor, fields: Vec, ty: Cx::Ty) -> Self {
Self { ctor, fields, ty }
}
- pub(crate) fn wildcard(ty: Ty<'tcx>) -> Self {
+ pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
Self::new(Wildcard, Vec::new(), ty)
}
/// Construct a pattern that matches everything that starts with this constructor.
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
/// `Some(_)`.
- pub(crate) fn wild_from_ctor(pcx: &PatCtxt<'_, '_, 'tcx>, ctor: Constructor<'tcx>) -> Self {
- let field_tys =
- pcx.cx.ctor_wildcard_fields(&ctor, pcx.ty).iter().map(|deco_pat| deco_pat.ty());
- let fields = field_tys.map(|ty| Self::wildcard(ty)).collect();
+ pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, '_, Cx>, ctor: Constructor) -> Self {
+ let field_tys = pcx.ctor_sub_tys(&ctor);
+ let fields = field_tys.iter().map(|ty| Self::wildcard(*ty)).collect();
Self::new(ctor, fields, pcx.ty)
}
- pub fn ctor(&self) -> &Constructor<'tcx> {
+ pub fn ctor(&self) -> &Constructor {
&self.ctor
}
- pub fn ty(&self) -> Ty<'tcx> {
+ pub fn ty(&self) -> Cx::Ty {
self.ty
}
- pub fn iter_fields<'a>(&'a self) -> impl Iterator
- > {
+ pub fn iter_fields<'a>(&'a self) -> impl Iterator
- > {
self.fields.iter()
}
}
diff --git a/compiler/rustc_pattern_analysis/src/cx.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
similarity index 82%
rename from compiler/rustc_pattern_analysis/src/cx.rs
rename to compiler/rustc_pattern_analysis/src/rustc.rs
index 8a4f39a1f4ab..65c90aa9f1d2 100644
--- a/compiler/rustc_pattern_analysis/src/cx.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,15 +1,15 @@
use std::fmt;
use std::iter::once;
-use rustc_arena::TypedArena;
+use rustc_arena::{DroplessArena, TypedArena};
use rustc_data_structures::captures::Captures;
use rustc_hir::def_id::DefId;
-use rustc_hir::{HirId, RangeEnd};
+use rustc_hir::HirId;
use rustc_index::Idx;
use rustc_index::IndexVec;
use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::mir;
use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::{self, Const};
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
@@ -18,14 +18,31 @@ use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
use smallvec::SmallVec;
use crate::constructor::{
- Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, OpaqueId, Slice, SliceKind,
- VariantVisibility,
+ IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
};
-use crate::pat::{DeconstructedPat, WitnessPat};
+use crate::TypeCx;
-use Constructor::*;
+use crate::constructor::Constructor::*;
-pub struct MatchCheckCtxt<'p, 'tcx> {
+// Re-export rustc-specific versions of all these types.
+pub type Constructor<'p, 'tcx> = crate::constructor::Constructor>;
+pub type ConstructorSet<'p, 'tcx> =
+ crate::constructor::ConstructorSet>;
+pub type DeconstructedPat<'p, 'tcx> =
+ crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub(crate) type PlaceCtxt<'a, 'p, 'tcx> =
+ crate::usefulness::PlaceCtxt<'a, 'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub(crate) type SplitConstructorSet<'p, 'tcx> =
+ crate::constructor::SplitConstructorSet>;
+pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type UsefulnessReport<'p, 'tcx> =
+ crate::usefulness::UsefulnessReport<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat>;
+
+#[derive(Clone)]
+pub struct RustcMatchCheckCtxt<'p, 'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The module in which the match occurs. This is necessary for
/// checking inhabited-ness of types because whether a type is (visibly)
@@ -35,6 +52,7 @@ pub struct MatchCheckCtxt<'p, 'tcx> {
pub module: DefId,
pub param_env: ty::ParamEnv<'tcx>,
pub pattern_arena: &'p TypedArena>,
+ pub dropless_arena: &'p DroplessArena,
/// Lint level at the match.
pub match_lint_level: HirId,
/// The span of the whole match, if applicable.
@@ -48,8 +66,14 @@ pub struct MatchCheckCtxt<'p, 'tcx> {
pub known_valid_scrutinee: bool,
}
-impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
- pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RustcMatchCheckCtxt").finish()
+ }
+}
+
+impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
+ pub(crate) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
!ty.is_inhabited_from(self.tcx, self.module, self.param_env)
}
@@ -63,12 +87,18 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
}
}
- pub(crate) fn alloc_wildcard_slice(
- &self,
- tys: impl IntoIterator
- >,
- ) -> &'p [DeconstructedPat<'p, 'tcx>] {
- self.pattern_arena
- .alloc_from_iter(tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, DUMMY_SP)))
+ /// Whether the range denotes the fictitious values before `isize::MIN` or after
+ /// `usize::MAX`/`isize::MAX` (see doc of [`IntRange::split`] for why these exist).
+ pub fn is_range_beyond_boundaries(&self, range: &IntRange, ty: Ty<'tcx>) -> bool {
+ ty.is_ptr_sized_integral() && {
+ // The two invalid ranges are `NegInfinity..isize::MIN` (represented as
+ // `NegInfinity..0`), and `{u,i}size::MAX+1..PosInfinity`. `hoist_pat_range_bdy`
+ // converts `MAX+1` to `PosInfinity`, and we couldn't have `PosInfinity` in `range.lo`
+ // otherwise.
+ let lo = self.hoist_pat_range_bdy(range.lo, ty);
+ matches!(lo, PatRangeBoundary::PosInfinity)
+ || matches!(range.hi, MaybeInfiniteInt::Finite(0))
+ }
}
// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
@@ -100,12 +130,12 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
}
pub(crate) fn variant_index_for_adt(
- ctor: &Constructor<'tcx>,
+ ctor: &Constructor<'p, 'tcx>,
adt: ty::AdtDef<'tcx>,
) -> VariantIdx {
match *ctor {
Variant(idx) => idx,
- Single => {
+ Struct | UnionField => {
assert!(!adt.is_enum());
FIRST_VARIANT
}
@@ -113,37 +143,36 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
}
}
- /// Creates a new list of wildcard fields for a given constructor. The result must have a length
- /// of `ctor.arity()`.
+ /// Returns the types of the fields for a given constructor. The result must have a length of
+ /// `ctor.arity()`.
#[instrument(level = "trace", skip(self))]
- pub(crate) fn ctor_wildcard_fields(
- &self,
- ctor: &Constructor<'tcx>,
- ty: Ty<'tcx>,
- ) -> &'p [DeconstructedPat<'p, 'tcx>] {
+ pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<'p, 'tcx>, ty: Ty<'tcx>) -> &[Ty<'tcx>] {
let cx = self;
match ctor {
- Single | Variant(_) => match ty.kind() {
- ty::Tuple(fs) => cx.alloc_wildcard_slice(fs.iter()),
- ty::Ref(_, rty, _) => cx.alloc_wildcard_slice(once(*rty)),
+ Struct | Variant(_) | UnionField => match ty.kind() {
+ ty::Tuple(fs) => cx.dropless_arena.alloc_from_iter(fs.iter()),
ty::Adt(adt, args) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
- cx.alloc_wildcard_slice(once(args.type_at(0)))
+ cx.dropless_arena.alloc_from_iter(once(args.type_at(0)))
} else {
let variant =
- &adt.variant(MatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
+ &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
let tys = cx.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty);
- cx.alloc_wildcard_slice(tys)
+ cx.dropless_arena.alloc_from_iter(tys)
}
}
- _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+ _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
+ },
+ Ref => match ty.kind() {
+ ty::Ref(_, rty, _) => cx.dropless_arena.alloc_from_iter(once(*rty)),
+ _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"),
},
Slice(slice) => match *ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
- cx.alloc_wildcard_slice((0..arity).map(|_| ty))
+ cx.dropless_arena.alloc_from_iter((0..arity).map(|_| ty))
}
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
},
@@ -163,13 +192,11 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
}
}
- /// The number of fields for this constructor. This must be kept in sync with
- /// `Fields::wildcards`.
- pub(crate) fn ctor_arity(&self, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> usize {
+ /// The number of fields for this constructor.
+ pub(crate) fn ctor_arity(&self, ctor: &Constructor<'p, 'tcx>, ty: Ty<'tcx>) -> usize {
match ctor {
- Single | Variant(_) => match ty.kind() {
+ Struct | Variant(_) | UnionField => match ty.kind() {
ty::Tuple(fs) => fs.len(),
- ty::Ref(..) => 1,
ty::Adt(adt, ..) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
@@ -177,12 +204,13 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
1
} else {
let variant =
- &adt.variant(MatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
+ &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
self.list_variant_nonhidden_fields(ty, variant).count()
}
}
- _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+ _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
},
+ Ref => 1,
Slice(slice) => slice.arity(),
Bool(..)
| IntRange(..)
@@ -202,7 +230,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
///
/// See [`crate::constructor`] for considerations of emptiness.
#[instrument(level = "debug", skip(self), ret)]
- pub fn ctors_for_ty(&self, ty: Ty<'tcx>) -> ConstructorSet {
+ pub fn ctors_for_ty(&self, ty: Ty<'tcx>) -> ConstructorSet<'p, 'tcx> {
let cx = self;
let make_uint_range = |start, end| {
IntRange::from_range(
@@ -298,9 +326,9 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
}
}
- ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => {
- ConstructorSet::Single { empty: cx.is_uninhabited(ty) }
- }
+ ty::Adt(def, _) if def.is_union() => ConstructorSet::Union,
+ ty::Adt(..) | ty::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(ty) },
+ ty::Ref(..) => ConstructorSet::Ref,
ty::Never => ConstructorSet::NoConstructors,
// This type is one for which we cannot list constructors, like `str` or `f64`.
// FIXME(Nadrieril): which of these are actually allowed?
@@ -359,13 +387,18 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
fields = &[];
}
PatKind::Deref { subpattern } => {
- ctor = Single;
fields = singleton(self.lower_pat(subpattern));
+ ctor = match pat.ty.kind() {
+ // This is a box pattern.
+ ty::Adt(adt, ..) if adt.is_box() => Struct,
+ ty::Ref(..) => Ref,
+ _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty),
+ };
}
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
match pat.ty.kind() {
ty::Tuple(fs) => {
- ctor = Single;
+ ctor = Struct;
let mut wilds: SmallVec<[_; 2]> =
fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect();
for pat in subpatterns {
@@ -380,7 +413,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
// _)` or a box pattern. As a hack to avoid an ICE with the former, we
// ignore other fields than the first one. This will trigger an error later
// anyway.
- // See https://github.com/rust-lang/rust/issues/82772 ,
+ // See https://github.com/rust-lang/rust/issues/82772,
// explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
// The problem is that we can't know from the type whether we'll match
// normally or through box-patterns. We'll have to figure out a proper
@@ -392,17 +425,18 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
} else {
DeconstructedPat::wildcard(args.type_at(0), pat.span)
};
- ctor = Single;
+ ctor = Struct;
fields = singleton(pat);
}
ty::Adt(adt, _) => {
ctor = match pat.kind {
- PatKind::Leaf { .. } => Single,
+ PatKind::Leaf { .. } if adt.is_union() => UnionField,
+ PatKind::Leaf { .. } => Struct,
PatKind::Variant { variant_index, .. } => Variant(variant_index),
_ => bug!(),
};
let variant =
- &adt.variant(MatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
+ &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
// For each field in the variant, we store the relevant index into `self.fields` if any.
let mut field_id_to_id: Vec