Rollup merge of #74064 - RalfJung:variant-count-bootstrap, r=kennytm
variant_count: avoid incorrect dummy implementation
This also avoids a stage 0 doctest failure.
diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md
new file mode 100644
index 0000000..2967200
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md
@@ -0,0 +1,53 @@
+# `rustc_attrs`
+
+This feature has no tracking issue, and is therefore internal to
+the compiler, not being intended for general use.
+
+Note: `rustc_attrs` enables many rustc-internal attributes and this page
+only discuss a few of them.
+
+------------------------
+
+The `rustc_attrs` feature allows debugging rustc type layouts by using
+`#[rustc_layout(...)]` to debug layout at compile time (it even works
+with `cargo check`) as an alternative to `rustc -Z print-type-sizes`
+that is way more verbose.
+
+Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`.
+Note that it only work best with sized type without generics.
+
+## Examples
+
+```rust,ignore
+#![feature(rustc_attrs)]
+
+#[rustc_layout(abi, size)]
+pub enum X {
+ Y(u8, u8, u8),
+ Z(isize),
+}
+```
+
+When that is compiled, the compiler will error with something like
+
+```text
+error: abi: Aggregate { sized: true }
+ --> src/lib.rs:4:1
+ |
+4 | / pub enum T {
+5 | | Y(u8, u8, u8),
+6 | | Z(isize),
+7 | | }
+ | |_^
+
+error: size: Size { raw: 16 }
+ --> src/lib.rs:4:1
+ |
+4 | / pub enum T {
+5 | | Y(u8, u8, u8),
+6 | | Z(isize),
+7 | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+```
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 13ef94d..5b671b4 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -1774,6 +1774,15 @@
}
}
+#[stable(feature = "box_str2", since = "1.45.0")]
+impl FromIterator<Box<str>> for String {
+ fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
+ let mut buf = String::new();
+ buf.extend(iter);
+ buf
+ }
+}
+
#[stable(feature = "herd_cows", since = "1.19.0")]
impl<'a> FromIterator<Cow<'a, str>> for String {
fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
@@ -1842,6 +1851,13 @@
}
}
+#[stable(feature = "box_str2", since = "1.45.0")]
+impl Extend<Box<str>> for String {
+ fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
+ iter.into_iter().for_each(move |s| self.push_str(&s));
+ }
+}
+
#[stable(feature = "extend_string", since = "1.4.0")]
impl Extend<String> for String {
fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index ac3ce225..2d6a391 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -419,8 +419,7 @@
#[inline]
#[stable(feature = "arc_unique", since = "1.4.0")]
pub fn try_unwrap(this: Self) -> Result<T, Self> {
- // See `drop` for why all these atomics are like this
- if this.inner().strong.compare_exchange(1, 0, Release, Relaxed).is_err() {
+ if this.inner().strong.compare_exchange(1, 0, Relaxed, Relaxed).is_err() {
return Err(this);
}
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 530cf88..ce4be97 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -1521,7 +1521,7 @@
///
/// let iter = a.iter();
///
- /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i );
+ /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i);
///
/// assert_eq!(sum, 6);
///
@@ -1535,7 +1535,7 @@
/// let mut iter = a.iter();
///
/// // instead, we add in a .by_ref()
- /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i );
+ /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i);
///
/// assert_eq!(sum, 3);
///
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 313744e..32481bf 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -570,6 +570,9 @@
/// Allows capturing variables in scope using format_args!
(active, format_args_capture, "1.46.0", Some(67984), None),
+ /// Lazily evaluate constants. This allows constants to depend on type parameters.
+ (active, lazy_normalization_consts, "1.46.0", Some(72219), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@@ -586,5 +589,6 @@
sym::raw_dylib,
sym::const_trait_impl,
sym::const_trait_bound_opt_out,
+ sym::lazy_normalization_consts,
sym::specialization,
];
diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index c8d4e9f..3b564e0 100644
--- a/src/librustc_infer/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -112,7 +112,7 @@
// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
- Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b)))
+ Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
}
_ => ty::relate::super_relate_tys(relation, a, b),
@@ -701,7 +701,7 @@
a_is_expected: bool,
(a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>),
) -> TypeError<'tcx> {
- TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
+ TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
}
fn int_unification_error<'tcx>(
@@ -709,7 +709,7 @@
v: (ty::IntVarValue, ty::IntVarValue),
) -> TypeError<'tcx> {
let (a, b) = v;
- TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
+ TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
}
fn float_unification_error<'tcx>(
@@ -717,5 +717,5 @@
v: (ty::FloatVarValue, ty::FloatVarValue),
) -> TypeError<'tcx> {
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
- TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
+ TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
}
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index d942c07..698bef4 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -1370,7 +1370,7 @@
/// we still evaluate them eagerly.
#[inline]
pub fn lazy_normalization(self) -> bool {
- self.features().const_generics
+ self.features().const_generics || self.features().lazy_normalization_consts
}
#[inline]
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 9fa1260..9dda208 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -282,26 +282,27 @@
// where there is no explicit `extern crate`, we just prepend
// the crate name.
match self.tcx().extern_crate(def_id) {
- Some(&ExternCrate {
- src: ExternCrateSource::Extern(def_id),
- dependency_of: LOCAL_CRATE,
- span,
- ..
- }) => {
- debug!("try_print_visible_def_path: def_id={:?}", def_id);
- return Ok((
- if !span.is_dummy() {
- self.print_def_path(def_id, &[])?
- } else {
- self.path_crate(cnum)?
- },
- true,
- ));
- }
+ Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
+ (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
+ debug!("try_print_visible_def_path: def_id={:?}", def_id);
+ return Ok((
+ if !span.is_dummy() {
+ self.print_def_path(def_id, &[])?
+ } else {
+ self.path_crate(cnum)?
+ },
+ true,
+ ));
+ }
+ (ExternCrateSource::Path, LOCAL_CRATE) => {
+ debug!("try_print_visible_def_path: def_id={:?}", def_id);
+ return Ok((self.path_crate(cnum)?, true));
+ }
+ _ => {}
+ },
None => {
return Ok((self.path_crate(cnum)?, true));
}
- _ => {}
}
}
diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs
index cee04ce..7946a27 100644
--- a/src/librustc_middle/ty/relate.rs
+++ b/src/librustc_middle/ty/relate.rs
@@ -159,8 +159,8 @@
if a.c_variadic != b.c_variadic {
return Err(TypeError::VariadicMismatch(expected_found(
relation,
- &a.c_variadic,
- &b.c_variadic,
+ a.c_variadic,
+ b.c_variadic,
)));
}
let unsafety = relation.relate(a.unsafety, b.unsafety)?;
@@ -200,7 +200,7 @@
b: ast::Unsafety,
) -> RelateResult<'tcx, ast::Unsafety> {
if a != b {
- Err(TypeError::UnsafetyMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
} else {
Ok(a)
}
@@ -213,7 +213,7 @@
a: abi::Abi,
b: abi::Abi,
) -> RelateResult<'tcx, abi::Abi> {
- if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, &a, &b))) }
+ if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) }
}
}
@@ -226,8 +226,8 @@
if a.item_def_id != b.item_def_id {
Err(TypeError::ProjectionMismatched(expected_found(
relation,
- &a.item_def_id,
- &b.item_def_id,
+ a.item_def_id,
+ b.item_def_id,
)))
} else {
let substs = relation.relate(a.substs, b.substs)?;
@@ -245,8 +245,8 @@
if a.item_def_id != b.item_def_id {
Err(TypeError::ProjectionMismatched(expected_found(
relation,
- &a.item_def_id,
- &b.item_def_id,
+ a.item_def_id,
+ b.item_def_id,
)))
} else {
let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
@@ -264,7 +264,7 @@
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
// Different traits cannot be related.
if a.def_id != b.def_id {
- Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
+ Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relate_substs(relation, None, a.substs, b.substs)?;
Ok(ty::TraitRef { def_id: a.def_id, substs })
@@ -280,7 +280,7 @@
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
// Different traits cannot be related.
if a.def_id != b.def_id {
- Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
+ Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relate_substs(relation, None, a.substs, b.substs)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
@@ -305,6 +305,7 @@
}
impl<'tcx> Relate<'tcx> for Ty<'tcx> {
+ #[inline]
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Ty<'tcx>,
@@ -421,7 +422,7 @@
let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize(
- expected_found(relation, &sz_a_val, &sz_b_val),
+ expected_found(relation, sz_a_val, sz_b_val),
)),
_ => Err(err),
}
@@ -440,9 +441,9 @@
as_.iter().zip(bs).map(|(a, b)| relation.relate(a.expect_ty(), b.expect_ty())),
)?)
} else if !(as_.is_empty() || bs.is_empty()) {
- Err(TypeError::TupleSize(expected_found(relation, &as_.len(), &bs.len())))
+ Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len())))
} else {
- Err(TypeError::Sorts(expected_found(relation, &a, &b)))
+ Err(TypeError::Sorts(expected_found(relation, a, b)))
}
}
@@ -471,7 +472,7 @@
Ok(tcx.mk_opaque(a_def_id, substs))
}
- _ => Err(TypeError::Sorts(expected_found(relation, &a, &b))),
+ _ => Err(TypeError::Sorts(expected_found(relation, a, b))),
}
}
@@ -521,10 +522,10 @@
if a_instance == b_instance {
Ok(ConstValue::Scalar(a_val))
} else {
- Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
} else {
- Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
}
@@ -534,7 +535,7 @@
if a_bytes == b_bytes {
Ok(a_val)
} else {
- Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
}
@@ -554,7 +555,7 @@
Ok(a_val)
} else {
- Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
}
// FIXME(const_generics): There are probably some `TyKind`s
@@ -564,12 +565,12 @@
DUMMY_SP,
&format!("unexpected consts: a: {:?}, b: {:?}", a, b),
);
- Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+ Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
}
}
- _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
+ _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))),
};
new_val.map(ty::ConstKind::Value)
@@ -584,7 +585,7 @@
relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?;
Ok(ty::ConstKind::Unevaluated(a_def_id, substs, a_promoted))
}
- _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
+ _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))),
};
new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty }))
}
@@ -607,7 +608,7 @@
b_v.sort_by(|a, b| a.stable_cmp(tcx, b));
b_v.dedup();
if a_v.len() != b_v.len() {
- return Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b)));
+ return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
}
let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| {
@@ -616,7 +617,7 @@
(Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)),
(Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)),
(AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)),
- _ => Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b))),
+ _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
}
});
Ok(tcx.mk_existential_predicates(v)?)
@@ -740,20 +741,14 @@
///////////////////////////////////////////////////////////////////////////
// Error handling
-pub fn expected_found<R, T>(relation: &mut R, a: &T, b: &T) -> ExpectedFound<T>
+pub fn expected_found<R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
where
R: TypeRelation<'tcx>,
- T: Clone,
{
expected_found_bool(relation.a_is_expected(), a, b)
}
-pub fn expected_found_bool<T>(a_is_expected: bool, a: &T, b: &T) -> ExpectedFound<T>
-where
- T: Clone,
-{
- let a = a.clone();
- let b = b.clone();
+pub fn expected_found_bool<T>(a_is_expected: bool, a: T, b: T) -> ExpectedFound<T> {
if a_is_expected {
ExpectedFound { expected: a, found: b }
} else {
diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
index edd2dc3..8cebd36 100644
--- a/src/librustc_mir/borrow_check/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -122,7 +122,7 @@
if let Err(terr) = self.eq_opaque_type_and_type(
mir_output_ty,
normalized_output_ty,
- self.mir_def_id.to_def_id(),
+ self.mir_def_id,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {
@@ -145,7 +145,7 @@
if let Err(err) = self.eq_opaque_type_and_type(
mir_output_ty,
user_provided_output_ty,
- self.mir_def_id.to_def_id(),
+ self.mir_def_id,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 0e35caf..3532b6d 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -1144,7 +1144,8 @@
// When you have `let x: impl Foo = ...` in a closure,
// the resulting inferend values are stored with the
// def-id of the base function.
- let parent_def_id = self.tcx().closure_base_def_id(self.mir_def_id.to_def_id());
+ let parent_def_id =
+ self.tcx().closure_base_def_id(self.mir_def_id.to_def_id()).expect_local();
return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category);
} else {
return Err(terr);
@@ -1208,7 +1209,7 @@
&mut self,
revealed_ty: Ty<'tcx>,
anon_ty: Ty<'tcx>,
- anon_owner_def_id: DefId,
+ anon_owner_def_id: LocalDefId,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
@@ -1238,8 +1239,7 @@
let tcx = infcx.tcx;
let param_env = self.param_env;
let body = self.body;
- let concrete_opaque_types =
- &tcx.typeck_tables_of(anon_owner_def_id.expect_local()).concrete_opaque_types;
+ let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
let mut opaque_type_values = Vec::new();
debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index d62300b..75067ff 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -334,9 +334,9 @@
}
v
- } else if def_id.is_local() {
+ } else if let Some(def_id) = def_id.as_local() {
// constant defined in this crate, we can figure out a lint level!
- match tcx.def_kind(def_id) {
+ match tcx.def_kind(def_id.to_def_id()) {
// constants never produce a hard error at the definition site. Anything else is
// a backwards compatibility hazard (and will break old versions of winapi for
// sure)
@@ -346,7 +346,7 @@
// validation thus preventing such a hard error from being a backwards
// compatibility hazard
DefKind::Const | DefKind::AssocConst => {
- let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+ let hir_id = tcx.hir().as_local_hir_id(def_id);
err.report_as_lint(
tcx.at(tcx.def_span(def_id)),
"any use of this value will cause an error",
@@ -369,7 +369,7 @@
err.report_as_lint(
tcx.at(span),
"reaching this expression at runtime will panic or abort",
- tcx.hir().as_local_hir_id(def_id.expect_local()),
+ tcx.hir().as_local_hir_id(def_id),
Some(err.span),
)
}
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index 6dd0674..707e136 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -1,6 +1,7 @@
use crate::util::elaborate_drops::DropFlagState;
use rustc_middle::mir::{self, Body, Location};
use rustc_middle::ty::{self, TyCtxt};
+use rustc_target::abi::VariantIdx;
use super::indexes::MovePathIndex;
use super::move_paths::{InitKind, LookupResult, MoveData};
@@ -228,3 +229,42 @@
}
}
}
+
+/// Calls `handle_inactive_variant` for each descendant move path of `enum_place` that contains a
+/// `Downcast` to a variant besides the `active_variant`.
+///
+/// NOTE: If there are no move paths corresponding to an inactive variant,
+/// `handle_inactive_variant` will not be called for that variant.
+pub(crate) fn on_all_inactive_variants<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &mir::Body<'tcx>,
+ move_data: &MoveData<'tcx>,
+ enum_place: mir::Place<'tcx>,
+ active_variant: VariantIdx,
+ mut handle_inactive_variant: impl FnMut(MovePathIndex),
+) {
+ let enum_mpi = match move_data.rev_lookup.find(enum_place.as_ref()) {
+ LookupResult::Exact(mpi) => mpi,
+ LookupResult::Parent(_) => return,
+ };
+
+ let enum_path = &move_data.move_paths[enum_mpi];
+ for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) {
+ // Because of the way we build the `MoveData` tree, each child should have exactly one more
+ // projection than `enum_place`. This additional projection must be a downcast since the
+ // base is an enum.
+ let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap();
+ assert_eq!(enum_place.projection.len(), base_proj.len());
+
+ let variant_idx = match *downcast {
+ mir::ProjectionElem::Downcast(_, idx) => idx,
+ _ => unreachable!(),
+ };
+
+ if variant_idx != active_variant {
+ on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| {
+ handle_inactive_variant(mpi)
+ });
+ }
+ }
+}
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index d5def03..8975fae 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -12,7 +12,7 @@
use crate::util::elaborate_drops::DropFlagState;
-use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
+use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis};
use super::drop_flag_effects_for_function_entry;
@@ -124,11 +124,23 @@
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
mdpe: &'a MoveDataParamEnv<'tcx>,
+
+ mark_inactive_variants_as_uninit: bool,
}
impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
- MaybeUninitializedPlaces { tcx, body, mdpe }
+ MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false }
+ }
+
+ /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
+ /// enum discriminant.
+ ///
+ /// This is correct in a vacuum but is not the default because it causes problems in the borrow
+ /// checker, where this information gets propagated along `FakeEdge`s.
+ pub fn mark_inactive_variants_as_uninit(mut self) -> Self {
+ self.mark_inactive_variants_as_uninit = true;
+ self
}
}
@@ -350,27 +362,16 @@
_adt: &ty::AdtDef,
variant: VariantIdx,
) {
- let enum_mpi = match self.move_data().rev_lookup.find(enum_place.as_ref()) {
- LookupResult::Exact(mpi) => mpi,
- LookupResult::Parent(_) => return,
- };
-
- // Kill all move paths that correspond to variants other than this one
- let move_paths = &self.move_data().move_paths;
- let enum_path = &move_paths[enum_mpi];
- for (mpi, variant_path) in enum_path.children(move_paths) {
- trans.kill(mpi);
- match variant_path.place.projection.last().unwrap() {
- mir::ProjectionElem::Downcast(_, idx) if *idx == variant => continue,
- _ => drop_flag_effects::on_all_children_bits(
- self.tcx,
- self.body,
- self.move_data(),
- mpi,
- |mpi| trans.kill(mpi),
- ),
- }
- }
+ // Kill all move paths that correspond to variants we know to be inactive along this
+ // particular outgoing edge of a `SwitchInt`.
+ drop_flag_effects::on_all_inactive_variants(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ enum_place,
+ variant,
+ |mpi| trans.kill(mpi),
+ );
}
}
@@ -443,6 +444,30 @@
},
);
}
+
+ fn discriminant_switch_effect(
+ &self,
+ trans: &mut impl GenKill<Self::Idx>,
+ _block: mir::BasicBlock,
+ enum_place: mir::Place<'tcx>,
+ _adt: &ty::AdtDef,
+ variant: VariantIdx,
+ ) {
+ if !self.mark_inactive_variants_as_uninit {
+ return;
+ }
+
+ // Mark all move paths that correspond to variants other than this one as maybe
+ // uninitialized (in reality, they are *definitely* uninitialized).
+ drop_flag_effects::on_all_inactive_variants(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ enum_place,
+ variant,
+ |mpi| trans.gen(mpi),
+ );
+ }
}
impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index e4aa88e..81c1b0b 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -22,7 +22,7 @@
pub struct ConstCx<'mir, 'tcx> {
pub body: &'mir mir::Body<'tcx>,
pub tcx: TyCtxt<'tcx>,
- pub def_id: DefId,
+ pub def_id: LocalDefId,
pub param_env: ty::ParamEnv<'tcx>,
pub const_kind: Option<hir::ConstContext>,
}
@@ -40,7 +40,7 @@
param_env: ty::ParamEnv<'tcx>,
) -> Self {
let const_kind = tcx.hir().body_const_context(def_id);
- ConstCx { body, tcx, def_id: def_id.to_def_id(), param_env, const_kind }
+ ConstCx { body, tcx, def_id: def_id, param_env, const_kind }
}
/// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
index 1fd907f..55075b3 100644
--- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
+++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
@@ -29,13 +29,7 @@
return;
}
- let ccx = ConstCx {
- body,
- tcx,
- def_id: def_id.to_def_id(),
- const_kind,
- param_env: tcx.param_env(def_id),
- };
+ let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index e2893e8..3dddd9c 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -126,7 +126,7 @@
// because that component may be part of an enum variant (e.g.,
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
// structural-match (`Option::None`).
- let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
+ let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id);
traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
}
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index f00fc96..5cb161e 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -56,7 +56,7 @@
// without breaking stable code?
MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
.unsound_ignore_borrow_on_drop()
- .into_engine(tcx, &body, def_id)
+ .into_engine(tcx, &body, def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
@@ -83,7 +83,7 @@
let ConstCx { tcx, body, def_id, .. } = *ccx;
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
- .into_engine(tcx, &body, def_id)
+ .into_engine(tcx, &body, def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
@@ -110,7 +110,7 @@
let ConstCx { tcx, body, def_id, .. } = *ccx;
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
- .into_engine(tcx, &body, def_id)
+ .into_engine(tcx, &body, def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
@@ -153,7 +153,7 @@
hir::ConstContext::Const | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
- .into_engine(ccx.tcx, &ccx.body, ccx.def_id)
+ .into_engine(ccx.tcx, &ccx.body, ccx.def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(&ccx.body);
@@ -195,13 +195,13 @@
let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
- && crate::const_eval::is_min_const_fn(tcx, def_id))
+ && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()))
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
if use_min_const_fn_checks {
// Enforce `min_const_fn` for stable `const fn`s.
use crate::transform::qualify_min_const_fn::is_min_const_fn;
- if let Err((span, err)) = is_min_const_fn(tcx, def_id, &body) {
+ if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) {
error_min_const_fn_violation(tcx, span, err);
return;
}
@@ -212,10 +212,10 @@
// Ensure that the end result is `Sync` in a non-thread local `static`.
let should_check_for_sync = const_kind
== Some(hir::ConstContext::Static(hir::Mutability::Not))
- && !tcx.is_thread_local_static(def_id);
+ && !tcx.is_thread_local_static(def_id.to_def_id());
if should_check_for_sync {
- let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+ let hir_id = tcx.hir().as_local_hir_id(def_id);
check_return_ty_is_sync(tcx, &body, hir_id);
}
}
@@ -535,7 +535,7 @@
// `#[allow_internal_unstable]`.
use crate::transform::qualify_min_const_fn::lib_feature_allowed;
if !self.span.allows_unstable(feature)
- && !lib_feature_allowed(self.tcx, self.def_id, feature)
+ && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature)
{
self.check_op(ops::FnCallUnstable(def_id, feature));
}
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 1704d8b..d3bfd87 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -48,6 +48,7 @@
.into_results_cursor(body);
let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
+ .mark_inactive_variants_as_uninit()
.into_engine(tcx, body, def_id)
.dead_unwinds(&dead_unwinds)
.iterate_to_fixpoint()
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 8ca240d..14c3093 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -203,7 +203,8 @@
}
fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
- let const_kind = tcx.hir().body_const_context(def_id.expect_local());
+ let def_id = def_id.expect_local();
+ let const_kind = tcx.hir().body_const_context(def_id);
// No need to const-check a non-const `fn`.
if const_kind.is_none() {
@@ -214,7 +215,7 @@
// cannot yet be stolen), because `mir_validated()`, which steals
// from `mir_const(), forces this query to execute before
// performing the steal.
- let body = &tcx.mir_const(def_id).borrow();
+ let body = &tcx.mir_const(def_id.to_def_id()).borrow();
if body.return_ty().references_error() {
tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index bd7ebaa..5aa6722 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -60,15 +60,16 @@
return;
}
- let def_id = src.def_id();
+ let def_id = src.def_id().expect_local();
let mut rpo = traversal::reverse_postorder(body);
- let ccx = ConstCx::new(tcx, def_id.expect_local(), body);
+ let ccx = ConstCx::new(tcx, def_id, body);
let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
- let promoted = promote_candidates(def_id, body, tcx, temps, promotable_candidates);
+ let promoted =
+ promote_candidates(def_id.to_def_id(), body, tcx, temps, promotable_candidates);
self.promoted_fragments.set(promoted);
}
}
@@ -724,7 +725,7 @@
ty::FnDef(def_id, _) => {
is_const_fn(self.tcx, def_id)
|| is_unstable_const_fn(self.tcx, def_id).is_some()
- || is_lang_panic_fn(self.tcx, self.def_id)
+ || is_lang_panic_fn(self.tcx, self.def_id.to_def_id())
}
_ => false,
};
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index 18b92bf..372cb78 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -276,6 +276,7 @@
use self::WitnessPreference::*;
use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashSet;
use rustc_index::vec::Idx;
use super::{compare_const_vals, PatternFoldable, PatternFolder};
@@ -1246,15 +1247,15 @@
}
#[derive(Clone, Debug)]
-crate enum Usefulness<'tcx, 'p> {
+crate enum Usefulness<'tcx> {
/// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
- Useful(Vec<&'p Pat<'tcx>>),
+ Useful(Vec<Span>),
/// Carries a list of witnesses of non-exhaustiveness.
UsefulWithWitness(Vec<Witness<'tcx>>),
NotUseful,
}
-impl<'tcx, 'p> Usefulness<'tcx, 'p> {
+impl<'tcx> Usefulness<'tcx> {
fn new_useful(preference: WitnessPreference) -> Self {
match preference {
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
@@ -1269,7 +1270,7 @@
}
}
- fn apply_constructor(
+ fn apply_constructor<'p>(
self,
cx: &MatchCheckCtxt<'p, 'tcx>,
ctor: &Constructor<'tcx>,
@@ -1828,7 +1829,7 @@
hir_id: HirId,
is_under_guard: bool,
is_top_level: bool,
-) -> Usefulness<'tcx, 'p> {
+) -> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:#?}, {:#?})", matrix, v);
@@ -1852,16 +1853,35 @@
// We need to push the already-seen patterns into the matrix in order to detect redundant
// branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
let mut matrix = matrix.clone();
- let mut unreachable_pats = Vec::new();
+ // `Vec` of all the unreachable branches of the current or-pattern.
+ let mut unreachable_branches = Vec::new();
+ // Subpatterns that are unreachable from all branches. E.g. in the following case, the last
+ // `true` is unreachable only from one branch, so it is overall reachable.
+ // ```
+ // match (true, true) {
+ // (true, true) => {}
+ // (false | true, false | true) => {}
+ // }
+ // ```
+ let mut unreachable_subpats = FxHashSet::default();
+ // Whether any branch at all is useful.
let mut any_is_useful = false;
+
for v in vs {
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
match res {
Useful(pats) => {
- any_is_useful = true;
- unreachable_pats.extend(pats);
+ if !any_is_useful {
+ any_is_useful = true;
+ // Initialize with the first set of unreachable subpatterns encountered.
+ unreachable_subpats = pats.into_iter().collect();
+ } else {
+ // Keep the patterns unreachable from both this and previous branches.
+ unreachable_subpats =
+ pats.into_iter().filter(|p| unreachable_subpats.contains(p)).collect();
+ }
}
- NotUseful => unreachable_pats.push(v.head()),
+ NotUseful => unreachable_branches.push(v.head().span),
UsefulWithWitness(_) => {
bug!("Encountered or-pat in `v` during exhaustiveness checking")
}
@@ -1871,7 +1891,13 @@
matrix.push(v);
}
}
- return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
+ if any_is_useful {
+ // Collect all the unreachable patterns.
+ unreachable_branches.extend(unreachable_subpats);
+ return Useful(unreachable_branches);
+ } else {
+ return NotUseful;
+ }
}
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
@@ -2014,7 +2040,7 @@
witness_preference: WitnessPreference,
hir_id: HirId,
is_under_guard: bool,
-) -> Usefulness<'tcx, 'p> {
+) -> Usefulness<'tcx> {
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, ty);
// We cache the result of `Fields::wildcards` because it is used a lot.
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index 6fc447a..2ae20f5 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -12,6 +12,7 @@
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat};
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::nightly_options;
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
use rustc_session::parse::feature_err;
@@ -392,8 +393,8 @@
}
}
Useful(unreachable_subpatterns) => {
- for pat in unreachable_subpatterns {
- unreachable_pattern(cx.tcx, pat.span, id, None);
+ for span in unreachable_subpatterns {
+ unreachable_pattern(cx.tcx, span, id, None);
}
}
UsefulWithWitness(_) => bug!(),
@@ -487,9 +488,27 @@
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
err.help(
"ensure that all possible cases are being handled, \
- possibly by adding wildcards or more match arms",
+ possibly by adding wildcards or more match arms",
);
err.note(&format!("the matched value is of type `{}`", scrut_ty));
+ if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
+ && !is_empty_match
+ && witnesses.len() == 1
+ && witnesses[0].is_wildcard()
+ {
+ err.note(&format!(
+ "`{}` does not have a fixed maximum value, \
+ so a wildcard `_` is necessary to match exhaustively",
+ scrut_ty,
+ ));
+ if nightly_options::is_nightly_build() {
+ err.help(&format!(
+ "add `#![feature(precise_pointer_size_matching)]` \
+ to the crate attributes to enable precise `{}` matching",
+ scrut_ty,
+ ));
+ }
+ }
err.emit();
}
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index acc2a50..92afb7d 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -152,10 +152,14 @@
arm_target_feature,
asm,
assert,
+ assert_inhabited,
+ assert_uninit_valid,
+ assert_zero_valid,
associated_consts,
associated_type_bounds,
associated_type_defaults,
associated_types,
+ assume,
assume_init,
async_await,
async_closure,
@@ -181,11 +185,14 @@
box_patterns,
box_syntax,
braced_empty_structs,
+ breakpoint,
bswap,
bitreverse,
C,
caller_location,
cdylib,
+ ceilf32,
+ ceilf64,
cfg,
cfg_accessible,
cfg_attr,
@@ -239,8 +246,14 @@
convert,
Copy,
copy_closures,
+ copy,
+ copy_nonoverlapping,
+ copysignf32,
+ copysignf64,
core,
core_intrinsics,
+ cosf32,
+ cosf64,
count_code_region,
coverage_counter_add,
coverage_counter_subtract,
@@ -299,6 +312,7 @@
dropck_eyepatch,
dropck_parametricity,
drop_types_in_const,
+ drop_in_place,
dylib,
dyn_trait,
eh_personality,
@@ -311,11 +325,16 @@
Eq,
Equal,
enclosing_scope,
+ exact_div,
except,
exclusive_range_pattern,
exhaustive_integer_patterns,
exhaustive_patterns,
existential_type,
+ expf32,
+ expf64,
+ exp2f32,
+ exp2f64,
expected,
export_name,
expr,
@@ -329,6 +348,10 @@
f16c_target_feature,
f32,
f64,
+ fadd_fast,
+ fabsf32,
+ fabsf64,
+ fdiv_fast,
feature,
ffi_const,
ffi_pure,
@@ -336,13 +359,21 @@
field,
field_init_shorthand,
file,
+ float_to_int_unchecked,
+ floorf64,
+ floorf32,
+ fmaf32,
+ fmaf64,
fmt,
fmt_internals,
+ fmul_fast,
fn_must_use,
forbid,
+ forget,
format_args,
format_args_nl,
format_args_capture,
+ frem_fast,
from,
From,
from_desugaring,
@@ -352,6 +383,7 @@
from_ok,
from_usize,
from_trait,
+ fsub_fast,
fundamental,
future,
Future,
@@ -427,6 +459,7 @@
label_break_value,
lang,
lang_items,
+ lazy_normalization_consts,
lateout,
let_chains,
lhs,
@@ -448,6 +481,12 @@
llvm_asm,
local_inner_macros,
log_syntax,
+ logf32,
+ logf64,
+ log10f32,
+ log10f64,
+ log2f32,
+ log2f64,
loop_break_value,
macro_at_most_once_rep,
macro_escape,
@@ -475,10 +514,16 @@
message,
meta,
min_align_of,
+ min_align_of_val,
min_const_fn,
min_const_unsafe_fn,
min_specialization,
+ minnumf32,
+ minnumf64,
+ maxnumf32,
+ maxnumf64,
mips_target_feature,
+ miri_start_panic,
mmx_target_feature,
module,
module_path,
@@ -491,6 +536,8 @@
naked,
naked_functions,
name,
+ nearbyintf32,
+ nearbyintf64,
needs_allocator,
needs_drop,
needs_panic_runtime,
@@ -518,6 +565,7 @@
None,
non_exhaustive,
non_modrs_mods,
+ nontemporal_store,
nontrapping_fptoint: "nontrapping-fptoint",
noreturn,
no_niche,
@@ -577,8 +625,16 @@
poll,
Poll,
powerpc_target_feature,
+ powf32,
+ powf64,
+ powif32,
+ powif64,
precise_pointer_size_matching,
pref_align_of,
+ prefetch_read_data,
+ prefetch_read_instruction,
+ prefetch_write_data,
+ prefetch_write_instruction,
prelude,
prelude_import,
preserves_flags,
@@ -640,10 +696,14 @@
Result,
Return,
rhs,
+ rintf32,
+ rintf64,
riscv_target_feature,
rlib,
rotate_left,
rotate_right,
+ roundf32,
+ roundf64,
rt,
rtm_target_feature,
rust,
@@ -726,14 +786,19 @@
simd_ffi,
simd_insert,
since,
+ sinf32,
+ sinf64,
size,
size_of,
+ size_of_val,
slice_patterns,
slicing_syntax,
soft,
Some,
specialization,
speed,
+ sqrtf32,
+ sqrtf64,
sse4a_target_feature,
stable,
staged_api,
@@ -787,6 +852,8 @@
transparent_enums,
transparent_unions,
trivial_bounds,
+ truncf32,
+ truncf64,
Try,
try_blocks,
try_trait,
@@ -809,6 +876,8 @@
u32,
u64,
u8,
+ unaligned_volatile_load,
+ unaligned_volatile_store,
unboxed_closures,
unchecked_add,
unchecked_div,
@@ -824,6 +893,7 @@
universal_impl_trait,
unlikely,
unmarked_api,
+ unreachable,
unreachable_code,
unrestricted_attribute_tokens,
unsafe_block_in_unsafe_fn,
@@ -843,12 +913,21 @@
val,
var,
variant_count,
+ va_arg,
+ va_copy,
+ va_end,
+ va_start,
vec,
Vec,
version,
vis,
visible_private_types,
volatile,
+ volatile_copy_memory,
+ volatile_copy_nonoverlapping_memory,
+ volatile_load,
+ volatile_set_memory,
+ volatile_store,
warn,
wasm_import_module,
wasm_target_feature,
@@ -858,6 +937,7 @@
wrapping_add,
wrapping_sub,
wrapping_mul,
+ write_bytes,
Yield,
}
}
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index ce478de..b605318 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -108,7 +108,7 @@
pub trait InferCtxtExt<'tcx> {
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
- parent_def_id: DefId,
+ parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
@@ -184,7 +184,7 @@
/// - `value_span` -- the span where the value came from, used in error reporting
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
- parent_def_id: DefId,
+ parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
@@ -986,7 +986,7 @@
struct Instantiator<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
- parent_def_id: DefId,
+ parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value_span: Span,
@@ -1043,8 +1043,7 @@
let parent_def_id = self.parent_def_id;
let def_scope_default = || {
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id
- == tcx.hir().local_def_id(opaque_parent_hir_id).to_def_id()
+ parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
};
let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) {
Some(Node::Item(item)) => match item.kind {
@@ -1053,18 +1052,14 @@
impl_trait_fn: Some(parent),
origin,
..
- }) => (parent == self.parent_def_id, origin),
+ }) => (parent == self.parent_def_id.to_def_id(), origin),
// Named `type Foo = impl Bar;`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: None,
origin,
..
}) => (
- may_define_opaque_type(
- tcx,
- self.parent_def_id.expect_local(),
- opaque_hir_id,
- ),
+ may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id),
origin,
),
_ => (def_scope_default(), hir::OpaqueTyOrigin::Misc),
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 6205088..9b3b4a6 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -5,10 +5,11 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::spec::abi::Abi;
use std::iter;
@@ -16,14 +17,13 @@
fn equate_intrinsic_type<'tcx>(
tcx: TyCtxt<'tcx>,
it: &hir::ForeignItem<'_>,
+ def_id: DefId,
n_tps: usize,
abi: Abi,
safety: hir::Unsafety,
inputs: Vec<Ty<'tcx>>,
output: Ty<'tcx>,
) {
- let def_id = tcx.hir().local_def_id(it.hir_id);
-
match it.kind {
hir::ForeignItemKind::Fn(..) => {}
_ => {
@@ -67,15 +67,43 @@
}
/// Returns `true` if the given intrinsic is unsafe to call or not.
-pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
+pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
match intrinsic {
- "abort" | "size_of" | "min_align_of" | "needs_drop" | "caller_location" | "size_of_val"
- | "min_align_of_val" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow"
- | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
- | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
- | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
- | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
- | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal,
+ sym::abort
+ | sym::size_of
+ | sym::min_align_of
+ | sym::needs_drop
+ | sym::caller_location
+ | sym::size_of_val
+ | sym::min_align_of_val
+ | sym::add_with_overflow
+ | sym::sub_with_overflow
+ | sym::mul_with_overflow
+ | sym::wrapping_add
+ | sym::wrapping_sub
+ | sym::wrapping_mul
+ | sym::saturating_add
+ | sym::saturating_sub
+ | sym::rotate_left
+ | sym::rotate_right
+ | sym::ctpop
+ | sym::ctlz
+ | sym::cttz
+ | sym::bswap
+ | sym::bitreverse
+ | sym::discriminant_value
+ | sym::type_id
+ | sym::likely
+ | sym::unlikely
+ | sym::ptr_guaranteed_eq
+ | sym::ptr_guaranteed_ne
+ | sym::minnumf32
+ | sym::minnumf64
+ | sym::maxnumf32
+ | sym::rustc_peek
+ | sym::maxnumf64
+ | sym::type_name
+ | sym::variant_count => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
}
@@ -84,7 +112,9 @@
/// and in libcore/intrinsics.rs
pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
- let name = it.ident.as_str();
+ let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
+ let intrinsic_name = tcx.item_name(def_id);
+ let name_str = intrinsic_name.as_str();
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
@@ -98,8 +128,8 @@
})
};
- let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
- let split: Vec<&str> = name.split('_').collect();
+ let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+ let split: Vec<&str> = name_str.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
//We only care about the operation here
@@ -129,32 +159,30 @@
}
};
(n_tps, inputs, output, hir::Unsafety::Unsafe)
- } else if &name[..] == "abort" {
- (0, Vec::new(), tcx.types.never, hir::Unsafety::Normal)
- } else if &name[..] == "unreachable" {
- (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
} else {
- let unsafety = intrinsic_operation_unsafety(&name[..]);
- let (n_tps, inputs, output) = match &name[..] {
- "breakpoint" => (0, Vec::new(), tcx.mk_unit()),
- "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => {
+ let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+ let (n_tps, inputs, output) = match intrinsic_name {
+ sym::abort => (0, Vec::new(), tcx.types.never),
+ sym::unreachable => (0, Vec::new(), tcx.types.never),
+ sym::breakpoint => (0, Vec::new(), tcx.mk_unit()),
+ sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
(1, Vec::new(), tcx.types.usize)
}
- "size_of_val" | "min_align_of_val" => {
+ sym::size_of_val | sym::min_align_of_val => {
(1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
}
- "rustc_peek" => (1, vec![param(0)], param(0)),
- "caller_location" => (0, vec![], tcx.caller_location_ty()),
- "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => {
+ sym::rustc_peek => (1, vec![param(0)], param(0)),
+ sym::caller_location => (0, vec![], tcx.caller_location_ty()),
+ sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
(1, Vec::new(), tcx.mk_unit())
}
- "forget" => (1, vec![param(0)], tcx.mk_unit()),
- "transmute" => (2, vec![param(0)], param(1)),
- "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
- "prefetch_read_data"
- | "prefetch_write_data"
- | "prefetch_read_instruction"
- | "prefetch_write_instruction" => (
+ sym::forget => (1, vec![param(0)], tcx.mk_unit()),
+ sym::transmute => (2, vec![param(0)], param(1)),
+ sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+ sym::prefetch_read_data
+ | sym::prefetch_write_data
+ | sym::prefetch_read_instruction
+ | sym::prefetch_write_instruction => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -162,12 +190,12 @@
],
tcx.mk_unit(),
),
- "drop_in_place" => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()),
- "needs_drop" => (1, Vec::new(), tcx.types.bool),
+ sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()),
+ sym::needs_drop => (1, Vec::new(), tcx.types.bool),
- "type_name" => (1, Vec::new(), tcx.mk_static_str()),
- "type_id" => (1, Vec::new(), tcx.types.u64),
- "offset" | "arith_offset" => (
+ sym::type_name => (1, Vec::new(), tcx.mk_static_str()),
+ sym::type_id => (1, Vec::new(), tcx.types.u64),
+ sym::offset | sym::arith_offset => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -175,7 +203,7 @@
],
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
),
- "copy" | "copy_nonoverlapping" => (
+ sym::copy | sym::copy_nonoverlapping => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -184,7 +212,7 @@
],
tcx.mk_unit(),
),
- "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => (
+ sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
@@ -193,7 +221,7 @@
],
tcx.mk_unit(),
),
- "write_bytes" | "volatile_set_memory" => (
+ sym::write_bytes | sym::volatile_set_memory => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
@@ -202,93 +230,98 @@
],
tcx.mk_unit(),
),
- "sqrtf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "sqrtf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "powif32" => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
- "powif64" => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
- "sinf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "sinf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "cosf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "cosf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "powf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
- "powf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
- "expf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "expf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "exp2f32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "exp2f64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "logf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "logf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "log10f32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "log10f64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "log2f32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "log2f64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "fmaf32" => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
- "fmaf64" => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
- "fabsf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "fabsf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "minnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
- "minnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
- "maxnumf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
- "maxnumf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
- "copysignf32" => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
- "copysignf64" => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
- "floorf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "floorf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "ceilf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "ceilf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "truncf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "truncf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "rintf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "rintf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "nearbyintf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "nearbyintf64" => (0, vec![tcx.types.f64], tcx.types.f64),
- "roundf32" => (0, vec![tcx.types.f32], tcx.types.f32),
- "roundf64" => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::powif32 => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
+ sym::powif64 => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
+ sym::sinf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::sinf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::cosf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::cosf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::powf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+ sym::powf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+ sym::expf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::expf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::exp2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::exp2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::logf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::logf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::log10f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::log10f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::log2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::log2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::fmaf32 => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
+ sym::fmaf64 => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
+ sym::fabsf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::fabsf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::minnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+ sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+ sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+ sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+ sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+ sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+ sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::floorf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::ceilf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::ceilf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::truncf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::truncf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::rintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::rintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::nearbyintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+ sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+ sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
- "volatile_load" | "unaligned_volatile_load" => {
+ sym::volatile_load | sym::unaligned_volatile_load => {
(1, vec![tcx.mk_imm_ptr(param(0))], param(0))
}
- "volatile_store" | "unaligned_volatile_store" => {
+ sym::volatile_store | sym::unaligned_volatile_store => {
(1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit())
}
- "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap"
- | "bitreverse" => (1, vec![param(0)], param(0)),
+ sym::ctpop
+ | sym::ctlz
+ | sym::ctlz_nonzero
+ | sym::cttz
+ | sym::cttz_nonzero
+ | sym::bswap
+ | sym::bitreverse => (1, vec![param(0)], param(0)),
- "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
+ sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
(1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
}
- "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+ sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
}
- "ptr_offset_from" => {
+ sym::ptr_offset_from => {
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
}
- "unchecked_div" | "unchecked_rem" | "exact_div" => {
+ sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
(1, vec![param(0), param(0)], param(0))
}
- "unchecked_shl" | "unchecked_shr" | "rotate_left" | "rotate_right" => {
+ sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
(1, vec![param(0), param(0)], param(0))
}
- "unchecked_add" | "unchecked_sub" | "unchecked_mul" => {
+ sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
(1, vec![param(0), param(0)], param(0))
}
- "wrapping_add" | "wrapping_sub" | "wrapping_mul" => {
+ sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
(1, vec![param(0), param(0)], param(0))
}
- "saturating_add" | "saturating_sub" => (1, vec![param(0), param(0)], param(0)),
- "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
+ sym::saturating_add | sym::saturating_sub => (1, vec![param(0), param(0)], param(0)),
+ sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
(1, vec![param(0), param(0)], param(0))
}
- "float_to_int_unchecked" => (2, vec![param(0)], param(1)),
+ sym::float_to_int_unchecked => (2, vec![param(0)], param(1)),
- "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
- "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
- "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
+ sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()),
+ sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
+ sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
- "discriminant_value" => {
+ sym::discriminant_value => {
let assoc_items =
tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
@@ -303,7 +336,7 @@
)
}
- "try" => {
+ kw::Try => {
let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
iter::once(mut_u8),
@@ -326,12 +359,12 @@
)
}
- "va_start" | "va_end" => match mk_va_list_ty(hir::Mutability::Mut) {
+ sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()),
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
},
- "va_copy" => match mk_va_list_ty(hir::Mutability::Not) {
+ sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
Some((va_list_ref_ty, va_list_ty)) => {
let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty);
(0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit())
@@ -339,38 +372,38 @@
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
},
- "va_arg" => match mk_va_list_ty(hir::Mutability::Mut) {
+ sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)),
None => bug!("`va_list` language item needed for C-variadic intrinsics"),
},
- "nontemporal_store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+ sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
- "miri_start_panic" => {
+ sym::miri_start_panic => {
// FIXME - the relevant types aren't lang items,
// so it's not trivial to check this
return;
}
- "count_code_region" => {
+ sym::count_code_region => {
(0, vec![tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
}
- "coverage_counter_add" | "coverage_counter_subtract" => (
+ sym::coverage_counter_add | sym::coverage_counter_subtract => (
0,
vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32],
tcx.mk_unit(),
),
- "coverage_unreachable" => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()),
+ sym::coverage_unreachable => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()),
- ref other => {
+ other => {
struct_span_err!(
tcx.sess,
it.span,
E0093,
"unrecognized intrinsic function: `{}`",
- *other
+ other,
)
.span_label(it.span, "unrecognized intrinsic")
.emit();
@@ -379,7 +412,7 @@
};
(n_tps, inputs, output, unsafety)
};
- equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
+ equate_intrinsic_type(tcx, it, def_id, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -389,6 +422,7 @@
tcx.mk_ty_param(n, name)
};
+ let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
let name = it.ident.as_str();
let (n_tps, inputs, output) = match &*name {
@@ -463,6 +497,7 @@
equate_intrinsic_type(
tcx,
it,
+ def_id,
n_tps,
Abi::PlatformIntrinsic,
hir::Unsafety::Unsafe,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 58fd0f9..e564b01 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1321,8 +1321,8 @@
fcx.resume_yield_tys = Some((resume_ty, yield_ty));
}
- let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id());
- let outer_hir_id = hir.as_local_hir_id(outer_def_id.expect_local());
+ let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local();
+ let outer_hir_id = hir.as_local_hir_id(outer_def_id);
GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body);
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
@@ -3427,7 +3427,7 @@
let (value, opaque_type_map) =
self.register_infer_ok_obligations(self.instantiate_opaque_types(
- parent_def_id.to_def_id(),
+ parent_def_id,
self.body_id,
self.param_env,
value,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8920203e..cc491c5 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2063,7 +2063,7 @@
ident: Ident,
) -> ty::PolyFnSig<'tcx> {
let unsafety = if abi == abi::Abi::RustIntrinsic {
- intrinsic_operation_unsafety(&tcx.item_name(def_id).as_str())
+ intrinsic_operation_unsafety(tcx.item_name(def_id))
} else {
hir::Unsafety::Unsafe
};
diff --git a/src/test/mir-opt/no-drop-for-inactive-variant/rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no-drop-for-inactive-variant/rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
index ce987a5..2e8cfae 100644
--- a/src/test/mir-opt/no-drop-for-inactive-variant/rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/no-drop-for-inactive-variant/rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
@@ -8,22 +8,19 @@
let mut _4: !; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
let mut _5: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
let mut _6: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+ let mut _7: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
scope 1 {
debug x => _3; // in scope 1 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15
}
bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
- switchInt(move _2) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
+ switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
}
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:1: 12:2
- }
-
- bb2: {
+ bb1: {
StorageLive(_4); // scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
- const std::rt::begin_panic::<&str>(const "explicit panic") -> bb5; // scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+ const std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
// ty::Const
// + ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}
// + val: Value(Scalar(<ZST>))
@@ -38,20 +35,21 @@
// + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [101, 120, 112, 108, 105, 99, 105, 116, 32, 112, 97, 110, 105, 99], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [16383], len: Size { raw: 14 } }, size: Size { raw: 14 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 14 }) }
}
- bb3: {
+ bb2: {
unreachable; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:8:11: 8:14
}
- bb4: {
+ bb3: {
StorageLive(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15
_3 = move ((_1 as Some).0: T); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15
_0 = move _3; // scope 1 at $DIR/no-drop-for-inactive-variant.rs:9:20: 9:21
StorageDead(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:21: 9:22
- _5 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+ _6 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
return; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:2: 12:2
}
- bb5 (cleanup): {
- drop(_1) -> bb1; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+ bb4 (cleanup): {
+ _5 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+ resume; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:1: 12:2
}
}
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff
index 551f6db..440c5f8 100644
--- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff
@@ -7,13 +7,28 @@
let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
-- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
scope 1 {
debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
}
bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // ty::Const
+- // + ty: bool
+- // + val: Value(Scalar(0x00))
+- // mir::Constant
+- // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // ty::Const
+- // + ty: bool
+- // + val: Value(Scalar(0x01))
+- // mir::Constant
+- // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
_2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
}
@@ -35,7 +50,7 @@
}
bb3: {
-- _5 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
}
}
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff
index 388b382..c12d171 100644
--- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff
@@ -7,13 +7,28 @@
let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
-- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
scope 1 {
debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
}
bb0: {
+- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // ty::Const
+- // + ty: bool
+- // + val: Value(Scalar(0x00))
+- // mir::Constant
+- // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // ty::Const
+- // + ty: bool
+- // + val: Value(Scalar(0x01))
+- // mir::Constant
+- // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+- // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
_2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
}
@@ -35,7 +50,7 @@
}
bb3: {
-- _5 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
}
}
diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71986.rs b/src/test/ui/const-generics/issue-71986.rs
similarity index 100%
rename from src/test/ui/const-generics/lazy-normalization/issue-71986.rs
rename to src/test/ui/const-generics/issue-71986.rs
diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
index 6c5d009..c7a63e5 100644
--- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
+++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
@@ -6,6 +6,8 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
@@ -15,6 +17,8 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/auxiliary/reexported-trait.rs b/src/test/ui/issues/auxiliary/reexported-trait.rs
new file mode 100644
index 0000000..51a991b
--- /dev/null
+++ b/src/test/ui/issues/auxiliary/reexported-trait.rs
@@ -0,0 +1,17 @@
+mod private {
+ pub trait Trait {
+ fn trait_method(&self) {
+ }
+ }
+ pub trait TraitB {
+ fn trait_method_b(&self) {
+ }
+ }
+}
+
+pub struct FooStruct;
+pub use crate::private::Trait;
+impl crate::private::Trait for FooStruct {}
+
+pub use crate::private::TraitB as TraitBRename;
+impl crate::private::TraitB for FooStruct {}
diff --git a/src/test/ui/issues/issue-56175.rs b/src/test/ui/issues/issue-56175.rs
new file mode 100644
index 0000000..ca1d0d4
--- /dev/null
+++ b/src/test/ui/issues/issue-56175.rs
@@ -0,0 +1,9 @@
+// edition:2018
+// aux-crate:reexported_trait=reexported-trait.rs
+
+fn main() {
+ reexported_trait::FooStruct.trait_method();
+ //~^ ERROR
+ reexported_trait::FooStruct.trait_method_b();
+ //~^ ERROR
+}
diff --git a/src/test/ui/issues/issue-56175.stderr b/src/test/ui/issues/issue-56175.stderr
new file mode 100644
index 0000000..c0799db
--- /dev/null
+++ b/src/test/ui/issues/issue-56175.stderr
@@ -0,0 +1,27 @@
+error[E0599]: no method named `trait_method` found for struct `reexported_trait::FooStruct` in the current scope
+ --> $DIR/issue-56175.rs:5:33
+ |
+LL | reexported_trait::FooStruct.trait_method();
+ | ^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct`
+ |
+ = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use reexported_trait::Trait;
+ |
+
+error[E0599]: no method named `trait_method_b` found for struct `reexported_trait::FooStruct` in the current scope
+ --> $DIR/issue-56175.rs:7:33
+ |
+LL | reexported_trait::FooStruct.trait_method_b();
+ | ^^^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct`
+ |
+ = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use reexported_trait::TraitBRename;
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.rs b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.rs
new file mode 100644
index 0000000..44cb748
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.rs
@@ -0,0 +1,10 @@
+pub const fn sof<T>() -> usize {
+ 10
+}
+
+fn test<T>() {
+ let _: [u8; sof::<T>()];
+ //~^ ERROR the size for values of type `T`
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
new file mode 100644
index 0000000..6e19251
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+ --> $DIR/feature-gate-lazy_normalization_consts.rs:6:23
+ |
+LL | pub const fn sof<T>() -> usize {
+ | - required by this bound in `sof`
+...
+LL | fn test<T>() {
+ | - this type parameter needs to be `std::marker::Sized`
+LL | let _: [u8; sof::<T>()];
+ | ^ doesn't have a size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `T`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+ |
+LL | pub const fn sof<T: ?Sized>() -> usize {
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lazy_normalization_consts/issue-47814.rs b/src/test/ui/lazy_normalization_consts/issue-47814.rs
new file mode 100644
index 0000000..1fd0c45
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/issue-47814.rs
@@ -0,0 +1,16 @@
+// check-pass
+#![feature(lazy_normalization_consts)]
+#![allow(incomplete_features)]
+pub struct ArpIPv4<'a> {
+ _s: &'a u8
+}
+
+impl<'a> ArpIPv4<'a> {
+ const LENGTH: usize = 20;
+
+ pub fn to_buffer() -> [u8; Self::LENGTH] {
+ unimplemented!()
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy_normalization_consts/issue-57739.rs b/src/test/ui/lazy_normalization_consts/issue-57739.rs
new file mode 100644
index 0000000..4607f3e
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/issue-57739.rs
@@ -0,0 +1,17 @@
+#![feature(lazy_normalization_consts)]
+//~^ WARN the feature `lazy_normalization_consts` is incomplete
+trait ArraySizeTrait {
+ const SIZE: usize = 0;
+}
+
+impl<T: ?Sized> ArraySizeTrait for T {
+ const SIZE: usize = 1;
+}
+
+struct SomeArray<T: ArraySizeTrait> {
+ array: [u8; T::SIZE],
+ //~^ ERROR constant expression depends on a generic parameter
+ phantom: std::marker::PhantomData<T>,
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy_normalization_consts/issue-57739.stderr b/src/test/ui/lazy_normalization_consts/issue-57739.stderr
new file mode 100644
index 0000000..1987f58
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/issue-57739.stderr
@@ -0,0 +1,19 @@
+warning: the feature `lazy_normalization_consts` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-57739.rs:1:12
+ |
+LL | #![feature(lazy_normalization_consts)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information
+
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-57739.rs:12:5
+ |
+LL | array: [u8; T::SIZE],
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs
new file mode 100644
index 0000000..339b22c
--- /dev/null
+++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs
@@ -0,0 +1,14 @@
+// check-pass
+#![feature(lazy_normalization_consts)]
+#![allow(incomplete_features)]
+
+pub struct X<P, Q>(P, Q);
+pub struct L<T: ?Sized>(T);
+
+impl<T: ?Sized> L<T> {
+ const S: usize = 1;
+}
+
+impl<T> X<T, [u8; L::<T>::S]> {}
+
+fn main() {}
diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs
index 91d41e9..3046082 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.rs
+++ b/src/test/ui/mir-dataflow/def-inits-1.rs
@@ -11,13 +11,13 @@
fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
let ret;
// `ret` starts off uninitialized
- unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
// All function formal parameters start off initialized.
- unsafe { rustc_peek(&x) };
- unsafe { rustc_peek(&y) };
- unsafe { rustc_peek(&z) };
+ rustc_peek(&x);
+ rustc_peek(&y);
+ rustc_peek(&z);
ret = if test {
::std::mem::replace(x, y)
@@ -27,21 +27,21 @@
};
// `z` may be uninitialized here.
- unsafe { rustc_peek(&z); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&z); //~ ERROR rustc_peek: bit not set
// `y` is definitely uninitialized here.
- unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&y); //~ ERROR rustc_peek: bit not set
// `x` is still (definitely) initialized (replace above is a reborrow).
- unsafe { rustc_peek(&x); }
+ rustc_peek(&x);
::std::mem::drop(x);
// `x` is *definitely* uninitialized here
- unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&x); //~ ERROR rustc_peek: bit not set
// `ret` is now definitely initialized (via `if` above).
- unsafe { rustc_peek(&ret); }
+ rustc_peek(&ret);
ret
}
diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr
index 48d8450..e2bddb5 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.stderr
+++ b/src/test/ui/mir-dataflow/def-inits-1.stderr
@@ -1,26 +1,26 @@
error: rustc_peek: bit not set
- --> $DIR/def-inits-1.rs:14:14
+ --> $DIR/def-inits-1.rs:14:5
|
-LL | unsafe { rustc_peek(&ret); }
- | ^^^^^^^^^^^^^^^^
+LL | rustc_peek(&ret);
+ | ^^^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/def-inits-1.rs:30:14
+ --> $DIR/def-inits-1.rs:30:5
|
-LL | unsafe { rustc_peek(&z); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&z);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/def-inits-1.rs:33:14
+ --> $DIR/def-inits-1.rs:33:5
|
-LL | unsafe { rustc_peek(&y); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&y);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/def-inits-1.rs:41:14
+ --> $DIR/def-inits-1.rs:41:5
|
-LL | unsafe { rustc_peek(&x); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&x);
+ | ^^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
index caa307e..374a9f7 100644
--- a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
+++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
@@ -38,7 +38,7 @@
*rmut_cell = 42; // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
let val = *rmut_cell;
- unsafe { rustc_peek(x) }; //~ ERROR rustc_peek: bit not set
+ rustc_peek(x); //~ ERROR rustc_peek: bit not set
val
};
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
index 8d3548ec..1d5287c 100644
--- a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
+++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
@@ -1,8 +1,8 @@
error: rustc_peek: bit not set
- --> $DIR/indirect-mutation-offset.rs:41:14
+ --> $DIR/indirect-mutation-offset.rs:41:5
|
-LL | unsafe { rustc_peek(x) };
- | ^^^^^^^^^^^^^
+LL | rustc_peek(x);
+ | ^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs
index 4a4786a..8fb1d4b 100644
--- a/src/test/ui/mir-dataflow/inits-1.rs
+++ b/src/test/ui/mir-dataflow/inits-1.rs
@@ -11,13 +11,13 @@
fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
let ret;
// `ret` starts off uninitialized, so we get an error report here.
- unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
// All function formal parameters start off initialized.
- unsafe { rustc_peek(&x) };
- unsafe { rustc_peek(&y) };
- unsafe { rustc_peek(&z) };
+ rustc_peek(&x);
+ rustc_peek(&y);
+ rustc_peek(&z);
ret = if test {
::std::mem::replace(x, y)
@@ -28,21 +28,21 @@
// `z` may be initialized here.
- unsafe { rustc_peek(&z); }
+ rustc_peek(&z);
// `y` is definitely uninitialized here.
- unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&y); //~ ERROR rustc_peek: bit not set
// `x` is still (definitely) initialized (replace above is a reborrow).
- unsafe { rustc_peek(&x); }
+ rustc_peek(&x);
::std::mem::drop(x);
// `x` is *definitely* uninitialized here
- unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&x); //~ ERROR rustc_peek: bit not set
// `ret` is now definitely initialized (via `if` above).
- unsafe { rustc_peek(&ret); }
+ rustc_peek(&ret);
ret
}
diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr
index 23d0679..7a00a70 100644
--- a/src/test/ui/mir-dataflow/inits-1.stderr
+++ b/src/test/ui/mir-dataflow/inits-1.stderr
@@ -1,20 +1,20 @@
error: rustc_peek: bit not set
- --> $DIR/inits-1.rs:14:14
+ --> $DIR/inits-1.rs:14:5
|
-LL | unsafe { rustc_peek(&ret); }
- | ^^^^^^^^^^^^^^^^
+LL | rustc_peek(&ret);
+ | ^^^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/inits-1.rs:34:14
+ --> $DIR/inits-1.rs:34:5
|
-LL | unsafe { rustc_peek(&y); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&y);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/inits-1.rs:42:14
+ --> $DIR/inits-1.rs:42:5
|
-LL | unsafe { rustc_peek(&x); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&x);
+ | ^^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/mir-dataflow/liveness-ptr.rs b/src/test/ui/mir-dataflow/liveness-ptr.rs
index 34097d7..786da52 100644
--- a/src/test/ui/mir-dataflow/liveness-ptr.rs
+++ b/src/test/ui/mir-dataflow/liveness-ptr.rs
@@ -10,17 +10,17 @@
x = 0;
// `x` is live here since it is used in the next statement...
- unsafe { rustc_peek(x); }
+ rustc_peek(x);
p = &x;
// ... but not here, even while it can be accessed through `p`.
- unsafe { rustc_peek(x); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(x); //~ ERROR rustc_peek: bit not set
let tmp = unsafe { *p };
x = tmp + 1;
- unsafe { rustc_peek(x); }
+ rustc_peek(x);
x
}
diff --git a/src/test/ui/mir-dataflow/liveness-ptr.stderr b/src/test/ui/mir-dataflow/liveness-ptr.stderr
index 3397d0c..858cdba 100644
--- a/src/test/ui/mir-dataflow/liveness-ptr.stderr
+++ b/src/test/ui/mir-dataflow/liveness-ptr.stderr
@@ -1,8 +1,8 @@
error: rustc_peek: bit not set
- --> $DIR/liveness-ptr.rs:18:14
+ --> $DIR/liveness-ptr.rs:18:5
|
-LL | unsafe { rustc_peek(x); }
- | ^^^^^^^^^^^^^
+LL | rustc_peek(x);
+ | ^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs
index 66b3f45..c2b4284 100644
--- a/src/test/ui/mir-dataflow/uninits-1.rs
+++ b/src/test/ui/mir-dataflow/uninits-1.rs
@@ -11,13 +11,13 @@
fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
let ret;
// `ret` starts off uninitialized
- unsafe { rustc_peek(&ret); }
+ rustc_peek(&ret);
// All function formal parameters start off initialized.
- unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
- unsafe { rustc_peek(&y) }; //~ ERROR rustc_peek: bit not set
- unsafe { rustc_peek(&z) }; //~ ERROR rustc_peek: bit not set
+ rustc_peek(&x); //~ ERROR rustc_peek: bit not set
+ rustc_peek(&y); //~ ERROR rustc_peek: bit not set
+ rustc_peek(&z); //~ ERROR rustc_peek: bit not set
ret = if test {
::std::mem::replace(x, y)
@@ -27,21 +27,21 @@
};
// `z` may be uninitialized here.
- unsafe { rustc_peek(&z); }
+ rustc_peek(&z);
// `y` is definitely uninitialized here.
- unsafe { rustc_peek(&y); }
+ rustc_peek(&y);
// `x` is still (definitely) initialized (replace above is a reborrow).
- unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&x); //~ ERROR rustc_peek: bit not set
::std::mem::drop(x);
// `x` is *definitely* uninitialized here
- unsafe { rustc_peek(&x); }
+ rustc_peek(&x);
// `ret` is now definitely initialized (via `if` above).
- unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set
+ rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
ret
}
diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr
index 5f6dbde..c52f5ac 100644
--- a/src/test/ui/mir-dataflow/uninits-1.stderr
+++ b/src/test/ui/mir-dataflow/uninits-1.stderr
@@ -1,32 +1,32 @@
error: rustc_peek: bit not set
- --> $DIR/uninits-1.rs:18:14
+ --> $DIR/uninits-1.rs:18:5
|
-LL | unsafe { rustc_peek(&x) };
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&x);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/uninits-1.rs:19:14
+ --> $DIR/uninits-1.rs:19:5
|
-LL | unsafe { rustc_peek(&y) };
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&y);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/uninits-1.rs:20:14
+ --> $DIR/uninits-1.rs:20:5
|
-LL | unsafe { rustc_peek(&z) };
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&z);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/uninits-1.rs:36:14
+ --> $DIR/uninits-1.rs:36:5
|
-LL | unsafe { rustc_peek(&x); }
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&x);
+ | ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
- --> $DIR/uninits-1.rs:44:14
+ --> $DIR/uninits-1.rs:44:5
|
-LL | unsafe { rustc_peek(&ret); }
- | ^^^^^^^^^^^^^^^^
+LL | rustc_peek(&ret);
+ | ^^^^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs
index 2ccf1c7..c584ee7 100644
--- a/src/test/ui/mir-dataflow/uninits-2.rs
+++ b/src/test/ui/mir-dataflow/uninits-2.rs
@@ -11,12 +11,12 @@
fn foo(x: &mut S) {
// `x` is initialized here, so maybe-uninit bit is 0.
- unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
+ rustc_peek(&x); //~ ERROR rustc_peek: bit not set
::std::mem::drop(x);
// `x` definitely uninitialized here, so maybe-uninit bit is 1.
- unsafe { rustc_peek(&x) };
+ rustc_peek(&x);
}
fn main() {
foo(&mut S(13));
diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr
index dcb6137..0ef954e 100644
--- a/src/test/ui/mir-dataflow/uninits-2.stderr
+++ b/src/test/ui/mir-dataflow/uninits-2.stderr
@@ -1,8 +1,8 @@
error: rustc_peek: bit not set
- --> $DIR/uninits-2.rs:14:14
+ --> $DIR/uninits-2.rs:14:5
|
-LL | unsafe { rustc_peek(&x) };
- | ^^^^^^^^^^^^^^
+LL | rustc_peek(&x);
+ | ^^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
index 44bae28..a1147cb 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
@@ -29,6 +29,9 @@
(1, 4 | 5) => {} //~ ERROR unreachable pattern
_ => {}
}
+ match (true, true) {
+ (false | true, false | true) => (),
+ }
match (Some(0u8),) {
(None | Some(1 | 2),) => {}
(Some(1),) => {} //~ ERROR unreachable pattern
@@ -67,4 +70,29 @@
| 1) => {}
_ => {}
}
+
+ // A subpattern that is only unreachable in one branch is overall reachable.
+ match (true, true) {
+ (true, true) => {}
+ (false | true, false | true) => {}
+ }
+ match (true, true) {
+ (true, false) => {}
+ (false, true) => {}
+ (false | true, false | true) => {}
+ }
+ // A subpattern that is unreachable in all branches is overall unreachable.
+ match (true, true) {
+ (false, true) => {}
+ (true, true) => {}
+ (false | true, false
+ | true) => {} //~ ERROR unreachable
+ }
+ match (true, true) {
+ (true, false) => {}
+ (true, true) => {}
+ (false
+ | true, //~ ERROR unreachable
+ false | true) => {}
+ }
}
diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
index bef6f82..d92b545a 100644
--- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
+++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
@@ -53,52 +53,64 @@
| ^^^^^^^^^^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:34:9
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
|
LL | (Some(1),) => {}
| ^^^^^^^^^^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:38:9
|
LL | (None,) => {}
| ^^^^^^^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:40:9
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
|
LL | ((1..=4,),) => {}
| ^^^^^^^^^^^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:45:14
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:48:14
|
LL | (1 | 1,) => {}
| ^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:52:15
- |
-LL | | 0] => {}
- | ^
-
-error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:50:15
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:53:15
|
LL | | 0
| ^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:60:10
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:55:15
+ |
+LL | | 0] => {}
+ | ^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:63:10
|
LL | [1
| ^
error: unreachable pattern
- --> $DIR/exhaustiveness-unreachable-pattern.rs:66:14
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:69:14
|
LL | Some(0
| ^
-error: aborting due to 16 previous errors
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:89:15
+ |
+LL | | true) => {}
+ | ^^^^
+
+error: unreachable pattern
+ --> $DIR/exhaustiveness-unreachable-pattern.rs:95:15
+ |
+LL | | true,
+ | ^^^^
+
+error: aborting due to 18 previous errors
diff --git a/src/test/ui/or-patterns/search-via-bindings.rs b/src/test/ui/or-patterns/search-via-bindings.rs
index eb127b8..067e617 100644
--- a/src/test/ui/or-patterns/search-via-bindings.rs
+++ b/src/test/ui/or-patterns/search-via-bindings.rs
@@ -3,7 +3,6 @@
// run-pass
#![feature(or_patterns)]
-#![allow(unreachable_patterns)] // FIXME(or-patterns) this shouldn't trigger
fn search(target: (bool, bool, bool)) -> u32 {
let x = ((false, true), (false, true), (false, true));
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs
new file mode 100644
index 0000000..0c52876
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs
@@ -0,0 +1,23 @@
+use std::{usize, isize};
+
+fn main() {
+ match 0usize {
+ //~^ ERROR non-exhaustive patterns
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `usize`
+ //~| NOTE `usize` does not have a fixed maximum value
+ 0 ..= usize::MAX => {}
+ }
+
+ match 0isize {
+ //~^ ERROR non-exhaustive patterns
+ //~| NOTE pattern `_` not covered
+ //~| NOTE the matched value is of type `isize`
+ //~| NOTE `isize` does not have a fixed maximum value
+ isize::MIN ..= isize::MAX => {}
+ }
+
+ match 7usize {}
+ //~^ ERROR non-exhaustive patterns
+ //~| NOTE the matched value is of type `usize`
+}
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr
new file mode 100644
index 0000000..d0aa452
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr
@@ -0,0 +1,34 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:4:11
+ |
+LL | match 0usize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+ = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:12:11
+ |
+LL | match 0isize {
+ | ^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `isize`
+ = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+ = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+ --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:20:11
+ |
+LL | match 7usize {}
+ | ^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+ = note: the matched value is of type `usize`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0004`.