/// What is the context that prevents using `~const`?
enum DisallowTildeConstContext<'a> {
TraitObject,
- ImplTrait,
Fn(FnKind<'a>),
}
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
- if outer.is_some() {
- self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
- } else {
- f(self);
- }
+ f(self);
self.outer_impl_trait = old;
}
let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
match reason {
DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
- DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
};
self.report_decorated(tcx, message, |_| {})
}
+ #[instrument(level = "trace", skip(self, decorate))]
+ pub(super) fn decorate(&self, err: &mut Diagnostic, decorate: impl FnOnce(&mut Diagnostic)) {
+ trace!("reporting const eval failure at {:?}", self.span);
+ // Add some more context for select error types.
+ match self.error {
+ InterpError::Unsupported(
+ UnsupportedOpInfo::ReadPointerAsBytes
+ | UnsupportedOpInfo::PartialPointerOverwrite(_)
+ | UnsupportedOpInfo::PartialPointerCopy(_),
+ ) => {
+ err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
+ err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
+ }
+ _ => {}
+ }
+ // Add spans for the stacktrace. Don't print a single-line backtrace though.
+ if self.stacktrace.len() > 1 {
+ // Helper closure to print duplicated lines.
+ let mut flush_last_line = |last_frame, times| {
+ if let Some((line, span)) = last_frame {
+ err.span_note(span, &line);
+ // Don't print [... additional calls ...] if the number of lines is small
+ if times < 3 {
+ for _ in 0..times {
+ err.span_note(span, &line);
+ }
+ } else {
+ err.span_note(
+ span,
+ format!("[... {} additional calls {} ...]", times, &line),
+ );
+ }
+ }
+ };
+
+ let mut last_frame = None;
+ let mut times = 0;
+ for frame_info in &self.stacktrace {
+ let frame = (frame_info.to_string(), frame_info.span);
+ if last_frame.as_ref() == Some(&frame) {
+ times += 1;
+ } else {
+ flush_last_line(last_frame, times);
+ last_frame = Some(frame);
+ times = 0;
+ }
+ }
+ flush_last_line(last_frame, times);
+ }
+ // Let the caller attach any additional information it wants.
+ decorate(err);
+ }
+
/// Create a diagnostic for this const eval error.
///
/// Sets the message passed in via `message` and adds span labels with detailed error
message: &str,
decorate: impl FnOnce(&mut Diagnostic),
) -> ErrorHandled {
- let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
- trace!("reporting const eval failure at {:?}", self.span);
- if let Some(span_msg) = span_msg {
- err.span_label(self.span, span_msg);
- }
- // Add some more context for select error types.
- match self.error {
- InterpError::Unsupported(
- UnsupportedOpInfo::ReadPointerAsBytes
- | UnsupportedOpInfo::PartialPointerOverwrite(_)
- | UnsupportedOpInfo::PartialPointerCopy(_),
- ) => {
- err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
- err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
- }
- _ => {}
- }
- // Add spans for the stacktrace. Don't print a single-line backtrace though.
- if self.stacktrace.len() > 1 {
- // Helper closure to print duplicated lines.
- let mut flush_last_line = |last_frame, times| {
- if let Some((line, span)) = last_frame {
- err.span_note(span, &line);
- // Don't print [... additional calls ...] if the number of lines is small
- if times < 3 {
- for _ in 0..times {
- err.span_note(span, &line);
- }
- } else {
- err.span_note(
- span,
- format!("[... {} additional calls {} ...]", times, &line),
- );
- }
- }
- };
-
- let mut last_frame = None;
- let mut times = 0;
- for frame_info in &self.stacktrace {
- let frame = (frame_info.to_string(), frame_info.span);
- if last_frame.as_ref() == Some(&frame) {
- times += 1;
- } else {
- flush_last_line(last_frame, times);
- last_frame = Some(frame);
- times = 0;
- }
- }
- flush_last_line(last_frame, times);
- }
- // Let the caller attach any additional information it wants.
- decorate(err);
- };
-
debug!("self.error: {:?}", self.error);
// Special handling for certain errors
match &self.error {
// Don't emit a new diagnostic for these errors
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
- return ErrorHandled::TooGeneric;
- }
- err_inval!(AlreadyReported(error_reported)) => {
- return ErrorHandled::Reported(*error_reported);
+ ErrorHandled::TooGeneric
}
+ err_inval!(AlreadyReported(error_reported)) => ErrorHandled::Reported(*error_reported),
err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
// We must *always* hard error on these, even if the caller wants just a lint.
// The `message` makes little sense here, this is a more serious error than the
// caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>.
let mut err = struct_error(tcx, &self.error.to_string());
- finish(&mut err, None);
- return ErrorHandled::Reported(err.emit());
+ self.decorate(&mut err, decorate);
+ ErrorHandled::Reported(err.emit())
}
- _ => {}
- };
-
- let err_msg = self.error.to_string();
-
- // Report as hard error.
- let mut err = struct_error(tcx, message);
- finish(&mut err, Some(err_msg));
- ErrorHandled::Reported(err.emit())
+ _ => {
+ // Report as hard error.
+ let mut err = struct_error(tcx, message);
+ err.span_label(self.span, self.error.to_string());
+ self.decorate(&mut err, decorate);
+ ErrorHandled::Reported(err.emit())
+ }
+ }
}
}
+use crate::const_eval::CheckAlignment;
use std::borrow::Cow;
use either::{Left, Right};
None => InternKind::Constant,
}
};
- ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
+ ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
// we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
tcx,
root_span,
param_env,
- CompileTimeInterpreter::new(
- tcx.const_eval_limit(),
- can_access_statics,
- /*check_alignment:*/ false,
- ),
+ CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
)
}
CompileTimeInterpreter::new(
tcx.const_eval_limit(),
/*can_access_statics:*/ is_static,
- /*check_alignment:*/ tcx.sess.opts.unstable_opts.extra_const_ub_checks,
+ if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
+ CheckAlignment::Error
+ } else {
+ CheckAlignment::FutureIncompat
+ },
),
);
use rustc_hir::def::DefKind;
-use rustc_hir::LangItem;
+use rustc_hir::{LangItem, CRATE_HIR_ID};
use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops::ControlFlow;
pub(super) can_access_statics: bool,
/// Whether to check alignment during evaluation.
- pub(super) check_alignment: bool,
+ pub(super) check_alignment: CheckAlignment,
+}
+
+#[derive(Copy, Clone)]
+pub enum CheckAlignment {
+ /// Ignore alignment when following relocations.
+ /// This is mainly used in interning.
+ No,
+ /// Hard error when dereferencing a misaligned pointer.
+ Error,
+ /// Emit a future incompat lint when dereferencing a misaligned pointer.
+ FutureIncompat,
+}
+
+impl CheckAlignment {
+ pub fn should_check(&self) -> bool {
+ match self {
+ CheckAlignment::No => false,
+ CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
+ }
+ }
}
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
pub(crate) fn new(
const_eval_limit: Limit,
can_access_statics: bool,
- check_alignment: bool,
+ check_alignment: CheckAlignment,
) -> Self {
CompileTimeInterpreter {
steps_remaining: const_eval_limit.0,
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
#[inline(always)]
- fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
ecx.machine.check_alignment
}
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
}
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ let err = err_ub!(AlignmentCheckFailed { has, required }).into();
+ match check {
+ CheckAlignment::Error => Err(err),
+ CheckAlignment::No => span_bug!(
+ ecx.cur_span(),
+ "`alignment_check_failed` called when no alignment check requested"
+ ),
+ CheckAlignment::FutureIncompat => {
+ let err = ConstEvalErr::new(ecx, err, None);
+ ecx.tcx.struct_span_lint_hir(
+ INVALID_ALIGNMENT,
+ ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+ err.span,
+ err.error.to_string(),
+ |db| {
+ err.decorate(db, |_| {});
+ db
+ },
+ );
+ Ok(())
+ }
+ }
+ }
+
fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>,
Right(span) => span,
}
}
+
+ pub fn lint_root(&self) -> Option<hir::HirId> {
+ self.current_source_info().and_then(|source_info| {
+ match &self.body.source_scopes[source_info.scope].local_data {
+ mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+ mir::ClearCrossCrate::Clear => None,
+ }
+ })
+ }
}
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
// This deliberately does *not* honor `requires_caller_location` since it is used for much
// more than just panics.
for frame in stack.iter().rev() {
- let lint_root = frame.current_source_info().and_then(|source_info| {
- match &frame.body.source_scopes[source_info.scope].local_data {
- mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
- mir::ClearCrossCrate::Clear => None,
- }
- });
+ let lint_root = frame.lint_root();
let span = frame.current_span();
frames.push(FrameInfo { span, instance: frame.instance, lint_root });
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
+use crate::const_eval::CheckAlignment;
+
use super::{
AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
const PANIC_ON_ALLOC_FAIL: bool;
/// Whether memory accesses should be alignment-checked.
- fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
/// Whether, when checking alignment, we should look at the actual address and thus support
/// custom alignment logic based on whatever the integer address happens to be.
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()>;
+
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size};
+use crate::const_eval::CheckAlignment;
+
use super::{
alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
- let align = M::enforce_alignment(&self).then_some(align);
self.check_and_deref_ptr(
ptr,
size,
align,
+ M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
align: Align,
msg: CheckInAllocMsg,
) -> InterpResult<'tcx> {
- self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
- let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
- Ok((size, align, ()))
- })?;
+ self.check_and_deref_ptr(
+ ptr,
+ size,
+ align,
+ CheckAlignment::Error,
+ msg,
+ |alloc_id, _, _| {
+ let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
+ Ok((size, align, ()))
+ },
+ )?;
Ok(())
}
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
- align: Option<Align>,
+ align: Align,
+ check: CheckAlignment,
msg: CheckInAllocMsg,
alloc_size: impl FnOnce(
AllocId,
M::ProvenanceExtra,
) -> InterpResult<'tcx, (Size, Align, T)>,
) -> InterpResult<'tcx, Option<T>> {
- fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
- if offset % align.bytes() == 0 {
- Ok(())
- } else {
- // The biggest power of two through which `offset` is divisible.
- let offset_pow2 = 1 << offset.trailing_zeros();
- throw_ub!(AlignmentCheckFailed {
- has: Align::from_bytes(offset_pow2).unwrap(),
- required: align,
- })
- }
- }
-
Ok(match self.ptr_try_get_alloc_id(ptr) {
Err(addr) => {
// We couldn't get a proper allocation. This is only okay if the access size is 0,
throw_ub!(DanglingIntPointer(addr, msg));
}
// Must be aligned.
- if let Some(align) = align {
- check_offset_align(addr, align)?;
+ if check.should_check() {
+ self.check_offset_align(addr, align, check)?;
}
None
}
}
// Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds.
- if let Some(align) = align {
+ if check.should_check() {
if M::use_addr_for_alignment_check(self) {
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
- check_offset_align(ptr.addr().bytes(), align)?;
+ self.check_offset_align(ptr.addr().bytes(), align, check)?;
} else {
// Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() {
- throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
+ M::alignment_check_failed(self, alloc_align, align, check)?;
}
- check_offset_align(offset.bytes(), align)?;
+ self.check_offset_align(offset.bytes(), align, check)?;
}
}
}
})
}
+
+ fn check_offset_align(
+ &self,
+ offset: u64,
+ align: Align,
+ check: CheckAlignment,
+ ) -> InterpResult<'tcx> {
+ if offset % align.bytes() == 0 {
+ Ok(())
+ } else {
+ // The biggest power of two through which `offset` is divisible.
+ let offset_pow2 = 1 << offset.trailing_zeros();
+ M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
+ }
+ }
}
/// Allocation accessors
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
- let align = M::enforce_alignment(self).then_some(align);
let ptr_and_alloc = self.check_and_deref_ptr(
ptr,
size,
align,
+ M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let alloc = self.get_alloc_raw(alloc_id)?;
.size_and_align_of_mplace(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
- let align = M::enforce_alignment(self).then_some(align);
- self.check_ptr_access_align(
- mplace.ptr,
- size,
- align.unwrap_or(Align::ONE),
- CheckInAllocMsg::DerefTest,
- )?;
+ let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
+ self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
Ok(())
}
use rustc_session::Limit;
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
-use crate::const_eval::CompileTimeInterpreter;
+use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
use crate::interpret::{InterpCx, MemoryKind, OpTy};
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
let machine = CompileTimeInterpreter::new(
Limit::new(0),
/*can_access_statics:*/ false,
- /*check_alignment:*/ true,
+ CheckAlignment::Error,
);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
-An associated const has been referenced in a pattern.
+An associated `const`, `const` parameter or `static` has been referenced
+in a pattern.
Erroneous code example:
```compile_fail,E0158
-enum EFoo { A, B, C, D }
+enum Foo {
+ One,
+ Two
+}
-trait Foo {
- const X: EFoo;
+trait Bar {
+ const X: Foo;
}
-fn test<A: Foo>(arg: EFoo) {
+fn test<A: Bar>(arg: Foo) {
match arg {
- A::X => { // error!
- println!("A::X");
- }
+ A::X => println!("A::X"), // error: E0158: associated consts cannot be
+ // referenced in patterns
+ Foo::Two => println!("Two")
}
}
```
-`const` and `static` mean different things. A `const` is a compile-time
-constant, an alias for a literal value. This property means you can match it
-directly within a pattern.
+Associated `const`s cannot be referenced in patterns because it is impossible
+for the compiler to prove exhaustiveness (that some pattern will always match).
+Take the above example, because Rust does type checking in the *generic*
+method, not the *monomorphized* specific instance. So because `Bar` could have
+theoretically infinite implementations, there's no way to always be sure that
+`A::X` is `Foo::One`. So this code must be rejected. Even if code can be
+proven exhaustive by a programmer, the compiler cannot currently prove this.
-The `static` keyword, on the other hand, guarantees a fixed location in memory.
-This does not always mean that the value is constant. For example, a global
-mutex can be declared `static` as well.
+The same holds true of `const` parameters and `static`s.
-If you want to match against a `static`, consider using a guard instead:
+If you want to match against an associated `const`, `const` parameter or
+`static` consider using a guard instead:
```
-static FORTY_TWO: i32 = 42;
+trait Trait {
+ const X: char;
+}
+
+static FOO: char = 'j';
-match Some(42) {
- Some(x) if x == FORTY_TWO => {}
- _ => {}
+fn test<A: Trait, const Y: char>(arg: char) {
+ match arg {
+ c if c == A::X => println!("A::X"),
+ c if c == Y => println!("Y"),
+ c if c == FOO => println!("FOO"),
+ _ => ()
+ }
}
```
moving {$size} bytes
.label = value moved from here
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_couldnt_dump_mono_stats =
+ unexpected error occurred while dumping monomorphization stats: {$error}
tcx.fn_sig(impl_m.def_id),
),
);
+ impl_sig.error_reported()?;
let impl_return_ty = impl_sig.output();
// Normalize the trait signature with liberated bound vars, passing it through
)
.fold_with(&mut collector);
let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+ trait_sig.error_reported()?;
let trait_return_ty = trait_sig.output();
let wf_tys = FxIndexSet::from_iter(
format!(
"{}::",
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
- self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(),
+ self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
),
Applicability::MaybeIncorrect,
);
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
- (_, DynStar) | (DynStar, _) => {
+ (_, DynStar) => {
if fcx.tcx.features().dyn_star {
bug!("should be handled by `try_coerce`")
} else {
Err(CastError::IllegalCast)
}
}
+
+ (DynStar, _) => Err(CastError::IllegalCast),
}
}
// `deduce_expectations_from_expected_type` introduces
// late-bound lifetimes defined elsewhere, which we now
// anonymize away, so as not to confuse the user.
- let bound_sig = self.tcx.anonymize_late_bound_regions(bound_sig);
+ let bound_sig = self.tcx.anonymize_bound_vars(bound_sig);
let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, Ty};
+use rustc_middle::ty::{
+ self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
+ && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
self.tcx,
traits::ObligationCause::dummy(),
self.param_env,
- ty::Binder::dummy(self.tcx.mk_trait_ref(
- clone_trait_did,
- [expected_ty],
- )),
+ trait_ref,
))
{
diag.span_note(
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
+ let owner = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+ if let ty::Param(param) = expected_ty.kind()
+ && let Some(generics) = self.tcx.hir().get_generics(owner)
+ {
+ suggest_constraining_type_params(
+ self.tcx,
+ generics,
+ diag,
+ vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+ );
+ } else {
+ self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+ }
}
}
use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
- let ty_str = self.ty_to_string(rcvr_ty);
+ let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
let is_method = mode == Mode::MethodCall;
let item_kind = if is_method {
"method"
let term = pred.skip_binder().term;
let obligation = format!("{} = {}", projection_ty, term);
- let quiet = format!("{} = {}", quiet_projection_ty, term);
+ let quiet = with_forced_trimmed_paths!(format!(
+ "{} = {}",
+ quiet_projection_ty, term
+ ));
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
let obligation = format!("{}: {}", self_ty, path);
- let quiet = format!("_: {}", path);
+ let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
bound_span_label(self_ty, &obligation, &quiet);
Some((obligation, self_ty))
}
let entry = spanned_predicates.entry(spans);
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+ span: item_span,
+ ..
+ })) => {
+ tcx.sess.delay_span_bug(
+ *item_span,
+ "auto trait is invoked with no method error, but no error reported?",
+ );
+ }
Some(_) => unreachable!(),
None => (),
}
(None, None)
};
let primary_message = primary_message.unwrap_or_else(|| format!(
- "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+ "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+ but its trait bounds were not satisfied"
));
err.set_primary_message(&primary_message);
if let Some(label) = label {
self.suggest_derive(err, &preds);
}
- fn suggest_derive(
+ pub fn suggest_derive(
&self,
err: &mut Diagnostic,
unsatisfied_predicates: &[(
return;
}
- match it.kind {
+ match &it.kind {
ast::ItemKind::TyAlias(..)
| ast::ItemKind::Enum(..)
| ast::ItemKind::Struct(..)
| ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
+
+ // N.B. This check is only for inherent associated types, so that we don't lint against
+ // trait impls where we should have warned for the trait definition already.
+ ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
+ for it in items {
+ if let ast::AssocItemKind::Type(..) = it.kind {
+ self.check_case(cx, "associated type", &it.ident);
+ }
+ }
+ }
_ => (),
}
}
};
}
+declare_lint! {
+ /// The `invalid_alignment` lint detects dereferences of misaligned pointers during
+ /// constant evluation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![feature(const_ptr_read)]
+ /// const FOO: () = unsafe {
+ /// let x = &[0_u8; 4];
+ /// let y = x.as_ptr().cast::<u32>();
+ /// y.read(); // the address of a `u8` array is unknown and thus we don't know if
+ /// // it is aligned enough for reading a `u32`.
+ /// };
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler allowed dereferencing raw pointers irrespective of alignment
+ /// during const eval due to the const evaluator at the time not making it easy
+ /// or cheap to check. Now that it is both, this is not accepted anymore.
+ ///
+ /// Since it was undefined behaviour to begin with, this breakage does not violate
+ /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
+ /// behaviour, including failure to build.
+ ///
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ pub INVALID_ALIGNMENT,
+ Deny,
+ "raw pointers must be aligned before dereferencing",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
+ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+ };
+}
+
declare_lint! {
/// The `exported_private_dependencies` lint detects private dependencies
/// that are exposed in a public interface.
};
injection_phase > self.phase
}
+
+ #[inline]
+ pub fn is_custom_mir(&self) -> bool {
+ self.injection_phase.is_some()
+ }
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
///////////////////////////////////////////////////////////////////////////
// Places
-impl<V, T> ProjectionElem<V, T> {
+impl<V, T, U> ProjectionElem<V, T, U> {
/// Returns `true` if the target of this projection may refer to a different region of memory
/// than the base.
fn is_indirect(&self) -> bool {
/// Alias for projections as they appear in `UserTypeProjection`, where we
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
-pub type ProjectionKind = ProjectionElem<(), ()>;
+pub type ProjectionKind = ProjectionElem<(), (), ()>;
rustc_index::newtype_index! {
/// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG]
MonoItem::GlobalAsm(..) => LOCAL_CRATE,
}
}
+
+ /// Returns the item's `DefId`
+ pub fn def_id(&self) -> DefId {
+ match *self {
+ MonoItem::Fn(Instance { def, .. }) => def.def_id(),
+ MonoItem::Static(def_id) => def_id,
+ MonoItem::GlobalAsm(item_id) => item_id.owner_id.to_def_id(),
+ }
+ }
}
impl<'tcx> fmt::Display for MonoItem<'tcx> {
pub projection: &'tcx List<PlaceElem<'tcx>>,
}
+/// The different kinds of projections that can be used in the projection of a `Place`.
+///
+/// `T1` is the generic type for a field projection. For an actual projection on a `Place`
+/// this parameter will always be `Ty`, but the field type can be unavailable when
+/// building (by using `PlaceBuilder`) places that correspond to upvars.
+/// `T2` is the generic type for an `OpaqueCast` (is generic since it's abstracted over
+/// in dataflow analysis, see `AbstractElem`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
-pub enum ProjectionElem<V, T> {
+pub enum ProjectionElem<V, T1, T2> {
Deref,
- Field(Field, T),
+ Field(Field, T1),
/// Index into a slice/array.
///
/// Note that this does not also dereference, and so it does not exactly correspond to slice
/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
- OpaqueCast(T),
+ OpaqueCast(T2),
}
/// Alias for projections as they appear in places, where the base is a place
/// and the index is a local.
-pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
+pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>, Ty<'tcx>>;
+
+/// Alias for projections that appear in `PlaceBuilder::Upvar`, for which
+/// we cannot provide any field types.
+pub type UpvarProjectionElem<'tcx> = ProjectionElem<Local, (), Ty<'tcx>>;
+
+impl<'tcx> From<PlaceElem<'tcx>> for UpvarProjectionElem<'tcx> {
+ fn from(elem: PlaceElem<'tcx>) -> Self {
+ match elem {
+ ProjectionElem::Deref => ProjectionElem::Deref,
+ ProjectionElem::Field(field, _) => ProjectionElem::Field(field, ()),
+ ProjectionElem::Index(v) => ProjectionElem::Index(v),
+ ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+ ProjectionElem::ConstantIndex { offset, min_length, from_end }
+ }
+ ProjectionElem::Subslice { from, to, from_end } => {
+ ProjectionElem::Subslice { from, to, from_end }
+ }
+ ProjectionElem::Downcast(opt_sym, variant_idx) => {
+ ProjectionElem::Downcast(opt_sym, variant_idx)
+ }
+ ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
+ }
+ }
+}
///////////////////////////////////////////////////////////////////////////
// Operands
/// `place_ty.field_ty(tcx, f)` computes the type at a given field
/// of a record or enum-variant. (Most clients of `PlaceTy` can
/// instead just extract the relevant type directly from their
- /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
- /// not carry a `Ty` for `T`.)
+ /// `PlaceElem`, but some instances of `ProjectionElem<V, T1, T2>` do
+ /// not carry a `Ty` for `T1` or `T2`.)
///
/// Note that the resulting type has not been normalized.
pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
/// `Ty` or downcast variant corresponding to that projection.
/// The `handle_field` callback must map a `Field` to its `Ty`,
/// (which should be trivial when `T` = `Ty`).
- pub fn projection_ty_core<V, T>(
+ pub fn projection_ty_core<V, T1, T2>(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- elem: &ProjectionElem<V, T>,
- mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
- mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
+ elem: &ProjectionElem<V, T1, T2>,
+ mut handle_field: impl FnMut(&Self, Field, T1) -> Ty<'tcx>,
+ mut handle_opaque_cast: impl FnMut(&Self, T2) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
- T: ::std::fmt::Debug + Copy,
+ T1: ::std::fmt::Debug + Copy,
+ T2: ::std::fmt::Debug + Copy,
{
if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
bug!("cannot use non field projection on downcasted place")
/// The `Key` trait controls what types can legally be used as the key
/// for a query.
pub trait Key: Sized {
- type CacheSelector = DefaultCacheSelector<Self>;
+ // N.B. Most of the keys down below have `type CacheSelector = DefaultCacheSelector<Self>;`,
+ // it would be reasonable to use associated type defaults, to remove the duplication...
+ //
+ // ...But r-a doesn't support them yet and using a default here causes r-a to not infer
+ // return types of queries which is very annoying. Thus, until r-a support associated
+ // type defaults, plese restrain from using them here <3
+ //
+ // r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693>
+ type CacheSelector;
/// Given an instance of this key, what crate is it referring to?
/// This is used to find the provider.
}
impl Key for () {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for ty::InstanceDef<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for ty::Instance<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for DefId {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.krate == LOCAL_CRATE
}
impl Key for ty::WithOptConstParam<LocalDefId> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for SimplifiedType {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for (DefId, DefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for (DefId, LocalDefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl Key for (LocalDefId, DefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for (LocalDefId, LocalDefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for (DefId, Option<Ident>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl Key for (DefId, LocalDefId, Ident) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl Key for (CrateNum, DefId) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0 == LOCAL_CRATE
}
impl Key for (CrateNum, SimplifiedType) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0 == LOCAL_CRATE
}
impl Key for (DefId, SimplifiedType) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl<'tcx> Key for SubstsRef<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.krate == LOCAL_CRATE
}
impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
(self.0).def.did.krate == LOCAL_CRATE
}
impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.1.def_id().krate == LOCAL_CRATE
}
impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.def_id().krate == LOCAL_CRATE
}
impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.def_id().krate == LOCAL_CRATE
}
impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.0.def_id().krate == LOCAL_CRATE
}
impl<'tcx> Key for GenericArg<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for mir::ConstantKind<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for ty::Const<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for Ty<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for TyAndLayout<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for ty::ParamEnv<'tcx> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
self.value.query_crate_is_local()
}
impl Key for Symbol {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for Option<Symbol> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
/// Canonical query goals correspond to abstract trait operations that
/// are not tied to any crate in particular.
impl<'tcx, T> Key for Canonical<'tcx, T> {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for (Symbol, u32, u32) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
impl Key for HirId {
+ type CacheSelector = DefaultCacheSelector<Self>;
+
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
use crate::arena::Arena;
use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::hir::place::Place as HirPlace;
-use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::struct_lint_level;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime;
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
use crate::ty::{
- self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
- ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
- GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
- PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
- TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
+ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstS, DefIdTree, FloatTy, FloatVar,
+ FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
+ ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
+ ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy,
+ Visibility,
};
-use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
+use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, WorkerLocal};
-use rustc_data_structures::unord::UnordSet;
-use rustc_data_structures::vec_map::VecMap;
use rustc_errors::{
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LOCAL_CRATE};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
-use rustc_hir::hir_id::OwnerId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
- Constness, ExprKind, HirId, ImplItemKind, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet,
- Node, TraitCandidate, TraitItemKind,
+ Constness, ExprKind, HirId, ImplItemKind, ItemKind, Node, TraitCandidate, TraitItemKind,
};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
-use rustc_middle::mir::FakeReadCause;
use rustc_query_system::dep_graph::DepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use std::any::Any;
use std::borrow::Borrow;
use std::cmp::Ordering;
-use std::collections::hash_map::{self, Entry};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter;
use std::ops::{Bound, Deref};
use std::sync::Arc;
-use super::{ImplPolarity, RvalueScopes};
-
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
pub unit: Const<'tcx>,
}
-pub struct LocalTableInContext<'a, V> {
- hir_owner: OwnerId,
- data: &'a ItemLocalMap<V>,
-}
-
-/// Validate that the given HirId (respectively its `local_id` part) can be
-/// safely used as a key in the maps of a TypeckResults. For that to be
-/// the case, the HirId must have the same `owner` as all the other IDs in
-/// this table (signified by `hir_owner`). Otherwise the HirId
-/// would be in a different frame of reference and using its `local_id`
-/// would result in lookup errors, or worse, in silently wrong data being
-/// stored/returned.
-#[inline]
-fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
- if hir_id.owner != hir_owner {
- invalid_hir_id_for_typeck_results(hir_owner, hir_id);
- }
-}
-
-#[cold]
-#[inline(never)]
-fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
- ty::tls::with(|tcx| {
- bug!(
- "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
- tcx.hir().node_to_string(hir_id),
- hir_id.owner,
- hir_owner
- )
- });
-}
-
-impl<'a, V> LocalTableInContext<'a, V> {
- pub fn contains_key(&self, id: hir::HirId) -> bool {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.contains_key(&id.local_id)
- }
-
- pub fn get(&self, id: hir::HirId) -> Option<&V> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.get(&id.local_id)
- }
-
- pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
- self.data.iter()
- }
-}
-
-impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
- type Output = V;
-
- fn index(&self, key: hir::HirId) -> &V {
- self.get(key).expect("LocalTableInContext: key not found")
- }
-}
-
-pub struct LocalTableInContextMut<'a, V> {
- hir_owner: OwnerId,
- data: &'a mut ItemLocalMap<V>,
-}
-
-impl<'a, V> LocalTableInContextMut<'a, V> {
- pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.get_mut(&id.local_id)
- }
-
- pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.entry(id.local_id)
- }
-
- pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.insert(id.local_id, val)
- }
-
- pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.data.remove(&id.local_id)
- }
-}
-
-/// Whenever a value may be live across a generator yield, the type of that value winds up in the
-/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
-/// captured types that can be useful for diagnostics. In particular, it stores the span that
-/// caused a given type to be recorded, along with the scope that enclosed the value (which can
-/// be used to find the await that the value is live across).
-///
-/// For example:
-///
-/// ```ignore (pseudo-Rust)
-/// async move {
-/// let x: T = expr;
-/// foo.await
-/// ...
-/// }
-/// ```
-///
-/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
-/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
-#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct GeneratorInteriorTypeCause<'tcx> {
- /// Type of the captured binding.
- pub ty: Ty<'tcx>,
- /// Span of the binding that was captured.
- pub span: Span,
- /// Span of the scope of the captured binding.
- pub scope_span: Option<Span>,
- /// Span of `.await` or `yield` expression.
- pub yield_span: Span,
- /// Expr which the type evaluated from.
- pub expr: Option<hir::HirId>,
-}
-
-// This type holds diagnostic information on generators and async functions across crate boundaries
-// and is used to provide better error messages
-#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
-pub struct GeneratorDiagnosticData<'tcx> {
- pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
- pub hir_owner: DefId,
- pub nodes_types: ItemLocalMap<Ty<'tcx>>,
- pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-}
-
-#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct TypeckResults<'tcx> {
- /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
- pub hir_owner: OwnerId,
-
- /// Resolved definitions for `<T>::X` associated paths and
- /// method calls, including those of overloaded operators.
- type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
-
- /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
- /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
- /// about the field you also need definition of the variant to which the field
- /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
- field_indices: ItemLocalMap<usize>,
-
- /// Stores the types for various nodes in the AST. Note that this table
- /// is not guaranteed to be populated outside inference. See
- /// typeck::check::fn_ctxt for details.
- node_types: ItemLocalMap<Ty<'tcx>>,
-
- /// Stores the type parameters which were substituted to obtain the type
- /// of this node. This only applies to nodes that refer to entities
- /// parameterized by type parameters, such as generic fns, types, or
- /// other items.
- node_substs: ItemLocalMap<SubstsRef<'tcx>>,
-
- /// This will either store the canonicalized types provided by the user
- /// or the substitutions that the user explicitly gave (if any) attached
- /// to `id`. These will not include any inferred values. The canonical form
- /// is used to capture things like `_` or other unspecified values.
- ///
- /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
- /// canonical substitutions would include only `for<X> { Vec<X> }`.
- ///
- /// See also `AscribeUserType` statement in MIR.
- user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
-
- /// Stores the canonicalized types provided by the user. See also
- /// `AscribeUserType` statement in MIR.
- pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
-
- adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
-
- /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
- pat_binding_modes: ItemLocalMap<BindingMode>,
-
- /// Stores the types which were implicitly dereferenced in pattern binding modes
- /// for later usage in THIR lowering. For example,
- ///
- /// ```
- /// match &&Some(5i32) {
- /// Some(n) => {},
- /// _ => {},
- /// }
- /// ```
- /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
- ///
- /// See:
- /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
- pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
-
- /// Records the reasons that we picked the kind of each closure;
- /// not all closures are present in the map.
- closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
-
- /// For each fn, records the "liberated" types of its arguments
- /// and return type. Liberated means that all bound regions
- /// (including late-bound regions) are replaced with free
- /// equivalents. This table is not used in codegen (since regions
- /// are erased there) and hence is not serialized to metadata.
- ///
- /// This table also contains the "revealed" values for any `impl Trait`
- /// that appear in the signature and whose values are being inferred
- /// by this function.
- ///
- /// # Example
- ///
- /// ```rust
- /// # use std::fmt::Debug;
- /// fn foo(x: &u32) -> impl Debug { *x }
- /// ```
- ///
- /// The function signature here would be:
- ///
- /// ```ignore (illustrative)
- /// for<'a> fn(&'a u32) -> Foo
- /// ```
- ///
- /// where `Foo` is an opaque type created for this function.
- ///
- ///
- /// The *liberated* form of this would be
- ///
- /// ```ignore (illustrative)
- /// fn(&'a u32) -> u32
- /// ```
- ///
- /// Note that `'a` is not bound (it would be an `ReFree`) and
- /// that the `Foo` opaque type is replaced by its hidden type.
- liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
-
- /// For each FRU expression, record the normalized types of the fields
- /// of the struct - this is needed because it is non-trivial to
- /// normalize while preserving regions. This table is used only in
- /// MIR construction and hence is not serialized to metadata.
- fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
-
- /// For every coercion cast we add the HIR node ID of the cast
- /// expression to this set.
- coercion_casts: ItemLocalSet,
-
- /// Set of trait imports actually used in the method resolution.
- /// This is used for warning unused imports. During type
- /// checking, this `Lrc` should not be cloned: it must have a ref-count
- /// of 1 so that we can insert things into the set mutably.
- pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
-
- /// If any errors occurred while type-checking this body,
- /// this field will be set to `Some(ErrorGuaranteed)`.
- pub tainted_by_errors: Option<ErrorGuaranteed>,
-
- /// All the opaque types that have hidden types set
- /// by this function. We also store the
- /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
- /// even if they are only set in dead code (which doesn't show up in MIR).
- pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
-
- /// Tracks the minimum captures required for a closure;
- /// see `MinCaptureInformationMap` for more details.
- pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
-
- /// Tracks the fake reads required for a closure and the reason for the fake read.
- /// When performing pattern matching for closures, there are times we don't end up
- /// reading places that are mentioned in a closure (because of _ patterns). However,
- /// to ensure the places are initialized, we introduce fake reads.
- /// Consider these two examples:
- /// ``` (discriminant matching with only wildcard arm)
- /// let x: u8;
- /// let c = || match x { _ => () };
- /// ```
- /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
- /// want to capture it. However, we do still want an error here, because `x` should have
- /// to be initialized at the point where c is created. Therefore, we add a "fake read"
- /// instead.
- /// ``` (destructured assignments)
- /// let c = || {
- /// let (t1, t2) = t;
- /// }
- /// ```
- /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
- /// we never capture `t`. This becomes an issue when we build MIR as we require
- /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
- /// issue by fake reading `t`.
- pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
-
- /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
- /// by applying extended parameter rules.
- /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
- pub rvalue_scopes: RvalueScopes,
-
- /// Stores the type, expression, span and optional scope span of all types
- /// that are live across the yield of this generator (if a generator).
- pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
-
- /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
- /// as `&[u8]`, depending on the pattern in which they are used.
- /// This hashset records all instances where we behave
- /// like this to allow `const_to_pat` to reliably handle this situation.
- pub treat_byte_string_as_slice: ItemLocalSet,
-
- /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
- /// on closure size.
- pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
-}
-
-impl<'tcx> TypeckResults<'tcx> {
- pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
- TypeckResults {
- hir_owner,
- type_dependent_defs: Default::default(),
- field_indices: Default::default(),
- user_provided_types: Default::default(),
- user_provided_sigs: Default::default(),
- node_types: Default::default(),
- node_substs: Default::default(),
- adjustments: Default::default(),
- pat_binding_modes: Default::default(),
- pat_adjustments: Default::default(),
- closure_kind_origins: Default::default(),
- liberated_fn_sigs: Default::default(),
- fru_field_types: Default::default(),
- coercion_casts: Default::default(),
- used_trait_imports: Lrc::new(Default::default()),
- tainted_by_errors: None,
- concrete_opaque_types: Default::default(),
- closure_min_captures: Default::default(),
- closure_fake_reads: Default::default(),
- rvalue_scopes: Default::default(),
- generator_interior_types: ty::Binder::dummy(Default::default()),
- treat_byte_string_as_slice: Default::default(),
- closure_size_eval: Default::default(),
- }
- }
-
- /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
- pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
- match *qpath {
- hir::QPath::Resolved(_, ref path) => path.res,
- hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
- .type_dependent_def(id)
- .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
- }
- }
-
- pub fn type_dependent_defs(
- &self,
- ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
- }
-
- pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
- }
-
- pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
- self.type_dependent_def(id).map(|(_, def_id)| def_id)
- }
-
- pub fn type_dependent_defs_mut(
- &mut self,
- ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
- }
-
- pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
- }
-
- pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
- }
-
- pub fn field_index(&self, id: hir::HirId) -> usize {
- self.field_indices().get(id).cloned().expect("no index for a field")
- }
-
- pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
- self.field_indices().get(id).cloned()
- }
-
- pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
- }
-
- pub fn user_provided_types_mut(
- &mut self,
- ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
- }
-
- pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
- }
-
- pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
- }
-
- pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
- let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
- vec.iter()
- .map(|item| {
- GeneratorInteriorTypeCause {
- ty: item.ty,
- span: item.span,
- scope_span: item.scope_span,
- yield_span: item.yield_span,
- expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
- }
- })
- .collect::<Vec<_>>()
- });
- GeneratorDiagnosticData {
- generator_interior_types: generator_interior_type,
- hir_owner: self.hir_owner.to_def_id(),
- nodes_types: self.node_types.clone(),
- adjustments: self.adjustments.clone(),
- }
- }
-
- pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
- self.node_type_opt(id).unwrap_or_else(|| {
- bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
- })
- }
-
- pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.node_types.get(&id.local_id).cloned()
- }
-
- pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
- }
-
- pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
- }
-
- pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
- validate_hir_id_for_typeck_results(self.hir_owner, id);
- self.node_substs.get(&id.local_id).cloned()
- }
-
- /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
- /// doesn't provide type parameter substitutions.
- ///
- /// [`expr_ty`]: TypeckResults::expr_ty
- pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
- self.node_type(pat.hir_id)
- }
-
- /// Returns the type of an expression as a monotype.
- ///
- /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
- /// some cases, we insert `Adjustment` annotations such as auto-deref or
- /// auto-ref. The type returned by this function does not consider such
- /// adjustments. See `expr_ty_adjusted()` instead.
- ///
- /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
- /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
- /// instead of `fn(ty) -> T with T = isize`.
- pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
- self.node_type(expr.hir_id)
- }
-
- pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
- self.node_type_opt(expr.hir_id)
- }
-
- pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
- }
-
- pub fn adjustments_mut(
- &mut self,
- ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
- }
-
- pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
- validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
- self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
- }
-
- /// Returns the type of `expr`, considering any `Adjustment`
- /// entry recorded for that expression.
- pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
- self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
- }
-
- pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
- self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
- }
-
- pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
- // Only paths and method calls/overloaded operators have
- // entries in type_dependent_defs, ignore the former here.
- if let hir::ExprKind::Path(_) = expr.kind {
- return false;
- }
-
- matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
- }
-
- pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
- self.pat_binding_modes().get(id).copied().or_else(|| {
- s.delay_span_bug(sp, "missing binding mode");
- None
- })
- }
-
- pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
- }
-
- pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
- }
-
- pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
- }
-
- pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
- }
-
- /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
- /// by the closure.
- pub fn closure_min_captures_flattened(
- &self,
- closure_def_id: LocalDefId,
- ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
- self.closure_min_captures
- .get(&closure_def_id)
- .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
- .into_iter()
- .flatten()
- }
-
- pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
- }
-
- pub fn closure_kind_origins_mut(
- &mut self,
- ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
- }
-
- pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
- }
-
- pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
- }
-
- pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
- LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
- }
-
- pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
- LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
- }
-
- pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
- validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
- self.coercion_casts.contains(&hir_id.local_id)
- }
-
- pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
- self.coercion_casts.insert(id);
- }
-
- pub fn coercion_casts(&self) -> &ItemLocalSet {
- &self.coercion_casts
- }
-}
-
-rustc_index::newtype_index! {
- pub struct UserTypeAnnotationIndex {
- derive [HashStable]
- DEBUG_FORMAT = "UserType({})",
- const START_INDEX = 0,
- }
-}
-
-/// Mapping of type annotation indices to canonical user type annotations.
-pub type CanonicalUserTypeAnnotations<'tcx> =
- IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
-
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct CanonicalUserTypeAnnotation<'tcx> {
- pub user_ty: Box<CanonicalUserType<'tcx>>,
- pub span: Span,
- pub inferred_ty: Ty<'tcx>,
-}
-
-/// Canonicalized user type annotation.
-pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
-
-impl<'tcx> CanonicalUserType<'tcx> {
- /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
- /// i.e., each thing is mapped to a canonical variable with the same index.
- pub fn is_identity(&self) -> bool {
- match self.value {
- UserType::Ty(_) => false,
- UserType::TypeOf(_, user_substs) => {
- if user_substs.user_self_ty.is_some() {
- return false;
- }
-
- iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
- match kind.unpack() {
- GenericArgKind::Type(ty) => match ty.kind() {
- ty::Bound(debruijn, b) => {
- // We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(*debruijn, ty::INNERMOST);
- cvar == b.var
- }
- _ => false,
- },
-
- GenericArgKind::Lifetime(r) => match *r {
- ty::ReLateBound(debruijn, br) => {
- // We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(debruijn, ty::INNERMOST);
- cvar == br.var
- }
- _ => false,
- },
-
- GenericArgKind::Const(ct) => match ct.kind() {
- ty::ConstKind::Bound(debruijn, b) => {
- // We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(debruijn, ty::INNERMOST);
- cvar == b
- }
- _ => false,
- },
- }
- })
- }
- }
- }
-}
-
-/// A user-given type annotation attached to a constant. These arise
-/// from constants that are named via paths, like `Foo::<A>::new` and
-/// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum UserType<'tcx> {
- Ty(Ty<'tcx>),
-
- /// The canonical type is the result of `type_of(def_id)` with the
- /// given substitutions applied.
- TypeOf(DefId, UserSubsts<'tcx>),
-}
-
impl<'tcx> CommonTypes<'tcx> {
fn new(
interners: &CtxtInterners<'tcx>,
use std::hash::Hash;
use std::iter;
-use self::SimplifiedTypeGen::*;
+use self::SimplifiedType::*;
-pub type SimplifiedType = SimplifiedTypeGen<DefId>;
-
-/// See `simplify_type`
-///
-/// Note that we keep this type generic over the type of identifier it uses
-/// because we sometimes need to use SimplifiedTypeGen values as stable sorting
-/// keys (in which case we use a DefPathHash as id-type) but in the general case
-/// the non-stable but fast to construct DefId-version is the better choice.
+/// See `simplify_type`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
-pub enum SimplifiedTypeGen<D>
-where
- D: Copy + Debug + Eq,
-{
+pub enum SimplifiedType {
BoolSimplifiedType,
CharSimplifiedType,
IntSimplifiedType(ty::IntTy),
UintSimplifiedType(ty::UintTy),
FloatSimplifiedType(ty::FloatTy),
- AdtSimplifiedType(D),
- ForeignSimplifiedType(D),
+ AdtSimplifiedType(DefId),
+ ForeignSimplifiedType(DefId),
StrSimplifiedType,
ArraySimplifiedType,
SliceSimplifiedType,
/// A trait object, all of whose components are markers
/// (e.g., `dyn Send + Sync`).
MarkerTraitObjectSimplifiedType,
- TraitSimplifiedType(D),
- ClosureSimplifiedType(D),
- GeneratorSimplifiedType(D),
+ TraitSimplifiedType(DefId),
+ ClosureSimplifiedType(DefId),
+ GeneratorSimplifiedType(DefId),
GeneratorWitnessSimplifiedType(usize),
FunctionSimplifiedType(usize),
PlaceholderSimplifiedType,
}
}
-impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
- pub fn def(self) -> Option<D> {
+impl SimplifiedType {
+ pub fn def(self) -> Option<DefId> {
match self {
AdtSimplifiedType(d)
| ForeignSimplifiedType(d)
_ => None,
}
}
-
- pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
- where
- F: Fn(D) -> U,
- U: Copy + Debug + Eq,
- {
- match self {
- BoolSimplifiedType => BoolSimplifiedType,
- CharSimplifiedType => CharSimplifiedType,
- IntSimplifiedType(t) => IntSimplifiedType(t),
- UintSimplifiedType(t) => UintSimplifiedType(t),
- FloatSimplifiedType(t) => FloatSimplifiedType(t),
- AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
- ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)),
- StrSimplifiedType => StrSimplifiedType,
- ArraySimplifiedType => ArraySimplifiedType,
- SliceSimplifiedType => SliceSimplifiedType,
- RefSimplifiedType(m) => RefSimplifiedType(m),
- PtrSimplifiedType(m) => PtrSimplifiedType(m),
- NeverSimplifiedType => NeverSimplifiedType,
- MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
- TupleSimplifiedType(n) => TupleSimplifiedType(n),
- TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
- ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
- GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
- GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
- FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
- PlaceholderSimplifiedType => PlaceholderSimplifiedType,
- }
- }
}
/// Given generic arguments from an obligation and an impl,
self.replace_late_bound_regions(value, |_| self.lifetimes.re_erased).0
}
- /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
- /// assigned starting at 0 and increasing monotonically in the order traversed
- /// by the fold operation.
- ///
- /// The chief purpose of this function is to canonicalize regions so that two
- /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
- /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
- /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
- pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tcx, T>
- where
- T: TypeFoldable<'tcx>,
- {
- let mut counter = 0;
- let inner = self
- .replace_late_bound_regions(sig, |_| {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter, None),
- };
- let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
- counter += 1;
- r
- })
- .0;
- let bound_vars = self.mk_bound_variable_kinds(
- (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
- );
- Binder::bind_with_vars(inner, bound_vars)
- }
-
/// Anonymize all bound variables in `value`, this is mostly used to improve caching.
pub fn anonymize_bound_vars<T>(self, value: Binder<'tcx, T>) -> Binder<'tcx, T>
where
Const, ConstInt, ConstKind, ConstS, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
- tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
- GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TyCtxtFeed, TypeckResults,
- UserType, UserTypeAnnotationIndex,
+ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
+ TyCtxtFeed,
};
pub use self::instance::{Instance, InstanceDef, ShortInstance};
pub use self::list::List;
Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
};
pub use self::trait_def::TraitDef;
+pub use self::typeck_results::{
+ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, TypeckResults, UserType,
+ UserTypeAnnotationIndex,
+};
pub mod _match;
pub mod abstract_const;
mod rvalue_scopes;
mod structural_impls;
mod sty;
+mod typeck_results;
// Data types
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{DefId, DefIndex};
+use rustc_hir::def_id::DefIndex;
use rustc_index::vec::{Idx, IndexVec};
-use crate::middle::exported_symbols::ExportedSymbol;
-use crate::mir::Body;
-use crate::ty::{
- self, Clause, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
-};
+use crate::ty;
pub trait ParameterizedOverTcx: 'static {
- #[allow(unused_lifetimes)]
type Value<'tcx>;
}
ty::TraitDef,
ty::Visibility<DefIndex>,
ty::adjustment::CoerceUnsizedInfo,
- ty::fast_reject::SimplifiedTypeGen<DefId>,
+ ty::fast_reject::SimplifiedType,
rustc_ast::Attribute,
rustc_ast::DelimArgs,
rustc_attr::ConstStability,
rustc_type_ir::Variance,
}
-// HACK(compiler-errors): This macro rule can only take an ident,
-// not a path, due to parsing ambiguity reasons. That means we gotta
-// import all of these types above.
+// HACK(compiler-errors): This macro rule can only take a fake path,
+// not a real, due to parsing ambiguity reasons.
#[macro_export]
macro_rules! parameterized_over_tcx {
- ($($ident:ident),+ $(,)?) => {
+ ($($($fake_path:ident)::+),+ $(,)?) => {
$(
- impl $crate::ty::ParameterizedOverTcx for $ident<'static> {
- type Value<'tcx> = $ident<'tcx>;
+ impl $crate::ty::ParameterizedOverTcx for $($fake_path)::+<'static> {
+ type Value<'tcx> = $($fake_path)::+<'tcx>;
}
)*
}
}
parameterized_over_tcx! {
- Ty,
- FnSig,
- GenericPredicates,
- TraitRef,
- Const,
- Predicate,
- Clause,
- GeneratorDiagnosticData,
- Body,
- ExportedSymbol,
+ crate::middle::exported_symbols::ExportedSymbol,
+ crate::mir::Body,
+ ty::Ty,
+ ty::FnSig,
+ ty::GenericPredicates,
+ ty::TraitRef,
+ ty::Const,
+ ty::Predicate,
+ ty::Clause,
+ ty::GeneratorDiagnosticData,
}
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
use rustc_session::Limit;
use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::FileNameDisplayPreference;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
p!("@", print_def_path(did.to_def_id(), substs));
} else {
let span = self.tcx().def_span(did);
+ let preference = if FORCE_TRIMMED_PATH.with(|flag| flag.get()) {
+ FileNameDisplayPreference::Short
+ } else {
+ FileNameDisplayPreference::Remapped
+ };
p!(write(
"@{}",
// This may end up in stderr diagnostics but it may also be emitted
// into MIR. Hence we use the remapped path if available
- self.tcx().sess.source_map().span_to_embeddable_string(span)
+ self.tcx().sess.source_map().span_to_string(span, preference)
));
}
} else {
--- /dev/null
+use crate::{
+ hir::place::Place as HirPlace,
+ infer::canonical::Canonical,
+ ty::{
+ self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
+ GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
+ },
+};
+use rustc_data_structures::{fx::FxHashMap, sync::Lrc, unord::UnordSet, vec_map::VecMap};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::{
+ def::{DefKind, Res},
+ def_id::{DefId, LocalDefId, LocalDefIdMap},
+ hir_id::OwnerId,
+ HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
+};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_macros::HashStable;
+use rustc_middle::mir::FakeReadCause;
+use rustc_session::Session;
+use rustc_span::Span;
+use std::{
+ collections::hash_map::{self, Entry},
+ hash::Hash,
+ iter,
+};
+
+use super::RvalueScopes;
+
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct TypeckResults<'tcx> {
+ /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
+ pub hir_owner: OwnerId,
+
+ /// Resolved definitions for `<T>::X` associated paths and
+ /// method calls, including those of overloaded operators.
+ type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
+
+ /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
+ /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
+ /// about the field you also need definition of the variant to which the field
+ /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
+ field_indices: ItemLocalMap<usize>,
+
+ /// Stores the types for various nodes in the AST. Note that this table
+ /// is not guaranteed to be populated outside inference. See
+ /// typeck::check::fn_ctxt for details.
+ node_types: ItemLocalMap<Ty<'tcx>>,
+
+ /// Stores the type parameters which were substituted to obtain the type
+ /// of this node. This only applies to nodes that refer to entities
+ /// parameterized by type parameters, such as generic fns, types, or
+ /// other items.
+ node_substs: ItemLocalMap<SubstsRef<'tcx>>,
+
+ /// This will either store the canonicalized types provided by the user
+ /// or the substitutions that the user explicitly gave (if any) attached
+ /// to `id`. These will not include any inferred values. The canonical form
+ /// is used to capture things like `_` or other unspecified values.
+ ///
+ /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
+ /// canonical substitutions would include only `for<X> { Vec<X> }`.
+ ///
+ /// See also `AscribeUserType` statement in MIR.
+ user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
+
+ /// Stores the canonicalized types provided by the user. See also
+ /// `AscribeUserType` statement in MIR.
+ pub user_provided_sigs: LocalDefIdMap<CanonicalPolyFnSig<'tcx>>,
+
+ adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+
+ /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
+ pat_binding_modes: ItemLocalMap<BindingMode>,
+
+ /// Stores the types which were implicitly dereferenced in pattern binding modes
+ /// for later usage in THIR lowering. For example,
+ ///
+ /// ```
+ /// match &&Some(5i32) {
+ /// Some(n) => {},
+ /// _ => {},
+ /// }
+ /// ```
+ /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
+ ///
+ /// See:
+ /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
+ pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+ /// Records the reasons that we picked the kind of each closure;
+ /// not all closures are present in the map.
+ closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
+
+ /// For each fn, records the "liberated" types of its arguments
+ /// and return type. Liberated means that all bound regions
+ /// (including late-bound regions) are replaced with free
+ /// equivalents. This table is not used in codegen (since regions
+ /// are erased there) and hence is not serialized to metadata.
+ ///
+ /// This table also contains the "revealed" values for any `impl Trait`
+ /// that appear in the signature and whose values are being inferred
+ /// by this function.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::fmt::Debug;
+ /// fn foo(x: &u32) -> impl Debug { *x }
+ /// ```
+ ///
+ /// The function signature here would be:
+ ///
+ /// ```ignore (illustrative)
+ /// for<'a> fn(&'a u32) -> Foo
+ /// ```
+ ///
+ /// where `Foo` is an opaque type created for this function.
+ ///
+ ///
+ /// The *liberated* form of this would be
+ ///
+ /// ```ignore (illustrative)
+ /// fn(&'a u32) -> u32
+ /// ```
+ ///
+ /// Note that `'a` is not bound (it would be an `ReFree`) and
+ /// that the `Foo` opaque type is replaced by its hidden type.
+ liberated_fn_sigs: ItemLocalMap<ty::FnSig<'tcx>>,
+
+ /// For each FRU expression, record the normalized types of the fields
+ /// of the struct - this is needed because it is non-trivial to
+ /// normalize while preserving regions. This table is used only in
+ /// MIR construction and hence is not serialized to metadata.
+ fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
+
+ /// For every coercion cast we add the HIR node ID of the cast
+ /// expression to this set.
+ coercion_casts: ItemLocalSet,
+
+ /// Set of trait imports actually used in the method resolution.
+ /// This is used for warning unused imports. During type
+ /// checking, this `Lrc` should not be cloned: it must have a ref-count
+ /// of 1 so that we can insert things into the set mutably.
+ pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
+
+ /// If any errors occurred while type-checking this body,
+ /// this field will be set to `Some(ErrorGuaranteed)`.
+ pub tainted_by_errors: Option<ErrorGuaranteed>,
+
+ /// All the opaque types that have hidden types set
+ /// by this function. We also store the
+ /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
+ /// even if they are only set in dead code (which doesn't show up in MIR).
+ pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+
+ /// Tracks the minimum captures required for a closure;
+ /// see `MinCaptureInformationMap` for more details.
+ pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
+
+ /// Tracks the fake reads required for a closure and the reason for the fake read.
+ /// When performing pattern matching for closures, there are times we don't end up
+ /// reading places that are mentioned in a closure (because of _ patterns). However,
+ /// to ensure the places are initialized, we introduce fake reads.
+ /// Consider these two examples:
+ /// ``` (discriminant matching with only wildcard arm)
+ /// let x: u8;
+ /// let c = || match x { _ => () };
+ /// ```
+ /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
+ /// want to capture it. However, we do still want an error here, because `x` should have
+ /// to be initialized at the point where c is created. Therefore, we add a "fake read"
+ /// instead.
+ /// ``` (destructured assignments)
+ /// let c = || {
+ /// let (t1, t2) = t;
+ /// }
+ /// ```
+ /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but
+ /// we never capture `t`. This becomes an issue when we build MIR as we require
+ /// information on `t` in order to create place `t.0` and `t.1`. We can solve this
+ /// issue by fake reading `t`.
+ pub closure_fake_reads: FxHashMap<LocalDefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
+
+ /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+ /// by applying extended parameter rules.
+ /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
+ pub rvalue_scopes: RvalueScopes,
+
+ /// Stores the type, expression, span and optional scope span of all types
+ /// that are live across the yield of this generator (if a generator).
+ pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+
+ /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
+ /// as `&[u8]`, depending on the pattern in which they are used.
+ /// This hashset records all instances where we behave
+ /// like this to allow `const_to_pat` to reliably handle this situation.
+ pub treat_byte_string_as_slice: ItemLocalSet,
+
+ /// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
+ /// on closure size.
+ pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
+}
+
+/// Whenever a value may be live across a generator yield, the type of that value winds up in the
+/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
+/// captured types that can be useful for diagnostics. In particular, it stores the span that
+/// caused a given type to be recorded, along with the scope that enclosed the value (which can
+/// be used to find the await that the value is live across).
+///
+/// For example:
+///
+/// ```ignore (pseudo-Rust)
+/// async move {
+/// let x: T = expr;
+/// foo.await
+/// ...
+/// }
+/// ```
+///
+/// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
+/// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub struct GeneratorInteriorTypeCause<'tcx> {
+ /// Type of the captured binding.
+ pub ty: Ty<'tcx>,
+ /// Span of the binding that was captured.
+ pub span: Span,
+ /// Span of the scope of the captured binding.
+ pub scope_span: Option<Span>,
+ /// Span of `.await` or `yield` expression.
+ pub yield_span: Span,
+ /// Expr which the type evaluated from.
+ pub expr: Option<hir::HirId>,
+}
+
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+ pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+ pub hir_owner: DefId,
+ pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+ pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
+impl<'tcx> TypeckResults<'tcx> {
+ pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
+ TypeckResults {
+ hir_owner,
+ type_dependent_defs: Default::default(),
+ field_indices: Default::default(),
+ user_provided_types: Default::default(),
+ user_provided_sigs: Default::default(),
+ node_types: Default::default(),
+ node_substs: Default::default(),
+ adjustments: Default::default(),
+ pat_binding_modes: Default::default(),
+ pat_adjustments: Default::default(),
+ closure_kind_origins: Default::default(),
+ liberated_fn_sigs: Default::default(),
+ fru_field_types: Default::default(),
+ coercion_casts: Default::default(),
+ used_trait_imports: Lrc::new(Default::default()),
+ tainted_by_errors: None,
+ concrete_opaque_types: Default::default(),
+ closure_min_captures: Default::default(),
+ closure_fake_reads: Default::default(),
+ rvalue_scopes: Default::default(),
+ generator_interior_types: ty::Binder::dummy(Default::default()),
+ treat_byte_string_as_slice: Default::default(),
+ closure_size_eval: Default::default(),
+ }
+ }
+
+ /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
+ pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
+ match *qpath {
+ hir::QPath::Resolved(_, ref path) => path.res,
+ hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
+ .type_dependent_def(id)
+ .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
+ }
+ }
+
+ pub fn type_dependent_defs(
+ &self,
+ ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
+ }
+
+ pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
+ }
+
+ pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
+ self.type_dependent_def(id).map(|(_, def_id)| def_id)
+ }
+
+ pub fn type_dependent_defs_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
+ }
+
+ pub fn field_indices(&self) -> LocalTableInContext<'_, usize> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.field_indices }
+ }
+
+ pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<'_, usize> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.field_indices }
+ }
+
+ pub fn field_index(&self, id: hir::HirId) -> usize {
+ self.field_indices().get(id).cloned().expect("no index for a field")
+ }
+
+ pub fn opt_field_index(&self, id: hir::HirId) -> Option<usize> {
+ self.field_indices().get(id).cloned()
+ }
+
+ pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
+ }
+
+ pub fn user_provided_types_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.user_provided_types }
+ }
+
+ pub fn node_types(&self) -> LocalTableInContext<'_, Ty<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.node_types }
+ }
+
+ pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
+ }
+
+ pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+ let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+ vec.iter()
+ .map(|item| {
+ GeneratorInteriorTypeCause {
+ ty: item.ty,
+ span: item.span,
+ scope_span: item.scope_span,
+ yield_span: item.yield_span,
+ expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+ }
+ })
+ .collect::<Vec<_>>()
+ });
+ GeneratorDiagnosticData {
+ generator_interior_types: generator_interior_type,
+ hir_owner: self.hir_owner.to_def_id(),
+ nodes_types: self.node_types.clone(),
+ adjustments: self.adjustments.clone(),
+ }
+ }
+
+ pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
+ self.node_type_opt(id).unwrap_or_else(|| {
+ bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
+ })
+ }
+
+ pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.node_types.get(&id.local_id).cloned()
+ }
+
+ pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_substs }
+ }
+
+ pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
+ }
+
+ pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.node_substs.get(&id.local_id).cloned()
+ }
+
+ /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
+ /// doesn't provide type parameter substitutions.
+ ///
+ /// [`expr_ty`]: TypeckResults::expr_ty
+ pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
+ self.node_type(pat.hir_id)
+ }
+
+ /// Returns the type of an expression as a monotype.
+ ///
+ /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
+ /// some cases, we insert `Adjustment` annotations such as auto-deref or
+ /// auto-ref. The type returned by this function does not consider such
+ /// adjustments. See `expr_ty_adjusted()` instead.
+ ///
+ /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
+ /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
+ /// instead of `fn(ty) -> T with T = isize`.
+ pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+ self.node_type(expr.hir_id)
+ }
+
+ pub fn expr_ty_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+ self.node_type_opt(expr.hir_id)
+ }
+
+ pub fn adjustments(&self) -> LocalTableInContext<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.adjustments }
+ }
+
+ pub fn adjustments_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::Adjustment<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.adjustments }
+ }
+
+ pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
+ validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
+ self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
+ }
+
+ /// Returns the type of `expr`, considering any `Adjustment`
+ /// entry recorded for that expression.
+ pub fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
+ self.expr_adjustments(expr).last().map_or_else(|| self.expr_ty(expr), |adj| adj.target)
+ }
+
+ pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr<'_>) -> Option<Ty<'tcx>> {
+ self.expr_adjustments(expr).last().map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr))
+ }
+
+ pub fn is_method_call(&self, expr: &hir::Expr<'_>) -> bool {
+ // Only paths and method calls/overloaded operators have
+ // entries in type_dependent_defs, ignore the former here.
+ if let hir::ExprKind::Path(_) = expr.kind {
+ return false;
+ }
+
+ matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
+ }
+
+ pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
+ self.pat_binding_modes().get(id).copied().or_else(|| {
+ s.delay_span_bug(sp, "missing binding mode");
+ None
+ })
+ }
+
+ pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
+ }
+
+ pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
+ }
+
+ pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
+ }
+
+ pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
+ }
+
+ /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
+ /// by the closure.
+ pub fn closure_min_captures_flattened(
+ &self,
+ closure_def_id: LocalDefId,
+ ) -> impl Iterator<Item = &ty::CapturedPlace<'tcx>> {
+ self.closure_min_captures
+ .get(&closure_def_id)
+ .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter()))
+ .into_iter()
+ .flatten()
+ }
+
+ pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
+ }
+
+ pub fn closure_kind_origins_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
+ }
+
+ pub fn liberated_fn_sigs(&self) -> LocalTableInContext<'_, ty::FnSig<'tcx>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.liberated_fn_sigs }
+ }
+
+ pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut<'_, ty::FnSig<'tcx>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.liberated_fn_sigs }
+ }
+
+ pub fn fru_field_types(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.fru_field_types }
+ }
+
+ pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.fru_field_types }
+ }
+
+ pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
+ validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
+ self.coercion_casts.contains(&hir_id.local_id)
+ }
+
+ pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
+ self.coercion_casts.insert(id);
+ }
+
+ pub fn coercion_casts(&self) -> &ItemLocalSet {
+ &self.coercion_casts
+ }
+}
+
+/// Validate that the given HirId (respectively its `local_id` part) can be
+/// safely used as a key in the maps of a TypeckResults. For that to be
+/// the case, the HirId must have the same `owner` as all the other IDs in
+/// this table (signified by `hir_owner`). Otherwise the HirId
+/// would be in a different frame of reference and using its `local_id`
+/// would result in lookup errors, or worse, in silently wrong data being
+/// stored/returned.
+#[inline]
+fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+ if hir_id.owner != hir_owner {
+ invalid_hir_id_for_typeck_results(hir_owner, hir_id);
+ }
+}
+
+#[cold]
+#[inline(never)]
+fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
+ ty::tls::with(|tcx| {
+ bug!(
+ "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
+ tcx.hir().node_to_string(hir_id),
+ hir_id.owner,
+ hir_owner
+ )
+ });
+}
+
+pub struct LocalTableInContext<'a, V> {
+ hir_owner: OwnerId,
+ data: &'a ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContext<'a, V> {
+ pub fn contains_key(&self, id: hir::HirId) -> bool {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.contains_key(&id.local_id)
+ }
+
+ pub fn get(&self, id: hir::HirId) -> Option<&V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.get(&id.local_id)
+ }
+
+ pub fn iter(&self) -> hash_map::Iter<'_, hir::ItemLocalId, V> {
+ self.data.iter()
+ }
+}
+
+impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
+ type Output = V;
+
+ fn index(&self, key: hir::HirId) -> &V {
+ self.get(key).expect("LocalTableInContext: key not found")
+ }
+}
+
+pub struct LocalTableInContextMut<'a, V> {
+ hir_owner: OwnerId,
+ data: &'a mut ItemLocalMap<V>,
+}
+
+impl<'a, V> LocalTableInContextMut<'a, V> {
+ pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.get_mut(&id.local_id)
+ }
+
+ pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.entry(id.local_id)
+ }
+
+ pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.insert(id.local_id, val)
+ }
+
+ pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
+ validate_hir_id_for_typeck_results(self.hir_owner, id);
+ self.data.remove(&id.local_id)
+ }
+}
+
+rustc_index::newtype_index! {
+ pub struct UserTypeAnnotationIndex {
+ derive [HashStable]
+ DEBUG_FORMAT = "UserType({})",
+ const START_INDEX = 0,
+ }
+}
+
+/// Mapping of type annotation indices to canonical user type annotations.
+pub type CanonicalUserTypeAnnotations<'tcx> =
+ IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
+
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct CanonicalUserTypeAnnotation<'tcx> {
+ pub user_ty: Box<CanonicalUserType<'tcx>>,
+ pub span: Span,
+ pub inferred_ty: Ty<'tcx>,
+}
+
+/// Canonicalized user type annotation.
+pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
+
+impl<'tcx> CanonicalUserType<'tcx> {
+ /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
+ /// i.e., each thing is mapped to a canonical variable with the same index.
+ pub fn is_identity(&self) -> bool {
+ match self.value {
+ UserType::Ty(_) => false,
+ UserType::TypeOf(_, user_substs) => {
+ if user_substs.user_self_ty.is_some() {
+ return false;
+ }
+
+ iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| {
+ match kind.unpack() {
+ GenericArgKind::Type(ty) => match ty.kind() {
+ ty::Bound(debruijn, b) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(*debruijn, ty::INNERMOST);
+ cvar == b.var
+ }
+ _ => false,
+ },
+
+ GenericArgKind::Lifetime(r) => match *r {
+ ty::ReLateBound(debruijn, br) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(debruijn, ty::INNERMOST);
+ cvar == br.var
+ }
+ _ => false,
+ },
+
+ GenericArgKind::Const(ct) => match ct.kind() {
+ ty::ConstKind::Bound(debruijn, b) => {
+ // We only allow a `ty::INNERMOST` index in substitutions.
+ assert_eq!(debruijn, ty::INNERMOST);
+ cvar == b
+ }
+ _ => false,
+ },
+ }
+ })
+ }
+ }
+ }
+}
+
+/// A user-given type annotation attached to a constant. These arise
+/// from constants that are named via paths, like `Foo::<A>::new` and
+/// so forth.
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub enum UserType<'tcx> {
+ Ty(Ty<'tcx>),
+
+ /// The canonical type is the result of `type_of(def_id)` with the
+ /// given substitutions applied.
+ TypeOf(DefId, UserSubsts<'tcx>),
+}
use rustc_middle::{
mir::*,
thir::*,
- ty::{Ty, TyCtxt},
+ ty::{ParamEnv, Ty, TyCtxt},
};
use rustc_span::Span;
let mut pctxt = ParseCtxt {
tcx,
+ param_env: tcx.param_env(did),
thir,
source_scope: OUTERMOST_SOURCE_SCOPE,
body: &mut body,
struct ParseCtxt<'tcx, 'body> {
tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
thir: &'body Thir<'tcx>,
source_scope: SourceScope,
use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::{mir::*, thir::*, ty};
+use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
+
+use crate::build::custom::ParseError;
+use crate::build::expr::as_constant::as_constant_inner;
use super::{parse_by_kind, PResult, ParseCtxt};
@call("mir_retag_raw", args) => {
Ok(StatementKind::Retag(RetagKind::Raw, Box::new(self.parse_place(args[0])?)))
},
+ @call("mir_set_discriminant", args) => {
+ let place = self.parse_place(args[0])?;
+ let var = self.parse_integer_literal(args[1])? as u32;
+ Ok(StatementKind::SetDiscriminant {
+ place: Box::new(place),
+ variant_index: VariantIdx::from_u32(var),
+ })
+ },
ExprKind::Assign { lhs, rhs } => {
let lhs = self.parse_place(*lhs)?;
let rhs = self.parse_rvalue(*rhs)?;
}
pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
- parse_by_kind!(self, expr_id, _, "terminator",
+ parse_by_kind!(self, expr_id, expr, "terminator",
@call("mir_return", _args) => {
Ok(TerminatorKind::Return)
},
@call("mir_goto", args) => {
Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
},
+ ExprKind::Match { scrutinee, arms } => {
+ let discr = self.parse_operand(*scrutinee)?;
+ self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
+ },
)
}
+ fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
+ let Some((otherwise, rest)) = arms.split_last() else {
+ return Err(ParseError {
+ span,
+ item_description: format!("no arms"),
+ expected: "at least one arm".to_string(),
+ })
+ };
+
+ let otherwise = &self.thir[*otherwise];
+ let PatKind::Wild = otherwise.pattern.kind else {
+ return Err(ParseError {
+ span: otherwise.span,
+ item_description: format!("{:?}", otherwise.pattern.kind),
+ expected: "wildcard pattern".to_string(),
+ })
+ };
+ let otherwise = self.parse_block(otherwise.body)?;
+
+ let mut values = Vec::new();
+ let mut targets = Vec::new();
+ for arm in rest {
+ let arm = &self.thir[*arm];
+ let PatKind::Constant { value } = arm.pattern.kind else {
+ return Err(ParseError {
+ span: arm.pattern.span,
+ item_description: format!("{:?}", arm.pattern.kind),
+ expected: "constant pattern".to_string(),
+ })
+ };
+ values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
+ targets.push(self.parse_block(arm.body)?);
+ }
+
+ Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
+ }
+
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
parse_by_kind!(self, expr_id, _, "rvalue",
+ @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
ExprKind::Borrow { borrow_kind, arg } => Ok(
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
),
| ExprKind::ConstParam { .. }
| ExprKind::ConstBlock { .. } => {
Ok(Operand::Constant(Box::new(
- crate::build::expr::as_constant::as_constant_inner(expr, |_| None, self.tcx)
+ as_constant_inner(expr, |_| None, self.tcx)
)))
},
_ => self.parse_place(expr_id).map(Operand::Copy),
}
fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
- parse_by_kind!(self, expr_id, _, "place",
- ExprKind::Deref { arg } => Ok(
- self.parse_place(*arg)?.project_deeper(&[PlaceElem::Deref], self.tcx)
- ),
- _ => self.parse_local(expr_id).map(Place::from),
- )
+ self.parse_place_inner(expr_id).map(|(x, _)| x)
+ }
+
+ fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
+ let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
+ @call("mir_field", args) => {
+ let (parent, ty) = self.parse_place_inner(args[0])?;
+ let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
+ let field_ty = ty.field_ty(self.tcx, field);
+ let proj = PlaceElem::Field(field, field_ty);
+ let place = parent.project_deeper(&[proj], self.tcx);
+ return Ok((place, PlaceTy::from_ty(field_ty)));
+ },
+ @call("mir_variant", args) => {
+ (args[0], PlaceElem::Downcast(
+ None,
+ VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
+ ))
+ },
+ ExprKind::Deref { arg } => {
+ parse_by_kind!(self, *arg, _, "does not matter",
+ @call("mir_make_place", args) => return self.parse_place_inner(args[0]),
+ _ => (*arg, PlaceElem::Deref),
+ )
+ },
+ ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
+ ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
+ _ => {
+ let place = self.parse_local(expr_id).map(Place::from)?;
+ return Ok((place, PlaceTy::from_ty(expr.ty)))
+ },
+ );
+ let (parent, ty) = self.parse_place_inner(parent)?;
+ let place = parent.project_deeper(&[proj], self.tcx);
+ let ty = ty.projection_ty(self.tcx, proj);
+ Ok((place, ty))
}
fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
},
)
}
+
+ fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
+ parse_by_kind!(self, expr_id, expr, "constant",
+ ExprKind::Literal { .. }
+ | ExprKind::NamedConst { .. }
+ | ExprKind::NonHirLiteral { .. }
+ | ExprKind::ConstBlock { .. } => Ok({
+ let value = as_constant_inner(expr, |_| None, self.tcx);
+ value.literal.eval_bits(self.tcx, self.param_env, value.ty())
+ }),
+ )
+ }
}
use rustc_middle::hir::place::Projection as HirProjection;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
+use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::AssertKind::BoundsCheck;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_index::vec::Idx;
use std::assert_matches::assert_matches;
+use std::convert::From;
use std::iter;
-/// The "outermost" place that holds this value.
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub(crate) enum PlaceBase {
+/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
+/// place by pushing more and more projections onto the end, and then convert the final set into a
+/// place using the `into_place` method.
+///
+/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
+/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
+#[derive(Clone, Debug, PartialEq)]
+pub(in crate::build) enum PlaceBuilder<'tcx> {
/// Denotes the start of a `Place`.
- Local(Local),
+ ///
+ /// We use `PlaceElem` since this has all `Field` types available.
+ Local { local: Local, projection: Vec<PlaceElem<'tcx>> },
/// When building place for an expression within a closure, the place might start off a
/// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture
/// index (within the desugared closure) of the captured path until most of the projections
- /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the
+ /// are applied. We use `PlaceBuilder::Upvar` to keep track of the root variable off of which the
/// captured path starts, the closure the capture belongs to and the trait the closure
/// implements.
///
- /// Once we have figured out the capture index, we can convert the place builder to start from
- /// `PlaceBase::Local`.
+ /// Once we have figured out the capture index, we can convert the place builder to
+ /// `PlaceBuilder::Local`.
///
/// Consider the following example
/// ```rust
///
/// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to
/// figure out that it is captured until all the `Field` projections are applied.
- Upvar {
- /// HirId of the upvar
- var_hir_id: LocalVarId,
- /// DefId of the closure
- closure_def_id: LocalDefId,
- },
+ ///
+ /// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types
+ /// and will only do so once converting to `PlaceBuilder::Local`.
+ Upvar { upvar: Upvar, projection: Vec<UpvarProjectionElem<'tcx>> },
}
-/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
-/// place by pushing more and more projections onto the end, and then convert the final set into a
-/// place using the `to_place` method.
-///
-/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
-/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
-#[derive(Clone, Debug, PartialEq)]
-pub(in crate::build) struct PlaceBuilder<'tcx> {
- base: PlaceBase,
- projection: Vec<PlaceElem<'tcx>>,
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub(crate) struct Upvar {
+ var_hir_id: LocalVarId,
+ closure_def_id: LocalDefId,
}
/// Given a list of MIR projections, convert them to list of HIR ProjectionKind.
/// part of a path that is captured by a closure. We stop applying projections once we see the first
/// projection that isn't captured by a closure.
fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
- mir_projections: &[PlaceElem<'tcx>],
+ mir_projections: &[UpvarProjectionElem<'tcx>],
) -> Vec<HirProjectionKind> {
let mut hir_projections = Vec::new();
let mut variant = None;
fn find_capture_matching_projections<'a, 'tcx>(
upvars: &'a CaptureMap<'tcx>,
var_hir_id: LocalVarId,
- projections: &[PlaceElem<'tcx>],
+ projections: &[UpvarProjectionElem<'tcx>],
) -> Option<(usize, &'a Capture<'tcx>)> {
let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
cx: &Builder<'_, 'tcx>,
var_hir_id: LocalVarId,
closure_def_id: LocalDefId,
- projection: &[PlaceElem<'tcx>],
+ projection: &[UpvarProjectionElem<'tcx>],
) -> Option<PlaceBuilder<'tcx>> {
let Some((capture_index, capture)) =
find_capture_matching_projections(
var_hir_id, projection,
);
}
+
return None;
};
// Access the capture by accessing the field within the Closure struct.
let capture_info = &cx.upvars[capture_index];
- let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
+ let Place { local: upvar_resolved_local, projection: local_projection } =
+ capture_info.use_place;
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
- trace!(?capture.captured_place, ?projection);
- let remaining_projections = strip_prefix(
+ let upvar_projection = strip_prefix(
capture.captured_place.place.base_ty,
projection,
&capture.captured_place.place.projections,
);
- upvar_resolved_place_builder.projection.extend(remaining_projections);
+
+ let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
+ cx,
+ upvar_resolved_local,
+ local_projection.as_slice(),
+ upvar_projection,
+ );
+
+ assert!(matches!(upvar_resolved_place_builder, PlaceBuilder::Local { .. }));
Some(upvar_resolved_place_builder)
}
/// projection kinds are unsupported.
fn strip_prefix<'a, 'tcx>(
mut base_ty: Ty<'tcx>,
- projections: &'a [PlaceElem<'tcx>],
+ projections: &'a [UpvarProjectionElem<'tcx>],
prefix_projections: &[HirProjection<'tcx>],
-) -> impl Iterator<Item = PlaceElem<'tcx>> + 'a {
+) -> impl Iterator<Item = UpvarProjectionElem<'tcx>> + 'a {
let mut iter = projections
.iter()
.copied()
// Filter out opaque casts, they are unnecessary in the prefix.
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
for projection in prefix_projections {
+ debug!(?projection, ?projection.ty);
+
match projection.kind {
HirProjectionKind::Deref => {
assert_matches!(iter.next(), Some(ProjectionElem::Deref));
bug!("unexpected projection kind: {:?}", projection);
}
}
+
base_ty = projection.ty;
}
+
iter
}
pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option<Place<'tcx>> {
let resolved = self.resolve_upvar(cx);
let builder = resolved.as_ref().unwrap_or(self);
- let PlaceBase::Local(local) = builder.base else { return None };
- let projection = cx.tcx.intern_place_elems(&builder.projection);
- Some(Place { local, projection })
+ let PlaceBuilder::Local{local, ref projection} = builder else { return None };
+ let projection = cx.tcx.intern_place_elems(projection);
+ Some(Place { local: *local, projection })
}
/// Attempts to resolve the `PlaceBuilder`.
&self,
cx: &Builder<'_, 'tcx>,
) -> Option<PlaceBuilder<'tcx>> {
- let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else {
+ let PlaceBuilder::Upvar{ upvar: Upvar {var_hir_id, closure_def_id }, projection} = self else {
return None;
};
- to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection)
- }
- pub(crate) fn base(&self) -> PlaceBase {
- self.base
+ to_upvars_resolved_place_builder(cx, *var_hir_id, *closure_def_id, &projection)
}
- pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] {
- &self.projection
- }
+ #[instrument(skip(cx), level = "debug")]
+ pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self {
+ match self.clone() {
+ PlaceBuilder::Local { local, projection } => {
+ let base_place = PlaceBuilder::Local { local, projection };
+ let PlaceTy { ty, variant_index } =
+ base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
+ let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+
+ let field_ty = PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index);
- pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
- self.project(PlaceElem::Field(f, ty))
+ self.project(ProjectionElem::Field(f, field_ty))
+ }
+ PlaceBuilder::Upvar { upvar, mut projection } => {
+ projection.push(ProjectionElem::Field(f, ()));
+ PlaceBuilder::Upvar { upvar, projection }
+ }
+ }
}
pub(crate) fn deref(self) -> Self {
self.project(PlaceElem::Index(index))
}
- pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
- self.projection.push(elem);
- self
+ #[instrument(level = "debug")]
+ pub(crate) fn project(self, elem: PlaceElem<'tcx>) -> Self {
+ let result = match self {
+ PlaceBuilder::Local { local, mut projection } => {
+ projection.push(elem);
+ PlaceBuilder::Local { local, projection }
+ }
+ PlaceBuilder::Upvar { upvar, mut projection } => {
+ projection.push(elem.into());
+ PlaceBuilder::Upvar { upvar, projection }
+ }
+ };
+
+ debug!(?result);
+ result
}
/// Same as `.clone().project(..)` but more efficient
pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
- Self {
- base: self.base,
- projection: Vec::from_iter(self.projection.iter().copied().chain([elem])),
+ match self {
+ PlaceBuilder::Local { local, projection } => PlaceBuilder::Local {
+ local: *local,
+ projection: Vec::from_iter(projection.iter().copied().chain([elem.into()])),
+ },
+ PlaceBuilder::Upvar { upvar, projection } => PlaceBuilder::Upvar {
+ upvar: *upvar,
+ projection: Vec::from_iter(projection.iter().copied().chain([elem.into()])),
+ },
}
}
+
+ /// Similar to `Place::ty` but needed during mir building.
+ ///
+ /// Applies the projections in the `PlaceBuilder` to the base
+ /// type.
+ ///
+ /// Fallible as the root of this place may be an upvar for
+ /// which no base type can be determined.
+ #[instrument(skip(cx), level = "debug")]
+ fn compute_field_ty(
+ cx: &Builder<'_, 'tcx>,
+ field: Field,
+ base_ty: Ty<'tcx>,
+ variant_index: Option<VariantIdx>,
+ ) -> Ty<'tcx> {
+ let field_idx = field.as_usize();
+ let field_ty = match base_ty.kind() {
+ ty::Adt(adt_def, substs) if adt_def.is_enum() => {
+ let variant_idx = variant_index.unwrap();
+ adt_def.variant(variant_idx).fields[field_idx].ty(cx.tcx, substs)
+ }
+ ty::Adt(adt_def, substs) => adt_def
+ .all_fields()
+ .nth(field_idx)
+ .unwrap_or_else(|| {
+ bug!(
+ "expected to take field with idx {:?} of fields of {:?}",
+ field_idx,
+ adt_def
+ )
+ })
+ .ty(cx.tcx, substs),
+ ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| {
+ bug!("expected to take field with idx {:?} of {:?}", field_idx, elems)
+ }),
+ ty::Closure(_, substs) => {
+ let substs = substs.as_closure();
+ let Some(f_ty) = substs.upvar_tys().nth(field_idx) else {
+ bug!("expected to take field with idx {:?} of {:?}", field_idx, substs.upvar_tys().collect::<Vec<_>>());
+ };
+
+ f_ty
+ }
+ &ty::Generator(def_id, substs, _) => {
+ if let Some(var) = variant_index {
+ let gen_body = cx.tcx.optimized_mir(def_id);
+ let Some(layout) = gen_body.generator_layout() else {
+ bug!("No generator layout for {:?}", base_ty);
+ };
+
+ let Some(&local) = layout.variant_fields[var].get(field) else {
+ bug!("expected to take field {:?} of {:?}", field, layout.variant_fields[var]);
+ };
+
+ let Some(&f_ty) = layout.field_tys.get(local) else {
+ bug!("expected to get element for {:?} in {:?}", local, layout.field_tys);
+ };
+
+ f_ty
+ } else {
+ let Some(f_ty) = substs.as_generator().prefix_tys().nth(field.index()) else {
+ bug!(
+ "expected to take index {:?} in {:?}",
+ field.index(),
+ substs.as_generator().prefix_tys().collect::<Vec<_>>()
+ );
+ };
+
+ f_ty
+ }
+ }
+ _ => bug!("couldn't create field type, unexpected base type: {:?}", base_ty),
+ };
+
+ cx.tcx.normalize_erasing_regions(cx.param_env, field_ty)
+ }
+
+ /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::Upvar` whose upvars
+ /// are resolved. This function takes two kinds of projections: `local_projection`
+ /// contains the projections of the captured upvar and `upvar_projection` the
+ /// projections that are applied to the captured upvar. The main purpose of this
+ /// function is to figure out the `Ty`s of the field projections in `upvar_projection`.
+ #[instrument(skip(cx, local, upvar_projection))]
+ fn construct_local_place_builder(
+ cx: &Builder<'_, 'tcx>,
+ local: Local,
+ local_projection: &[PlaceElem<'tcx>],
+ upvar_projection: impl Iterator<Item = UpvarProjectionElem<'tcx>>,
+ ) -> Self {
+ // We maintain a `Ty` to which we apply a projection in each iteration over `upvar_projection`.
+ // This `ancestor_ty` let's us infer the field type whenever we encounter a
+ // `ProjectionElem::Field`.
+ let (mut ancestor_ty, mut opt_variant_idx) =
+ local_projections_to_ty(cx, local, local_projection);
+
+ // We add all projection elements we encounter to this `Vec`.
+ let mut local_projection = local_projection.to_vec();
+
+ for (i, proj) in upvar_projection.enumerate() {
+ debug!("i: {:?}, proj: {:?}, local_projection: {:?}", i, proj, local_projection);
+ match proj {
+ ProjectionElem::Field(field, _) => {
+ let field_ty =
+ PlaceBuilder::compute_field_ty(cx, field, ancestor_ty, opt_variant_idx);
+ debug!(?field_ty);
+
+ local_projection.push(ProjectionElem::Field(field, field_ty));
+ ancestor_ty = field_ty;
+ opt_variant_idx = None;
+ }
+ _ => {
+ let proj = upvar_proj_to_place_elem_no_field_proj(proj);
+ (ancestor_ty, opt_variant_idx) = project_ty(cx.tcx, ancestor_ty, proj);
+ local_projection.push(proj);
+ }
+ }
+ }
+
+ PlaceBuilder::Local { local, projection: local_projection }
+ }
}
impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
fn from(local: Local) -> Self {
- Self { base: PlaceBase::Local(local), projection: Vec::new() }
+ Self::Local { local, projection: Vec::new() }
}
}
-impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
- fn from(base: PlaceBase) -> Self {
- Self { base, projection: Vec::new() }
+impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
+ fn from(p: Place<'tcx>) -> Self {
+ Self::Local { local: p.local, projection: p.projection.to_vec() }
}
}
-impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
- fn from(p: Place<'tcx>) -> Self {
- Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() }
+fn project_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ elem: PlaceElem<'tcx>,
+) -> (Ty<'tcx>, Option<VariantIdx>) {
+ match elem {
+ ProjectionElem::Deref => {
+ let updated_ty = ty
+ .builtin_deref(true)
+ .unwrap_or_else(|| bug!("deref projection of non-dereferenceable ty {:?}", ty))
+ .ty;
+
+ (updated_ty, None)
+ }
+ ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
+ (ty.builtin_index().unwrap(), None)
+ }
+ ProjectionElem::Subslice { from, to, from_end } => {
+ let ty = match ty.kind() {
+ ty::Slice(..) => ty,
+ ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
+ ty::Array(inner, size) if from_end => {
+ let size = size.eval_usize(tcx, ty::ParamEnv::empty());
+ let len = size - (from as u64) - (to as u64);
+ tcx.mk_array(*inner, len)
+ }
+ _ => bug!("cannot subslice non-array type: `{:?}`", ty),
+ };
+
+ (ty, None)
+ }
+ ProjectionElem::Downcast(_, variant_idx) => (ty, Some(variant_idx)),
+ ProjectionElem::Field(_, ty) => (ty, None),
+ ProjectionElem::OpaqueCast(..) => bug!("didn't expect OpaqueCast"),
+ }
+}
+
+fn local_projections_to_ty<'a, 'tcx>(
+ cx: &'a Builder<'a, 'tcx>,
+ local: Local,
+ projection: &'a [PlaceElem<'tcx>],
+) -> (Ty<'tcx>, Option<VariantIdx>) {
+ let local_ty = cx.local_decls.local_decls()[local].ty;
+ projection.iter().fold((local_ty, None), |ty_variant_idx, elem| {
+ let ty = ty_variant_idx.0;
+ project_ty(cx.tcx, ty, *elem)
+ })
+}
+
+// Converts an `UpvarProjectionElem` to `PlaceElem`, ICE'ing when being passed a
+// field projection.
+fn upvar_proj_to_place_elem_no_field_proj<'tcx>(
+ upvar_proj: UpvarProjectionElem<'tcx>,
+) -> PlaceElem<'tcx> {
+ match upvar_proj {
+ ProjectionElem::Deref => ProjectionElem::Deref,
+ ProjectionElem::Index(i) => ProjectionElem::Index(i),
+ ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+ ProjectionElem::ConstantIndex { offset, min_length, from_end }
+ }
+ ProjectionElem::Subslice { from, to, from_end } => {
+ ProjectionElem::Subslice { from, to, from_end }
+ }
+ ProjectionElem::Downcast(ty, variant_idx) => ProjectionElem::Downcast(ty, variant_idx),
+ ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
+ ProjectionElem::Field(..) => bug!("should not be called with `ProjectionElem::Field`"),
}
}
self.expr_as_place(block, expr, Mutability::Not, None)
}
+ #[instrument(skip(self, fake_borrow_temps), level = "debug")]
fn expr_as_place(
&mut self,
mut block: BasicBlock,
mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>,
) -> BlockAnd<PlaceBuilder<'tcx>> {
- debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
-
let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
let lhs = &this.thir[lhs];
let mut place_builder =
unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+ debug!(?place_builder);
if let ty::Adt(adt_def, _) = lhs.ty.kind() {
if adt_def.is_enum() {
place_builder = place_builder.downcast(*adt_def, variant_index);
}
}
- block.and(place_builder.field(name, expr.ty))
+ block.and(place_builder.field(this, name))
}
ExprKind::Deref { arg } => {
let place_builder = unpack!(
}
/// Lower a captured upvar. Note we might not know the actual capture index,
- /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved
+ /// so we create a place starting from `Upvar`, which will be resolved
/// once all projections that allow us to identify a capture have been applied.
fn lower_captured_upvar(
&mut self,
closure_def_id: LocalDefId,
var_hir_id: LocalVarId,
) -> BlockAnd<PlaceBuilder<'tcx>> {
- block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id }))
+ block.and(PlaceBuilder::Upvar {
+ upvar: Upvar { var_hir_id, closure_def_id },
+ projection: vec![],
+ })
}
/// Lower an index expression
source_info: SourceInfo,
) {
let tcx = self.tcx;
-
let place_ty = base_place.ty(&self.local_decls, tcx);
+
if let ty::Slice(_) = place_ty.ty.kind() {
// We need to create fake borrows to ensure that the bounds
// check that we just did stays valid. Since we can't assign to
use rustc_middle::ty::util::IntTypeExt;
use rustc_target::abi::{Abi, Primitive};
-use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary, PlaceBuilder};
use rustc_hir::lang_items::LangItem;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
- let mutability = match arg_place_builder.base() {
+ let mutability = match arg_place_builder {
// We are capturing a path that starts off a local variable in the parent.
// The mutability of the current capture is same as the mutability
// of the local declaration in the parent.
- PlaceBase::Local(local) => this.local_decls[local].mutability,
+ PlaceBuilder::Local { local, .. } => this.local_decls[local].mutability,
// Parent is a closure and we are capturing a path that is captured
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
- PlaceBase::Upvar { .. } => {
+ PlaceBuilder::Upvar { .. } => {
let enclosing_upvars_resolved = arg_place_builder.to_place(this);
match enclosing_upvars_resolved.as_ref() {
// base-supplied field, generate an operand that
// reads it from the base.
iter::zip(field_names, &**field_types)
- .map(|(n, ty)| match fields_map.get(&n) {
+ .map(|(n, _ty)| match fields_map.get(&n) {
Some(v) => v.clone(),
None => {
- let place = place_builder.clone_project(PlaceElem::Field(n, *ty));
- this.consume_by_copy_or_move(place.to_place(this))
+ let place_builder = place_builder.clone();
+ this.consume_by_copy_or_move(
+ place_builder.field(this, n).to_place(this),
+ )
}
})
.collect()
|| !adt_def.is_variant_list_non_exhaustive());
if irrefutable {
let place_builder = match_pair.place.downcast(adt_def, variant_index);
- candidate
- .match_pairs
- .extend(self.field_match_pairs(place_builder, subpatterns));
+ let field_match_pairs =
+ self.field_match_pairs(place_builder.clone(), subpatterns);
+ candidate.match_pairs.extend(field_match_pairs);
Ok(())
} else {
Err(match_pair)
let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
- let place = downcast_place
- .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
+ let place = downcast_place.clone().field(self, subpattern.field);
// e.g., `(x as Variant).0 @ P1`
MatchPair::new(place, &subpattern.pattern, self)
});
-use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
subpatterns
.iter()
.map(|fieldpat| {
- let place =
- place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
+ let place = place.clone().field(self, fieldpat.field);
+
MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
- let may_need_cast = match place.base() {
- PlaceBase::Local(local) => {
- let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
+ let may_need_cast = match place {
+ PlaceBuilder::Local { local, ref projection } => {
+ let ty = Place::ty_from(local, projection, &cx.local_decls, cx.tcx).ty;
ty != pattern.ty && ty.has_opaque_types()
}
_ => true,
pub struct AbstractOperand;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct AbstractType;
-pub type AbstractElem = ProjectionElem<AbstractOperand, AbstractType>;
+pub type AbstractElem = ProjectionElem<AbstractOperand, AbstractType, AbstractType>;
pub trait Lift {
type Abstract;
Field(Field),
}
-impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
+impl<V, T1, T2> TryFrom<ProjectionElem<V, T1, T2>> for TrackElem {
type Error = ();
- fn try_from(value: ProjectionElem<V, T>) -> Result<Self, Self::Error> {
+ fn try_from(value: ProjectionElem<V, T1, T2>) -> Result<Self, Self::Error> {
match value {
ProjectionElem::Field(field, _) => Ok(TrackElem::Field(field)),
_ => Err(()),
// `mir_built` force this.
let body = &tcx.mir_built(def).borrow();
- if body.should_skip() {
+ if body.is_custom_mir() {
return tcx.arena.alloc(UnsafetyCheckResult {
violations: Vec::new(),
used_unsafe_blocks: FxHashSet::default(),
use either::Right;
use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
use rustc_trait_selection::traits;
type MemoryKind = !;
#[inline(always)]
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
// We do not check for alignment to avoid having to carry an `Align`
// in `ConstValue::ByRef`.
- false
+ CheckAlignment::No
}
#[inline(always)]
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // for now, we don't enforce validity
}
+ fn alignment_check_failed(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ span_bug!(
+ ecx.cur_span(),
+ "`alignment_check_failed` called when no alignment check requested"
+ )
+ }
fn load_mir(
_ecx: &InterpCx<'mir, 'tcx, Self>,
//!
//! Currently, this pass only propagates scalar values.
+use rustc_const_eval::const_eval::CheckAlignment;
use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::visit::{MutVisitor, Visitor};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
use rustc_span::DUMMY_SP;
+use rustc_target::abi::Align;
use crate::MirPass;
type MemoryKind = !;
const PANIC_ON_ALLOC_FAIL: bool = true;
- fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+ fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
unimplemented!()
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
unimplemented!()
}
+ fn alignment_check_failed(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ _has: Align,
+ _required: Align,
+ _check: CheckAlignment,
+ ) -> interpret::InterpResult<'tcx, ()> {
+ unimplemented!()
+ }
fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
pub span: Option<Span>,
pub symbol: String,
}
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_couldnt_dump_mono_stats)]
+pub struct CouldntDumpMonoStats {
+ pub error: String,
+}
mod default;
mod merging;
+use std::cmp;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write};
+use std::path::{Path, PathBuf};
+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync;
use rustc_hir::def_id::DefIdSet;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
+use rustc_session::config::SwitchWithOptPath;
use rustc_span::symbol::Symbol;
use crate::collector::InliningMap;
use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
pub struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
})
.collect();
+ // Output monomorphization stats per def_id
+ if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
+ if let Err(err) =
+ dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+ {
+ tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+ }
+ }
+
if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default();
(tcx.arena.alloc(mono_items), codegen_units)
}
+/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
+/// def, to a file in the given output directory.
+fn dump_mono_items_stats<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ codegen_units: &[CodegenUnit<'tcx>],
+ output_directory: &Option<PathBuf>,
+ crate_name: Option<&str>,
+) -> Result<(), Box<dyn std::error::Error>> {
+ let output_directory = if let Some(ref directory) = output_directory {
+ fs::create_dir_all(directory)?;
+ directory
+ } else {
+ Path::new(".")
+ };
+
+ let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+ let output_path = output_directory.join(&filename);
+ let file = File::create(output_path)?;
+ let mut file = BufWriter::new(file);
+
+ // Gather instantiated mono items grouped by def_id
+ let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default();
+ for cgu in codegen_units {
+ for (&mono_item, _) in cgu.items() {
+ // Avoid variable-sized compiler-generated shims
+ if mono_item.is_user_defined() {
+ items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item);
+ }
+ }
+ }
+
+ // Output stats sorted by total instantiated size, from heaviest to lightest
+ let mut stats: Vec<_> = items_per_def_id
+ .into_iter()
+ .map(|(def_id, items)| {
+ let instantiation_count = items.len();
+ let size_estimate = items[0].size_estimate(tcx);
+ let total_estimate = instantiation_count * size_estimate;
+ (def_id, instantiation_count, size_estimate, total_estimate)
+ })
+ .collect();
+ stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+
+ if !stats.is_empty() {
+ writeln!(
+ file,
+ "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+ )?;
+ writeln!(file, "| --- | ---: | ---: | ---: |")?;
+ for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
+ let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+ writeln!(
+ file,
+ "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
+ )?;
+ }
+ }
+
+ Ok(())
+}
+
fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet {
let (items, cgus) = tcx.collect_and_partition_mono_items(());
let mut visited = DefIdSet::default();
computed `block` spans (one span encompassing a block's terminator and \
all statements). If `-Z instrument-coverage` is also enabled, create \
an additional `.html` file showing the computed coverage spans."),
+ dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+ parse_switch_with_opt_path, [UNTRACKED],
+ "output statistics about monomorphization collection (format: markdown)"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
FileNameDisplayPreference::Remapped => {
self.remapped_path_if_available().to_string_lossy()
}
+ FileNameDisplayPreference::Short => self
+ .local_path_if_available()
+ .file_name()
+ .map_or_else(|| "".into(), |f| f.to_string_lossy()),
}
}
}
/// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
/// This is appropriate for use in user-facing output (such as diagnostics).
Local,
+ /// Display only the filename, as a way to reduce the verbosity of the output.
+ /// This is appropriate for use in user-facing output (such as diagnostics).
+ Short,
}
pub struct FileNameDisplay<'a> {
}
}
- fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
+ pub fn span_to_string(
+ &self,
+ sp: Span,
+ filename_display_pref: FileNameDisplayPreference,
+ ) -> String {
if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
return "no-location".to_string();
}
let lo = self.lookup_char_pos(sp.lo());
let hi = self.lookup_char_pos(sp.hi());
format!(
- "{}:{}:{}: {}:{}",
+ "{}:{}:{}{}",
lo.file.name.display(filename_display_pref),
lo.line,
lo.col.to_usize() + 1,
- hi.line,
- hi.col.to_usize() + 1,
+ if let FileNameDisplayPreference::Short = filename_display_pref {
+ String::new()
+ } else {
+ format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+ }
)
}
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
- if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
- Some(format!(
- "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
- fn_kind = self_ty.prefix_string(self.tcx)
- ))
- } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
- Some(format!(
- "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
- ))
- } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
- Some(format!(
- "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
- ))
- } else {
- None
+ with_forced_trimmed_paths! {
+ if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
+ Some(format!(
+ "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it \
+ returns `{normalized_ty}`",
+ fn_kind = self_ty.prefix_string(self.tcx)
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
+ resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
+ yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
}
}
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if trait_impls.blanket_impls().is_empty()
- && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next()
- && let Some(impl_def_id) = impl_ty.def() {
- let message = if trait_impls.non_blanket_impls().len() == 1 {
+ && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
+ {
+ let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
+ let message = if non_blanket_impl_count == 1 {
"use the fully-qualified path to the only available implementation".to_string()
} else {
format!(
"use a fully-qualified path to a specific available implementation ({} found)",
- trait_impls.non_blanket_impls().len()
+ non_blanket_impl_count
)
};
let mut suggestions = vec![(
- trait_path_segment.ident.span.shrink_to_lo(),
+ path.span.shrink_to_lo(),
format!("<{} as ", self.tcx.type_of(impl_def_id))
)];
if let Some(generic_arg) = trait_path_segment.args {
param_env: ty::ParamEnv<'tcx>,
err: &mut Diagnostic,
);
+ fn probe_assoc_types_at_expr(
+ &self,
+ type_diffs: &[TypeError<'tcx>],
+ span: Span,
+ prev_ty: Ty<'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
}
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
if only_never_return {
// No return paths, probably using `panic!()` or similar.
- // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
+ // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
suggest_trait_object_return_type_alternatives(
err,
ret_ty.span,
&& self.tcx.is_fn_trait(trait_pred.def_id())
{
let expected_self =
- self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
+ self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty()));
let expected_substs = self
.tcx
- .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
+ .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.substs));
// Find another predicate whose self-type is equal to the expected self type,
// but whose substs don't match.
// Make sure that the self type matches
// (i.e. constraining this closure)
&& expected_self
- == self.tcx.anonymize_late_bound_regions(
+ == self.tcx.anonymize_bound_vars(
pred.kind().rebind(trait_pred.self_ty()),
)
// But the substs don't match (i.e. incompatible args)
&& expected_substs
- != self.tcx.anonymize_late_bound_regions(
+ != self.tcx.anonymize_bound_vars(
pred.kind().rebind(trait_pred.trait_ref.substs),
) =>
{
}
ObligationCauseCode::SizedArgumentType(sp) => {
if let Some(span) = sp {
+ if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+ && let ty::Clause::Trait(trait_pred) = clause
+ && let ty::Dynamic(..) = trait_pred.self_ty().kind()
+ {
+ let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ && snippet.starts_with("dyn ")
+ {
+ let pos = snippet.len() - snippet[3..].trim_start().len();
+ span.with_hi(span.lo() + BytePos(pos as u32))
+ } else {
+ span.shrink_to_lo()
+ };
+ err.span_suggestion_verbose(
+ span,
+ "you can use `impl Trait` as the argument type",
+ "impl ".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
err.span_suggestion_verbose(
span.shrink_to_lo(),
"function arguments must have a statically known size, borrowed types \
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
&& let Some(pred) = predicates.predicates.get(*idx)
- && let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
- _ => Err(()),
- })
{
- let mut c = CollectAllMismatches {
- infcx: self.infcx,
- param_env,
- errors: vec![],
- };
- if let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+ if let Ok(trait_pred) = pred.kind().try_map_bound(|pred| match pred {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
_ => Err(()),
- }) {
+ })
+ && let Ok(trait_predicate) = predicate.kind().try_map_bound(|pred| match pred {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => Ok(trait_pred),
+ _ => Err(()),
+ })
+ {
+ let mut c = CollectAllMismatches {
+ infcx: self.infcx,
+ param_env,
+ errors: vec![],
+ };
if let Ok(_) = c.relate(trait_pred, trait_predicate) {
type_diffs = c.errors;
}
+ } else if let ty::PredicateKind::Clause(
+ ty::Clause::Projection(proj)
+ ) = pred.kind().skip_binder()
+ && let ty::PredicateKind::Clause(
+ ty::Clause::Projection(projection)
+ ) = predicate.kind().skip_binder()
+ {
+ type_diffs = vec![
+ Sorts(ty::error::ExpectedFound {
+ expected: self.tcx.mk_ty(ty::Alias(ty::Projection, proj.projection_ty)),
+ found: projection.term.ty().unwrap(),
+ }),
+ ];
}
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
let tcx = self.tcx;
+ let mut print_root_expr = true;
let mut assocs = vec![];
- // We still want to point at the different methods even if there hasn't
- // been a change of assoc type.
- let mut call_spans = vec![];
let mut expr = expr;
let mut prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
// ^^^^^^ ^^^^^^^^^^^
expr = rcvr_expr;
- let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
- call_spans.push(span);
-
- let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
- for diff in &type_diffs {
- let Sorts(expected_found) = diff else { continue; };
- let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
-
- let origin =
- TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
- let trait_def_id = proj.trait_def_id(self.tcx);
- // Make `Self` be equivalent to the type of the call chain
- // expression we're looking at now, so that we can tell what
- // for example `Iterator::Item` is at this point in the chain.
- let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
- match param.kind {
- ty::GenericParamDefKind::Type { .. } => {
- if param.index == 0 {
- return prev_ty.into();
- }
- }
- ty::GenericParamDefKind::Lifetime
- | ty::GenericParamDefKind::Const { .. } => {}
- }
- self.var_for_def(span, param)
- });
- // This will hold the resolved type of the associated type, if the
- // current expression implements the trait that associated type is
- // in. For example, this would be what `Iterator::Item` is here.
- let ty_var = self.infcx.next_ty_var(origin);
- // This corresponds to `<ExprTy as Iterator>::Item = _`.
- let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
- ty::Clause::Projection(ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(proj.def_id, substs),
- term: ty_var.into(),
- }),
- ));
- // Add `<ExprTy as Iterator>::Item = _` obligation.
- ocx.register_obligation(Obligation::misc(
- self.tcx,
- span,
- expr.hir_id,
- param_env,
- projection,
- ));
- if ocx.select_where_possible().is_empty() {
- // `ty_var` now holds the type that `Item` is for `ExprTy`.
- let ty_var = self.resolve_vars_if_possible(ty_var);
- assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
- } else {
- // `<ExprTy as Iterator>` didn't select, so likely we've
- // reached the end of the iterator chain, like the originating
- // `Vec<_>`.
- // Keep the space consistent for later zipping.
- assocs_in_this_method.push(None);
- }
- }
+ let assocs_in_this_method =
+ self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
assocs.push(assocs_in_this_method);
prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id)
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
- && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
- && let Some(binding_expr) = local.init
+ && let Some(parent) = self.tcx.hir().find(parent_hir_id)
{
- // We've reached the root of the method call chain and it is a
- // binding. Get the binding creation and try to continue the chain.
- expr = binding_expr;
+ // We've reached the root of the method call chain...
+ if let hir::Node::Local(local) = parent
+ && let Some(binding_expr) = local.init
+ {
+ // ...and it is a binding. Get the binding creation and continue the chain.
+ expr = binding_expr;
+ }
+ if let hir::Node::Param(param) = parent {
+ // ...and it is a an fn argument.
+ let prev_ty = self.resolve_vars_if_possible(
+ typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()),
+ );
+ let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
+ if assocs_in_this_method.iter().any(|a| a.is_some()) {
+ assocs.push(assocs_in_this_method);
+ print_root_expr = false;
+ }
+ break;
+ }
}
}
// We want the type before deref coercions, otherwise we talk about `&[_]`
// instead of `Vec<_>`.
- if let Some(ty) = typeck_results.expr_ty_opt(expr) {
+ if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr {
let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
// Point at the root expression
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
let Some(prev_assoc_in_method) = assocs.peek() else {
for entry in assocs_in_method {
let Some((span, (assoc, ty))) = entry else { continue; };
- if type_diffs.iter().any(|diff| {
+ if primary_spans.is_empty() || type_diffs.iter().any(|diff| {
let Sorts(expected_found) = diff else { return false; };
self.can_eq(param_env, expected_found.found, ty).is_ok()
}) {
let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
- if ty != *prev_ty {
+ if self.can_eq(param_env, ty, *prev_ty).is_err() {
if type_diffs.iter().any(|diff| {
let Sorts(expected_found) = diff else { return false; };
self.can_eq(param_env, expected_found.found, ty).is_ok()
}
}
}
- for span in call_spans {
- if span_labels.iter().find(|(s, _)| *s == span).is_none() {
- // Ensure we are showing the entire chain, even if the assoc types
- // haven't changed.
- span_labels.push((span, String::new()));
- }
- }
if !primary_spans.is_empty() {
let mut multi_span: MultiSpan = primary_spans.into();
for (span, label) in span_labels {
}
err.span_note(
multi_span,
- format!(
- "the method call chain might not have had the expected \
- associated types",
- ),
+ format!("the method call chain might not have had the expected associated types"),
);
}
}
+
+ fn probe_assoc_types_at_expr(
+ &self,
+ type_diffs: &[TypeError<'tcx>],
+ span: Span,
+ prev_ty: Ty<'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>> {
+ let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
+ let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len());
+ for diff in type_diffs {
+ let Sorts(expected_found) = diff else { continue; };
+ let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { continue; };
+
+ let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
+ let trait_def_id = proj.trait_def_id(self.tcx);
+ // Make `Self` be equivalent to the type of the call chain
+ // expression we're looking at now, so that we can tell what
+ // for example `Iterator::Item` is at this point in the chain.
+ let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+ match param.kind {
+ ty::GenericParamDefKind::Type { .. } => {
+ if param.index == 0 {
+ return prev_ty.into();
+ }
+ }
+ ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
+ }
+ self.var_for_def(span, param)
+ });
+ // This will hold the resolved type of the associated type, if the
+ // current expression implements the trait that associated type is
+ // in. For example, this would be what `Iterator::Item` is here.
+ let ty_var = self.infcx.next_ty_var(origin);
+ // This corresponds to `<ExprTy as Iterator>::Item = _`.
+ let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+ ty::ProjectionPredicate {
+ projection_ty: self.tcx.mk_alias_ty(proj.def_id, substs),
+ term: ty_var.into(),
+ },
+ )));
+ // Add `<ExprTy as Iterator>::Item = _` obligation.
+ ocx.register_obligation(Obligation::misc(
+ self.tcx, span, body_id, param_env, projection,
+ ));
+ if ocx.select_where_possible().is_empty() {
+ // `ty_var` now holds the type that `Item` is for `ExprTy`.
+ let ty_var = self.resolve_vars_if_possible(ty_var);
+ assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
+ } else {
+ // `<ExprTy as Iterator>` didn't select, so likely we've
+ // reached the end of the iterator chain, like the originating
+ // `Vec<_>`.
+ // Keep the space consistent for later zipping.
+ assocs_in_this_method.push(None);
+ }
+ }
+ assocs_in_this_method
+ }
}
/// Add a hint to add a missing borrow or remove an unnecessary one.
trait_obj: &str,
is_object_safe: bool,
) {
- err.span_suggestion(
- ret_ty,
- "use some type `T` that is `T: Sized` as the return type if all return paths have the \
- same type",
- "T",
- Applicability::MaybeIncorrect,
- );
err.span_suggestion(
ret_ty,
&format!(
GenericArgKind::Const(ct) => {
match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
- let obligations = self.nominal_obligations(uv.def.did, uv.substs);
- self.out.extend(obligations);
-
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
- let cause = self.cause(traits::WellFormed(None));
- self.out.push(traits::Obligation::with_depth(
- self.tcx(),
- cause,
- self.recursion_depth,
- self.param_env,
- predicate,
- ));
+ if !ct.has_escaping_bound_vars() {
+ let obligations = self.nominal_obligations(uv.def.did, uv.substs);
+ self.out.extend(obligations);
+
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
+ let cause = self.cause(traits::WellFormed(None));
+ self.out.push(traits::Obligation::with_depth(
+ self.tcx(),
+ cause,
+ self.recursion_depth,
+ self.param_env,
+ predicate,
+ ));
+ }
}
ty::ConstKind::Infer(_) => {
let cause = self.cause(traits::WellFormed(None));
/// The deque is assumed to be partitioned according to the given predicate.
/// This means that all elements for which the predicate returns true are at the start of the deque
/// and all elements for which the predicate returns false are at the end.
- /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+ /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0`
/// (all odd numbers are at the start, all even at the end).
///
/// If the deque is not partitioned, the returned result is unspecified and meaningless,
/// if any element creation was unsuccessful.
///
/// The return type of this function depends on the return type of the closure.
-/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
///
/// # Arguments
/// return an array the same size as `self` or the first error encountered.
///
/// The return type of this function depends on the return type of the closure.
- /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+ /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
///
/// # Examples
//! #[custom_mir(dialect = "built")]
//! pub fn simple(x: i32) -> i32 {
//! mir!(
-//! let temp1: i32;
-//! let temp2: _;
+//! let temp2: i32;
//!
//! {
-//! temp1 = x;
-//! Goto(exit)
+//! let temp1 = x;
+//! Goto(my_second_block)
//! }
//!
-//! exit = {
+//! my_second_block = {
//! temp2 = Move(temp1);
//! RET = temp2;
//! Return()
//! }
//! ```
//!
-//! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
+//! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
+//! attribute only works on functions - there is no way to insert custom MIR into the middle of
+//! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
+//! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
+//! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
+//! "runtime", phase = "optimized")] if you don't.
//!
-//! - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
-//! attribute only works on functions - there is no way to insert custom MIR into the middle of
-//! another function.
-//! - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
-//! This will normally be the phase that corresponds to the thing you are trying to test. The
-//! phase can be omitted for dialects that have just one.
-//! - You should define your function signature like you normally would. Externally, this function
-//! can be called like any other function.
-//! - Type inference works - you don't have to spell out the type of all of your locals.
+//! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
//!
-//! For now, all statements and terminators are parsed from nested invocations of the special
-//! functions provided in this module. We additionally want to (but do not yet) support more
-//! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
-//! supported yet.
+//! The input to the [`mir!`] macro is:
+//!
+//! - A possibly empty list of local declarations. Locals can also be declared inline on
+//! assignments via `let`. Type inference generally works. Shadowing does not.
+//! - A list of basic blocks. The first of these is the start block and is where execution begins.
+//! All blocks other than the start block need to be given a name, so that they can be referred
+//! to later.
+//! - Each block is a list of semicolon terminated statements, followed by a terminator. The
+//! syntax for the various statements and terminators is designed to be as similar as possible
+//! to the syntax for analogous concepts in native Rust. See below for a list.
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
+//! mir!(
+//! {
+//! match c {
+//! true => t,
+//! _ => f,
+//! }
+//! }
+//!
+//! t = {
+//! let temp = a;
+//! Goto(load_and_exit)
+//! }
+//!
+//! f = {
+//! temp = b;
+//! Goto(load_and_exit)
+//! }
+//!
+//! load_and_exit = {
+//! RET = *temp;
+//! Return()
+//! }
+//! )
+//! }
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
+//! mir!({
+//! RET = Move(Field(Variant(opt, 1), 0));
+//! Return()
+//! })
+//! }
+//! ```
+//!
+//! We can also set off compilation failures that happen in sufficiently late stages of the
+//! compiler:
+//!
+//! ```rust,compile_fail
+//! #![feature(core_intrinsics, custom_mir)]
+//!
+//! extern crate core;
+//! use core::intrinsics::mir::*;
+//!
+//! #[custom_mir(dialect = "built")]
+//! fn borrow_error(should_init: bool) -> i32 {
+//! mir!(
+//! let temp: i32;
+//!
+//! {
+//! match should_init {
+//! true => init,
+//! _ => use_temp,
+//! }
+//! }
+//!
+//! init = {
+//! temp = 0;
+//! Goto(use_temp)
+//! }
+//!
+//! use_temp = {
+//! RET = temp;
+//! Return()
+//! }
+//! )
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0381]: used binding is possibly-uninitialized
+//! --> test.rs:24:13
+//! |
+//! 8 | / mir!(
+//! 9 | | let temp: i32;
+//! 10 | |
+//! 11 | | {
+//! ... |
+//! 19 | | temp = 0;
+//! | | -------- binding initialized here in some conditions
+//! ... |
+//! 24 | | RET = temp;
+//! | | ^^^^^^^^^^ value used here but it is possibly-uninitialized
+//! 25 | | Return()
+//! 26 | | }
+//! 27 | | )
+//! | |_____- binding declared here but left uninitialized
+//!
+//! error: aborting due to previous error
+//!
+//! For more information about this error, try `rustc --explain E0381`.
+//! ```
+//!
+//! # Syntax
+//!
+//! The lists below are an exhaustive description of how various MIR constructs can be created.
+//! Anything missing from the list should be assumed to not be supported, PRs welcome.
+//!
+//! #### Locals
+//!
+//! - The `_0` return local can always be accessed via `RET`.
+//! - Arguments can be accessed via their regular name.
+//! - All other locals need to be declared with `let` somewhere and then can be accessed by name.
+//!
+//! #### Places
+//! - Locals implicit convert to places.
+//! - Field accesses, derefs, and indexing work normally.
+//! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
+//! see their documentation for details.
+//!
+//! #### Operands
+//! - Places implicitly convert to `Copy` operands.
+//! - `Move` operands can be created via [`Move`].
+//! - Const blocks, literals, named constants, and const params all just work.
+//! - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
+//! constants in MIR and the only way to access statics.
+//!
+//! #### Statements
+//! - Assign statements work via normal Rust assignment.
+//! - [`Retag`] statements have an associated function.
+//!
+//! #### Rvalues
+//!
+//! - Operands implicitly convert to `Use` rvalues.
+//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
+//! - [`Discriminant`] has an associated function.
+//!
+//! #### Terminators
+//!
+//! - [`Goto`] and [`Return`] have associated functions.
+//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
+//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
+//! otherwise branch.
//!
#![unstable(
pub struct BasicBlock;
macro_rules! define {
- ($name:literal, $($sig:tt)*) => {
+ ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
#[rustc_diagnostic_item = $name]
- pub $($sig)* { panic!() }
+ $( #[ $meta ] )*
+ pub fn $($sig)* { panic!() }
}
}
define!("mir_move", fn Move<T>(place: T) -> T);
define!("mir_static", fn Static<T>(s: T) -> &'static T);
define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
+define!(
+ "mir_discriminant",
+ /// Gets the discriminant of a place.
+ fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
+);
+define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
+define!(
+ "mir_field",
+ /// Access the field with the given index of some place.
+ ///
+ /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
+ /// access the field of does not have variants, you can use normal field projection syntax.
+ ///
+ /// There is no proper way to do a place projection to a variant in Rust, and so these two
+ /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
+ /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
+ /// caveats:
+ ///
+ /// - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
+ /// still be generated.
+ /// - In some situations, the return type of `Field` cannot be inferred. You may need to
+ /// annotate it on the function in these cases.
+ /// - Since `Field` is a function call which is not a place expression, using this on the left
+ /// hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
+ /// work around that issue. Wrap the left hand side of an assignment in the macro to convince
+ /// the compiler that it's ok.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(custom_mir, core_intrinsics)]
+ ///
+ /// extern crate core;
+ /// use core::intrinsics::mir::*;
+ ///
+ /// #[custom_mir(dialect = "built")]
+ /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
+ /// mir!({
+ /// RET = *Field::<&i32>(Variant(opt, 1), 0);
+ /// Return()
+ /// })
+ /// }
+ ///
+ /// #[custom_mir(dialect = "built")]
+ /// fn set(opt: &mut Option<i32>) {
+ /// mir!({
+ /// place!(Field(Variant(*opt, 1), 0)) = 5;
+ /// Return()
+ /// })
+ /// }
+ /// ```
+ fn Field<F>(place: (), field: u32) -> F
+);
+define!(
+ "mir_variant",
+ /// Adds a variant projection with the given index to the place.
+ ///
+ /// See [`Field`] for documentation.
+ fn Variant<T>(place: T, index: u32) -> ()
+);
+define!(
+ "mir_make_place",
+ #[doc(hidden)]
+ fn __internal_make_place<T>(place: T) -> *mut T
+);
-/// Convenience macro for generating custom MIR.
+/// Macro for generating custom MIR.
///
/// See the module documentation for syntax details. This macro is not magic - it only transforms
/// your MIR into something that is easier to parse in the compiler.
}}
}
+/// Helper macro that allows you to treat a value expression like a place expression.
+///
+/// See the documentation on [`Variant`] for why this is necessary and how to use it.
+pub macro place($e:expr) {
+ (*::core::intrinsics::mir::__internal_make_place($e))
+}
+
/// Helper macro that extracts the `let` declarations out of a bunch of statements.
///
/// This macro is written using the "statement muncher" strategy. Each invocation parses the first
/// the first true result or the first error.
///
/// The return type of this method depends on the return type of the closure.
- /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>; E>`.
+ /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>, E>`.
/// If you return `Option<bool>` from the closure, you'll get an `Option<Option<Self::Item>>`.
///
/// # Examples
/// The slice is assumed to be partitioned according to the given predicate.
/// This means that all elements for which the predicate returns true are at the start of the slice
/// and all elements for which the predicate returns false are at the end.
- /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+ /// For example, `[7, 15, 3, 5, 4, 12, 6]` is partitioned under the predicate `x % 2 != 0`
/// (all odd numbers are at the start, all even at the end).
///
/// If this slice is not partitioned, the returned result is unspecified and meaningless,
}
}
+#[stable(feature = "path_buf_deref_mut", since = "CURRENT_RUSTC_VERSION")]
+impl ops::DerefMut for PathBuf {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Path {
+ Path::from_inner_mut(&mut self.inner)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Borrow<Path> for PathBuf {
#[inline]
unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
}
+ fn from_inner_mut(inner: &mut OsStr) -> &mut Path {
+ // SAFETY: Path is just a wrapper around OsStr,
+ // therefore converting &mut OsStr to &mut Path is safe.
+ unsafe { &mut *(inner as *mut OsStr as *mut Path) }
+ }
+
/// Yields the underlying [`OsStr`] slice.
///
/// # Examples
used when wrapping semantics are intended, and that explicit checking and
wrapping methods always be used when using Unsafe Rust.
-<small id="fn:2">2\. See <https://doc.rust-lang.org/std/primitive.u32.html>
+<small id="fn:2">2\. See [the `u32` docs](../std/primitive.u32.html)
for more information on the checked, overflowing, saturating, and wrapping
methods (using u32 as an example). <a href="#fnref:2"
class="reversefootnote" role="doc-backlink">↩</a></small>
<https://hacks.mozilla.org/2019/02/fearless-security-thread-safety/>.
3. S. Klabnik and C. Nichols. “What Is Ownership?.” The Rust Programming
- Language. <https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html>.
+ Language. [https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html](../book/ch04-01-what-is-ownership.html).
4. S. Klabnik and C. Nichols. “References and Borrowing.” The Rust
Programming Language.
- <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html>.
+ [https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html](../book/ch04-02-references-and-borrowing.html).
5. S. Klabnik and C. Nichols. “The Slice Type.” The Rust Programming
- Language. <https://doc.rust-lang.org/book/ch04-03-slices.html>.
+ Language. [https://doc.rust-lang.org/book/ch04-03-slices.html](../book/ch04-03-slices.html).
6. S. Klabnik and C. Nichols. “Unsafe Rust.” The Rust Programming Language.
- <https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html>.
+ [https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html](../book/ch19-01-unsafe-rust.html).
7. S. Davidoff. “How Rust’s standard library was vulnerable for years and
nobody noticed.” Medium.
for Rust #89653.” GitHub. <https://github.com/rust-lang/rust/issues/89653>.
41. “ControlFlowIntegrity.” The Rust Unstable Book.
- <https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity>.
+ [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity](../unstable-book/compiler-flags/sanitizer.html#controlflowintegrity).
This is fixed if you explicitly set the target, for example
`cargo build --target x86_64-pc-windows-msvc`
Without an explicit --target the flags will be passed to all compiler invocations (including build
-scripts and proc macros), see [cargo docs on rustflags](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags)
+scripts and proc macros), see [cargo docs on rustflags](../cargo/reference/config.html#buildrustflags)
If you have dependencies using the `cc` crate, you will need to set these
environment variables:
[Android NDK]: https://developer.android.com/ndk/downloads
A list of all supported targets can be found
-[here](https://doc.rust-lang.org/rustc/platform-support.html)
+[here](../platform-support.html)
The `cargo-3ds` tool mentioned in [Building Rust programs](#building-rust-programs)
supports the use of `3dslink` with `cargo 3ds run`. The default Rust test runner
is not supported, but
-[custom test frameworks](https://doc.rust-lang.org/beta/unstable-book/language-features/custom-test-frameworks.html)
+[custom test frameworks](../../unstable-book/language-features/custom-test-frameworks.html)
can be used with `cargo 3ds test` to run unit tests on a device.
The Rust test suite for `library/std` is not yet supported.
After installing our Fuchsia targets, we can now compile a Rust binary that targets
Fuchsia.
-To create our Rust project, we can issue a standard `cargo` command as follows:
+To create our Rust project, we can use [`cargo`][cargo] as follows:
**From base working directory**
```sh
[Fuchsia]: https://fuchsia.dev/
[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
[rustup]: https://rustup.rs/
-[cargo]: https://doc.rust-lang.org/cargo/
+[cargo]: ../../cargo/index.html
[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
[reference for the file format]: https://fuchsia.dev/reference/cml
rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json
```
-To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`.
+To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`.
Rust's standard library does not ship with BTI or pointer authentication enabled by default.
In Cargo projects the standard library can be recompiled with pointer authentication using the nightly
-[build-std](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) feature.
+[build-std](../../cargo/reference/unstable.html#build-std) feature.
To enable CFG in the standard library, use the [cargo `-Z build-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.
-[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
+[build-std]: ../../cargo/reference/unstable.html#build-std
For example:
```cmd
parameter types than the return type expected and arguments intended/passed in
the call/branch site, the execution is also terminated (see Fig. 9).
-[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
-[rust-book]: https://doc.rust-lang.org/book/title-page.html
+[rust-book-ch19-05]: ../../book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: ../../book/title-page.html
# HWAddressSanitizer
instrumented standard library, for example using [cargo `-Zbuild-std`
functionality][build-std].
-[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
+[build-std]: ../../cargo/reference/unstable.html#build-std
# Build scripts and procedural macros
to inlining of `f`, `Foo::foo` can then be called from a foreign crate. This can
lead to miscompilations.
-[Clto]: https://doc.rust-lang.org/rustc/codegen-options/index.html#lto
+[Clto]: ../../rustc/codegen-options/index.html#lto
has explicitly opted out via a negative impl. (Negative impls are separately controlled
by the `negative_impls` feature.)
-[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
-[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+[`Send`]: ../../std/marker/trait.Send.html
+[`Sync`]: ../../std/marker/trait.Sync.html
```rust,ignore (partial-example)
impl !Trait for Type {}
required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have
exactly one (non self) argument, a tuple representing the argument list.
-[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+[`Fn*`]: ../../std/ops/trait.Fn.html
```rust
#![feature(unboxed_closures)]
just forwards to [`Default::default()`], but may remove repetition of the word
"default" from the call site.
-[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default
+[`Default::default()`]: ../../std/default/trait.Default.html#tymethod.default
Here is an example:
The `fn_traits` feature allows for implementation of the [`Fn*`] traits
for creating custom closure-like types.
-[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+[`Fn*`]: ../../std/ops/trait.Fn.html
```rust
#![feature(unboxed_closures)]
// * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
// * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
- use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
+ use rustc_middle::ty::fast_reject::SimplifiedType::*;
let type_ =
if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
for &did in tcx.incoherent_impls(type_) {
}
pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
- use ty::fast_reject::SimplifiedTypeGen::*;
+ use ty::fast_reject::SimplifiedType::*;
use ty::{FloatTy, IntTy, UintTy};
use PrimitiveType::*;
static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
overflow-y: hidden;
}
-.source .sidebar, #sidebar-toggle, #source-sidebar {
+.source .sidebar, #src-sidebar-toggle, #source-sidebar {
background-color: var(--sidebar-background-color);
}
-#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
+#src-sidebar-toggle > button:hover, #src-sidebar-toggle > button:focus {
background-color: var(--sidebar-background-color-hover);
}
-.source .sidebar > *:not(#sidebar-toggle) {
+.source .sidebar > *:not(#src-sidebar-toggle) {
visibility: hidden;
}
flex-basis: 300px;
}
-.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
+.source-sidebar-expanded .source .sidebar > *:not(#src-sidebar-toggle) {
visibility: visible;
}
color: var(--code-highlight-doc-comment-color);
}
+.rustdoc.source .example-wrap pre.rust a {
+ background: var(--codeblock-link-background);
+}
+
.example-wrap.compile_fail,
.example-wrap.should_panic {
border-left: 2px solid var(--codeblock-error-color);
top: 5px;
}
-.example-wrap .tooltip::after {
- display: none;
+.example-wrap .tooltip:hover::after {
text-align: center;
padding: 5px 3px 3px 3px;
border-radius: 6px;
color: var(--tooltip-color);
}
-.example-wrap .tooltip::before {
+.example-wrap .tooltip:hover::before {
content: " ";
position: absolute;
top: 50%;
left: 16px;
margin-top: -5px;
- display: none;
z-index: 1;
border: 5px solid transparent;
border-right-color: var(--tooltip-background-color);
}
-.example-wrap.ignore .tooltip::after {
+.example-wrap.ignore .tooltip:hover::after {
content: "This example is not tested";
}
-.example-wrap.compile_fail .tooltip::after {
+.example-wrap.compile_fail .tooltip:hover::after {
content: "This example deliberately fails to compile";
}
-.example-wrap.should_panic .tooltip::after {
+.example-wrap.should_panic .tooltip:hover::after {
content: "This example panics";
}
-.example-wrap.edition .tooltip::after {
+.example-wrap.edition .tooltip:hover::after {
content: "This code runs with edition " attr(data-edition);
}
-.example-wrap .tooltip:hover::before, .example-wrap .tooltip:hover::after {
- display: inline;
-}
-
.example-wrap.compile_fail .tooltip,
.example-wrap.should_panic .tooltip,
.example-wrap.ignore .tooltip {
font-size: 1rem;
}
-#sidebar-toggle {
+#src-sidebar-toggle {
position: sticky;
top: 0;
left: 0;
#source-sidebar div.files > a.selected {
background-color: var(--source-sidebar-background-selected);
}
-#sidebar-toggle > button {
+#src-sidebar-toggle > button {
font-size: inherit;
font-weight: bold;
background: none;
left: -11px;
}
- #sidebar-toggle {
+ #src-sidebar-toggle {
position: fixed;
left: 1px;
top: 100px;
border-left: 0;
}
- .source-sidebar-expanded #sidebar-toggle {
+ .source-sidebar-expanded #src-sidebar-toggle {
left: unset;
top: unset;
width: unset;
width: 35px;
}
- #sidebar-toggle {
+ #src-sidebar-toggle {
top: 10px;
}
- .source-sidebar-expanded #sidebar-toggle {
+ .source-sidebar-expanded #src-sidebar-toggle {
top: unset;
}
}
cursor: pointer;
}
-.setting-line > .sub-settings {
- padding-left: 42px;
- width: 100%;
- display: block;
-}
-
#settings .setting-line {
margin: 1.2em 0.6em;
}
--source-sidebar-background-selected: #14191f;
--source-sidebar-background-hover: #14191f;
--table-alt-row-background-color: #191f26;
+ --codeblock-link-background: #333;
}
h1, h2, h3, h4 {
.sidebar h3 a {
color: white;
}
-body.source .example-wrap pre.rust a {
- background: #333;
-}
.result-name .primitive > i, .result-name .keyword > i {
color: #788797;
--source-sidebar-background-selected: #333;
--source-sidebar-background-hover: #444;
--table-alt-row-background-color: #2A2A2A;
-}
-
-body.source .example-wrap pre.rust a {
- background: #333;
+ --codeblock-link-background: #333;
}
#titles > button:not(.selected) {
--source-sidebar-background-selected: #fff;
--source-sidebar-background-hover: #e0e0e0;
--table-alt-row-background-color: #F5F5F5;
-}
-
-body.source .example-wrap pre.rust a {
- background: #eee;
+ --codeblock-link-background: #eee;
}
#titles > button:not(.selected) {
function createSidebarToggle() {
const sidebarToggle = document.createElement("div");
- sidebarToggle.id = "sidebar-toggle";
+ sidebarToggle.id = "src-sidebar-toggle";
const inner = document.createElement("button");
--- /dev/null
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR enums.switch_bool.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_bool(b: bool) -> u32 {
+ mir!(
+ {
+ match b {
+ true => t,
+ false => f,
+ _ => f,
+ }
+ }
+
+ t = {
+ RET = 5;
+ Return()
+ }
+
+ f = {
+ RET = 10;
+ Return()
+ }
+ )
+}
+
+// EMIT_MIR enums.switch_option.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn switch_option(option: Option<()>) -> bool {
+ mir!(
+ {
+ let discr = Discriminant(option);
+ match discr {
+ 0 => n,
+ 1 => s,
+ _ => s,
+ }
+ }
+
+ n = {
+ RET = false;
+ Return()
+ }
+
+ s = {
+ RET = true;
+ Return()
+ }
+ )
+}
+
+#[repr(u8)]
+enum Bool {
+ False = 0,
+ True = 1,
+}
+
+// EMIT_MIR enums.switch_option_repr.built.after.mir
+#[custom_mir(dialect = "built")]
+fn switch_option_repr(option: Bool) -> bool {
+ mir!(
+ {
+ let discr = Discriminant(option);
+ match discr {
+ 0 => f,
+ _ => t,
+ }
+ }
+
+ t = {
+ RET = true;
+ Return()
+ }
+
+ f = {
+ RET = false;
+ Return()
+ }
+ )
+}
+
+// EMIT_MIR enums.set_discr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr(option: &mut Option<()>) {
+ mir!({
+ SetDiscriminant(*option, 0);
+ Return()
+ })
+}
+
+// EMIT_MIR enums.set_discr_repr.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discr_repr(b: &mut Bool) {
+ mir!({
+ SetDiscriminant(*b, 0);
+ Return()
+ })
+}
+
+fn main() {
+ assert_eq!(switch_bool(true), 5);
+ assert_eq!(switch_bool(false), 10);
+
+ assert_eq!(switch_option(Some(())), true);
+ assert_eq!(switch_option(None), false);
+
+ assert_eq!(switch_option_repr(Bool::True), true);
+ assert_eq!(switch_option_repr(Bool::False), false);
+
+ let mut opt = Some(());
+ set_discr(&mut opt);
+ assert_eq!(opt, None);
+
+ let mut b = Bool::True;
+ set_discr_repr(&mut b);
+ assert!(matches!(b, Bool::False));
+}
--- /dev/null
+// MIR for `set_discr` after built
+
+fn set_discr(_1: &mut Option<()>) -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/enums.rs:+0:39: +0:39
+
+ bb0: {
+ discriminant((*_1)) = 0; // scope 0 at $DIR/enums.rs:+2:9: +2:36
+ return; // scope 0 at $DIR/enums.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `set_discr_repr` after built
+
+fn set_discr_repr(_1: &mut Bool) -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/enums.rs:+0:33: +0:33
+
+ bb0: {
+ discriminant((*_1)) = 0; // scope 0 at $DIR/enums.rs:+2:9: +2:31
+ return; // scope 0 at $DIR/enums.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `switch_bool` after built
+
+fn switch_bool(_1: bool) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/enums.rs:+0:32: +0:35
+
+ bb0: {
+ switchInt(_1) -> [1: bb1, 0: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+3:13: +7:14
+ }
+
+ bb1: {
+ _0 = const 5_u32; // scope 0 at $DIR/enums.rs:+11:13: +11:20
+ return; // scope 0 at $DIR/enums.rs:+12:13: +12:21
+ }
+
+ bb2: {
+ _0 = const 10_u32; // scope 0 at $DIR/enums.rs:+16:13: +16:21
+ return; // scope 0 at $DIR/enums.rs:+17:13: +17:21
+ }
+}
--- /dev/null
+// MIR for `switch_option` after built
+
+fn switch_option(_1: Option<()>) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/enums.rs:+0:45: +0:49
+ let mut _2: isize; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ switchInt(_2) -> [0: bb1, 1: bb2, otherwise: bb2]; // scope 0 at $DIR/enums.rs:+4:13: +8:14
+ }
+
+ bb1: {
+ _0 = const false; // scope 0 at $DIR/enums.rs:+12:13: +12:24
+ return; // scope 0 at $DIR/enums.rs:+13:13: +13:21
+ }
+
+ bb2: {
+ _0 = const true; // scope 0 at $DIR/enums.rs:+17:13: +17:23
+ return; // scope 0 at $DIR/enums.rs:+18:13: +18:21
+ }
+}
--- /dev/null
+// MIR for `switch_option_repr` after built
+
+fn switch_option_repr(_1: Bool) -> bool {
+ let mut _0: bool; // return place in scope 0 at $DIR/enums.rs:+0:40: +0:44
+ let mut _2: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ _2 = discriminant(_1); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ switchInt(_2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/enums.rs:+4:13: +7:14
+ }
+
+ bb1: {
+ _0 = const true; // scope 0 at $DIR/enums.rs:+11:13: +11:23
+ return; // scope 0 at $DIR/enums.rs:+12:13: +12:21
+ }
+
+ bb2: {
+ _0 = const false; // scope 0 at $DIR/enums.rs:+16:13: +16:24
+ return; // scope 0 at $DIR/enums.rs:+17:13: +17:21
+ }
+}
--- /dev/null
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+union U {
+ a: i32,
+ b: u32,
+}
+
+// EMIT_MIR projections.unions.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unions(u: U) -> i32 {
+ mir!({
+ RET = u.a;
+ Return()
+ })
+}
+
+// EMIT_MIR projections.tuples.built.after.mir
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn tuples(i: (u32, i32)) -> (u32, i32) {
+ mir!(
+ // FIXME(JakobDegen): This is necessary because we can't give type hints for `RET`
+ let temp: (u32, i32);
+ {
+ temp.0 = i.0;
+ temp.1 = i.1;
+
+ RET = temp;
+ Return()
+ }
+ )
+}
+
+// EMIT_MIR projections.unwrap.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap(opt: Option<i32>) -> i32 {
+ mir!({
+ RET = Field(Variant(opt, 1), 0);
+ Return()
+ })
+}
+
+// EMIT_MIR projections.unwrap_deref.built.after.mir
+#[custom_mir(dialect = "built")]
+fn unwrap_deref(opt: Option<&i32>) -> i32 {
+ mir!({
+ RET = *Field::<&i32>(Variant(opt, 1), 0);
+ Return()
+ })
+}
+
+// EMIT_MIR projections.set.built.after.mir
+#[custom_mir(dialect = "built")]
+fn set(opt: &mut Option<i32>) {
+ mir!({
+ place!(Field(Variant(*opt, 1), 0)) = 10;
+ Return()
+ })
+}
+
+// EMIT_MIR projections.simple_index.built.after.mir
+#[custom_mir(dialect = "built")]
+fn simple_index(a: [i32; 10], b: &[i32]) -> i32 {
+ mir!({
+ let temp = 3;
+ RET = a[temp];
+ RET = (*b)[temp];
+ Return()
+ })
+}
+
+fn main() {
+ assert_eq!(unions(U { a: 5 }), 5);
+ assert_eq!(tuples((5, 6)), (5, 6));
+
+ assert_eq!(unwrap(Some(5)), 5);
+ assert_eq!(unwrap_deref(Some(&5)), 5);
+ let mut o = Some(5);
+ set(&mut o);
+ assert_eq!(o, Some(10));
+
+ assert_eq!(simple_index([0; 10], &[0; 10]), 0);
+}
--- /dev/null
+// MIR for `set` after built
+
+fn set(_1: &mut Option<i32>) -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/projections.rs:+0:31: +0:31
+
+ bb0: {
+ (((*_1) as variant#1).0: i32) = const 10_i32; // scope 0 at $DIR/projections.rs:+2:9: +2:48
+ return; // scope 0 at $DIR/projections.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `simple_index` after built
+
+fn simple_index(_1: [i32; 10], _2: &[i32]) -> i32 {
+ let mut _0: i32; // return place in scope 0 at $DIR/projections.rs:+0:45: +0:48
+ let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ _3 = const 3_usize; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+ _0 = _1[_3]; // scope 0 at $DIR/projections.rs:+3:9: +3:22
+ _0 = (*_2)[_3]; // scope 0 at $DIR/projections.rs:+4:9: +4:25
+ return; // scope 0 at $DIR/projections.rs:+5:9: +5:17
+ }
+}
--- /dev/null
+// MIR for `tuples` after built
+
+fn tuples(_1: (u32, i32)) -> (u32, i32) {
+ let mut _0: (u32, i32); // return place in scope 0 at $DIR/projections.rs:+0:29: +0:39
+ let mut _2: (u32, i32); // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+ bb0: {
+ (_2.0: u32) = (_1.0: u32); // scope 0 at $DIR/projections.rs:+5:13: +5:25
+ (_2.1: i32) = (_1.1: i32); // scope 0 at $DIR/projections.rs:+6:13: +6:25
+ _0 = _2; // scope 0 at $DIR/projections.rs:+8:13: +8:23
+ return; // scope 0 at $DIR/projections.rs:+9:13: +9:21
+ }
+}
--- /dev/null
+// MIR for `unions` after built
+
+fn unions(_1: U) -> i32 {
+ let mut _0: i32; // return place in scope 0 at $DIR/projections.rs:+0:20: +0:23
+
+ bb0: {
+ _0 = (_1.0: i32); // scope 0 at $DIR/projections.rs:+2:9: +2:18
+ return; // scope 0 at $DIR/projections.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `unwrap` after built
+
+fn unwrap(_1: Option<i32>) -> i32 {
+ let mut _0: i32; // return place in scope 0 at $DIR/projections.rs:+0:32: +0:35
+
+ bb0: {
+ _0 = ((_1 as variant#1).0: i32); // scope 0 at $DIR/projections.rs:+2:9: +2:40
+ return; // scope 0 at $DIR/projections.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `unwrap_deref` after built
+
+fn unwrap_deref(_1: Option<&i32>) -> i32 {
+ let mut _0: i32; // return place in scope 0 at $DIR/projections.rs:+0:39: +0:42
+
+ bb0: {
+ _0 = (*((_1 as variant#1).0: &i32)); // scope 0 at $DIR/projections.rs:+2:9: +2:49
+ return; // scope 0 at $DIR/projections.rs:+3:9: +3:17
+ }
+}
--- /dev/null
+// MIR for `raw_pointer` after built
+
+fn raw_pointer(_1: *const i32) -> *const i32 {
+ let mut _0: *const i32; // return place in scope 0 at $DIR/references.rs:+0:38: +0:48
+
+ bb0: {
+ _0 = &raw const (*_1); // scope 0 at $DIR/references.rs:+4:9: +4:27
+ return; // scope 0 at $DIR/references.rs:+5:9: +5:17
+ }
+}
)
}
+// EMIT_MIR references.raw_pointer.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn raw_pointer(x: *const i32) -> *const i32 {
+ // Regression test for a bug in which unsafetyck was not correctly turned off for
+ // `dialect = "built"`
+ mir!({
+ RET = addr_of!(*x);
+ Return()
+ })
+}
+
fn main() {
let mut x = 5;
assert_eq!(*mut_ref(&mut x), 5);
assert_eq!(*immut_ref(&x), 5);
+ unsafe {
+ assert_eq!(*raw_pointer(addr_of!(x)), 5);
+ }
}
// This test checks that the source code pages sidebar toggle is working as expected.
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
click: ".srclink"
-wait-for: "#sidebar-toggle"
-click: "#sidebar-toggle"
+wait-for: "#src-sidebar-toggle"
+click: "#src-sidebar-toggle"
fail: true
assert-css: ("#source-sidebar", { "left": "-300px" })
{"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
)),
- ("move-cursor-to", ".docblock .example-wrap.compile_fail"),
+ ("move-cursor-to", ".docblock .example-wrap.compile_fail .tooltip"),
("assert-css", (
".docblock .example-wrap.compile_fail .tooltip",
{"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
)),
- ("move-cursor-to", ".docblock .example-wrap.should_panic"),
+ ("move-cursor-to", ".docblock .example-wrap.should_panic .tooltip"),
("assert-css", (
".docblock .example-wrap.should_panic .tooltip",
{"border-left": "2px solid rgba(255, 142, 0, 0.6)"},
)),
- ("move-cursor-to", ".docblock .example-wrap.ignore"),
+ ("move-cursor-to", ".docblock .example-wrap.ignore .tooltip"),
("assert-css", (
".docblock .example-wrap.ignore .tooltip",
// the sidebar toggle button on the source code pages
goto: "file://" + |DOC_PATH| + "/src/lib2/lib.rs.html"
-assert-css: ("#sidebar-toggle > button", {"cursor": "pointer"})
+assert-css: ("#src-sidebar-toggle > button", {"cursor": "pointer"})
javascript: false
goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// Since the javascript is disabled, there shouldn't be a toggle.
-assert-false: "#sidebar-toggle"
+assert-false: "#src-sidebar-toggle"
wait-for-css: (".sidebar", {"display": "none"})
// Let's retry with javascript enabled.
javascript: true
reload:
-wait-for: "#sidebar-toggle"
-assert-css: ("#sidebar-toggle", {"visibility": "visible"})
-assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden"})
+wait-for: "#src-sidebar-toggle"
+assert-css: ("#src-sidebar-toggle", {"visibility": "visible"})
+assert-css: (".sidebar > *:not(#src-sidebar-toggle)", {"visibility": "hidden"})
// Let's expand the sidebar now.
-click: "#sidebar-toggle"
-wait-for-css: ("#sidebar-toggle", {"visibility": "visible"})
+click: "#src-sidebar-toggle"
+wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
// We now check that opening the sidebar and clicking a link will leave it open.
// The behavior here on desktop is different than the behavior on mobile,
[
("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
("reload"),
- ("wait-for-css", ("#sidebar-toggle", {"visibility": "visible"})),
+ ("wait-for-css", ("#src-sidebar-toggle", {"visibility": "visible"})),
("assert-css", (
"#source-sidebar details[open] > .files a.selected",
{"color": |color_hover|, "background-color": |background|},
)),
// Without hover or focus.
- ("assert-css", ("#sidebar-toggle > button", {"background-color": |background_toggle|})),
+ ("assert-css", ("#src-sidebar-toggle > button", {"background-color": |background_toggle|})),
// With focus.
- ("focus", "#sidebar-toggle > button"),
+ ("focus", "#src-sidebar-toggle > button"),
("assert-css", (
- "#sidebar-toggle > button:focus",
+ "#src-sidebar-toggle > button:focus",
{"background-color": |background_toggle_hover|},
)),
("focus", ".search-input"),
// With hover.
- ("move-cursor-to", "#sidebar-toggle > button"),
+ ("move-cursor-to", "#src-sidebar-toggle > button"),
("assert-css", (
- "#sidebar-toggle > button:hover",
+ "#src-sidebar-toggle > button:hover",
{"background-color": |background_toggle_hover|},
)),
size: (500, 700)
reload:
// Waiting for the sidebar to be displayed...
-wait-for-css: ("#sidebar-toggle", {"visibility": "visible"})
+wait-for-css: ("#src-sidebar-toggle", {"visibility": "visible"})
// We now check it takes the full size of the display.
assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"})
assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"})
// We now check the display of the toggle once the sidebar is expanded.
-assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
+assert-property: ("#src-sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
assert-css: (
- "#sidebar-toggle",
+ "#src-sidebar-toggle",
{
"border-top-width": "0px",
"border-right-width": "0px",
)
// We now check that the scroll position is kept when opening the sidebar.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: (".sidebar", {"width": "0px"})
// We scroll to line 117 to change the scroll position.
scroll-to: '//*[@id="117"]'
assert-window-property: {"pageYOffset": "2542"}
// Expanding the sidebar...
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: (".sidebar", {"width": "500px"})
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: (".sidebar", {"width": "0px"})
// The "scrollTop" property should be the same.
assert-window-property: {"pageYOffset": "2542"}
// We now check that the scroll position is restored if the window is resized.
size: (500, 700)
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: ("#source-sidebar", {"visibility": "visible"})
assert-window-property: {"pageYOffset": "0"}
size: (900, 900)
assert-window-property: {"pageYOffset": "2542"}
size: (500, 700)
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
// We now check that opening the sidebar and clicking a link will close it.
// but common sense dictates that if you have a list of files that fills the entire screen, and
// you click one of them, you probably want to actually see the file's contents, and not just
// make it the current selection.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: ("#source-sidebar", {"visibility": "visible"})
assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
click: ".sidebar a.selected"
size: (1000, 1000)
wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
wait-for-css: ("#source-sidebar", {"visibility": "visible"})
assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
// Checking the source code sidebar.
// First we "open" it.
-click: "#sidebar-toggle"
+click: "#src-sidebar-toggle"
assert: ".source-sidebar-expanded"
// We check that the first entry of the sidebar is collapsed
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
-Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
-Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
+ -Z dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
-Z dylib-lto=val -- enables LTO for dylib crate type
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
--- /dev/null
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features, dead_code)]
+#![deny(non_camel_case_types)]
+
+struct S;
+
+impl S {
+ type typ = ();
+ //~^ ERROR associated type `typ` should have an upper camel case name
+}
+
+fn main() {}
--- /dev/null
+error: associated type `typ` should have an upper camel case name
+ --> $DIR/style.rs:8:10
+ |
+LL | type typ = ();
+ | ^^^ help: convert the identifier to upper camel case: `Typ`
+ |
+note: the lint level is defined here
+ --> $DIR/style.rs:3:9
+ |
+LL | #![deny(non_camel_case_types)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
- //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+ //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
}
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
...
LL | let x: isize = Foo::bar();
| ^^^^^^^^ cannot call associated function of trait
+ |
+help: use the fully-qualified path to the only available implementation
+ |
+LL | let x: isize = <isize as Foo>::bar();
+ | +++++++++ +
error: aborting due to previous error
--- /dev/null
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+//~^ WARN the feature `async_fn_in_trait` is incomplete
+
+trait MyTrait {
+ async fn bar(&abc self);
+ //~^ ERROR expected identifier, found keyword `self`
+ //~| ERROR expected one of `:`, `@`, or `|`, found keyword `self`
+}
+
+impl MyTrait for () {
+ async fn bar(&self) {}
+}
+
+fn main() {}
--- /dev/null
+error: expected identifier, found keyword `self`
+ --> $DIR/bad-signatures.rs:7:23
+ |
+LL | async fn bar(&abc self);
+ | ^^^^ expected identifier, found keyword
+
+error: expected one of `:`, `@`, or `|`, found keyword `self`
+ --> $DIR/bad-signatures.rs:7:23
+ |
+LL | async fn bar(&abc self);
+ | -----^^^^
+ | | |
+ | | expected one of `:`, `@`, or `|`
+ | help: declare the type after the parameter binding: `<identifier>: <type>`
+
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/bad-signatures.rs:3:12
+ |
+LL | #![feature(async_fn_in_trait)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
-error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
--> $DIR/issue-33784.rs:27:7
|
LL | p.closure();
LL | (p.closure)();
| + +
-error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@issue-33784.rs:25:43]>` in the current scope
--> $DIR/issue-33784.rs:29:7
|
LL | q.fn_ptr();
+++ /dev/null
-error: type parameters must be declared prior to const parameters
- --> $DIR/complex-unord-param.rs:8:41
- |
-LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
- | ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a = u32, const N: usize, const M: usize>`
-
-error: aborting due to previous error
-
--- /dev/null
+// check-pass
+// edition:2021
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[allow(unused)]
+async fn foo<'a>() {
+ let _data = &mut [0u8; { 1 + 4 }];
+ bar().await
+}
+
+async fn bar() {}
+
+fn main() {}
+++ /dev/null
-error: type parameters must be declared prior to const parameters
- --> $DIR/type-after-const-ok.rs:8:26
- |
-LL | struct A<const N: usize, T>(T);
- | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-
-error: aborting due to previous error
-
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
- = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/forbidden_slices.rs:32:1
|
LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
- = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u64>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
- = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u32>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 01 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- â\95¾ALLOC_IDâ\94\80â\95¼ 04 00 00 00 â\94\82 â\95¾â\94\80â\94\80â\95¼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | pub static R7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ = note: accessing memory with alignment 1, but alignment 2 is required
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
- }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+ --> $DIR/forbidden_slices.rs:69:5
+ |
+LL | from_ptr_range(ptr..ptr.add(4))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
- = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u64>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `ptr::const_ptr::<impl *const u64>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `R8`
- --> $DIR/forbidden_slices.rs:74:25
+ --> $DIR/forbidden_slices.rs:73:25
|
LL | from_ptr_range(ptr..ptr.add(1))
| ^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
note: inside `R9`
- --> $DIR/forbidden_slices.rs:79:34
+ --> $DIR/forbidden_slices.rs:78:34
|
LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
note: inside `R10`
- --> $DIR/forbidden_slices.rs:80:35
+ --> $DIR/forbidden_slices.rs:79:35
|
LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
- = note: dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/forbidden_slices.rs:32:1
|
LL | pub static S7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
- = note: dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `std::slice::from_raw_parts::<'_, u64>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
- = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u32>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/forbidden_slices.rs:67:1
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
|
-LL | pub static R7: &[u16] = unsafe {
- | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
+ = note: accessing memory with alignment 1, but alignment 2 is required
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
- }
+note: inside `std::slice::from_raw_parts::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `from_ptr_range::<'_, u16>`
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+note: inside `R7`
+ --> $DIR/forbidden_slices.rs:69:5
+ |
+LL | from_ptr_range(ptr..ptr.add(4))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
- = note: out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
|
note: inside `ptr::const_ptr::<impl *const u64>::offset`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `ptr::const_ptr::<impl *const u64>::add`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `R8`
- --> $DIR/forbidden_slices.rs:74:25
+ --> $DIR/forbidden_slices.rs:73:25
|
LL | from_ptr_range(ptr..ptr.add(1))
| ^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
note: inside `R9`
- --> $DIR/forbidden_slices.rs:79:34
+ --> $DIR/forbidden_slices.rs:78:34
|
LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `from_ptr_range::<'_, u32>`
--> $SRC_DIR/core/src/slice/raw.rs:LL:COL
note: inside `R10`
- --> $DIR/forbidden_slices.rs:80:35
+ --> $DIR/forbidden_slices.rs:79:35
|
LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^
// stderr-per-bitwidth
-// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
-// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
+// normalize-stderr-test "alloc\d+" -> "allocN"
// error-pattern: could not evaluate static initializer
#![feature(
slice_from_ptr_range,
// Reading padding is not ok
pub static S7: &[u16] = unsafe {
//~^ ERROR: it is undefined behavior to use this value
- let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+ let ptr = (&D2 as *const Struct as *const u16).add(1);
from_raw_parts(ptr, 4)
};
from_ptr_range(ptr..ptr.add(4))
};
pub static R7: &[u16] = unsafe {
- //~^ ERROR: it is undefined behavior to use this value
let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
- from_ptr_range(ptr..ptr.add(4))
+ from_ptr_range(ptr..ptr.add(4)) //~ inside `R7`
};
pub static R8: &[u64] = unsafe {
let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
- from_ptr_range(ptr..ptr.add(1))
+ from_ptr_range(ptr..ptr.add(1)) //~ inside `R8`
};
// This is sneaky: &D0 and &D0 point to different objects
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:13:1
+ --> $DIR/ub-ref-ptr.rs:14:1
|
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:17:1
+ --> $DIR/ub-ref-ptr.rs:18:1
|
LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:21:1
+ --> $DIR/ub-ref-ptr.rs:22:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:24:1
+ --> $DIR/ub-ref-ptr.rs:25:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:31:1
+ --> $DIR/ub-ref-ptr.rs:32:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:34:39
+ --> $DIR/ub-ref-ptr.rs:35:39
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:34:38
+ --> $DIR/ub-ref-ptr.rs:35:38
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:37:86
+ --> $DIR/ub-ref-ptr.rs:38:86
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:37:85
+ --> $DIR/ub-ref-ptr.rs:38:85
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:40:1
+ --> $DIR/ub-ref-ptr.rs:41:1
|
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:43:1
+ --> $DIR/ub-ref-ptr.rs:44:1
|
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:46:41
+ --> $DIR/ub-ref-ptr.rs:47:41
|
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:50:1
+ --> $DIR/ub-ref-ptr.rs:51:1
|
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:52:38
+ --> $DIR/ub-ref-ptr.rs:53:38
|
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:55:1
+ --> $DIR/ub-ref-ptr.rs:56:1
|
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:57:1
+ --> $DIR/ub-ref-ptr.rs:58:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
╾─alloc41─╼ │ ╾──╼
}
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:13:1
+ --> $DIR/ub-ref-ptr.rs:14:1
|
LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:17:1
+ --> $DIR/ub-ref-ptr.rs:18:1
|
LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:21:1
+ --> $DIR/ub-ref-ptr.rs:22:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:24:1
+ --> $DIR/ub-ref-ptr.rs:25:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:31:1
+ --> $DIR/ub-ref-ptr.rs:32:1
|
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:34:39
+ --> $DIR/ub-ref-ptr.rs:35:39
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:34:38
+ --> $DIR/ub-ref-ptr.rs:35:38
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:37:86
+ --> $DIR/ub-ref-ptr.rs:38:86
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
note: erroneous constant used
- --> $DIR/ub-ref-ptr.rs:37:85
+ --> $DIR/ub-ref-ptr.rs:38:85
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
| ^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:40:1
+ --> $DIR/ub-ref-ptr.rs:41:1
|
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated)
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:43:1
+ --> $DIR/ub-ref-ptr.rs:44:1
|
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated)
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:46:41
+ --> $DIR/ub-ref-ptr.rs:47:41
|
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:50:1
+ --> $DIR/ub-ref-ptr.rs:51:1
|
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-ref-ptr.rs:52:38
+ --> $DIR/ub-ref-ptr.rs:53:38
|
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:55:1
+ --> $DIR/ub-ref-ptr.rs:56:1
|
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-ref-ptr.rs:57:1
+ --> $DIR/ub-ref-ptr.rs:58:1
|
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
╾───────alloc41───────╼ │ ╾──────╼
}
-error: aborting due to 14 previous errors
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
+error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: accessing memory with alignment 1, but alignment 4 is required
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+note: inside `std::ptr::read::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+note: inside `ptr::const_ptr::<impl *const u32>::read`
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+note: inside `UNALIGNED_READ`
+ --> $DIR/ub-ref-ptr.rs:65:5
+ |
+LL | ptr.read();
+ | ^^^^^^^^^^
+ = note: `#[deny(invalid_alignment)]` on by default
+
// ignore-tidy-linelength
// stderr-per-bitwidth
#![allow(invalid_value)]
+#![feature(const_ptr_read)]
use std::mem;
const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
//~^ ERROR it is undefined behavior to use this value
+
+const UNALIGNED_READ: () = unsafe {
+ let x = &[0u8; 4];
+ let ptr = x.as_ptr().cast::<u32>();
+ ptr.read(); //~ inside `UNALIGNED_READ`
+};
+
+
fn main() {}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:36:1
+ --> $DIR/ub-wide-ptr.rs:37:1
|
LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN──╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:38:1
+ --> $DIR/ub-wide-ptr.rs:39:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff ff │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:41:1
+ --> $DIR/ub-wide-ptr.rs:42:1
|
LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:44:1
+ --> $DIR/ub-wide-ptr.rs:45:1
|
LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:46:1
+ --> $DIR/ub-wide-ptr.rs:47:1
|
LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff ff │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:50:1
+ --> $DIR/ub-wide-ptr.rs:51:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:53:1
+ --> $DIR/ub-wide-ptr.rs:54:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ 01 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:60:1
+ --> $DIR/ub-wide-ptr.rs:61:1
|
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:67:1
+ --> $DIR/ub-wide-ptr.rs:68:1
|
LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:70:1
+ --> $DIR/ub-wide-ptr.rs:71:1
|
LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ ff ff ff 7f │ ╾──╼....
+ ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:73:1
+ --> $DIR/ub-wide-ptr.rs:74:1
|
LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:76:1
+ --> $DIR/ub-wide-ptr.rs:77:1
|
LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─allocN─╼ e7 03 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:79:1
+ --> $DIR/ub-wide-ptr.rs:80:1
|
LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:83:1
+ --> $DIR/ub-wide-ptr.rs:84:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾─allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:83:40
+ --> $DIR/ub-wide-ptr.rs:84:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:90:1
+ --> $DIR/ub-wide-ptr.rs:91:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:90:42
+ --> $DIR/ub-wide-ptr.rs:91:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:94:1
+ --> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
- ╾allocN─╼ │ ╾──╼
+ ╾ALLOC_ID╼ │ ╾──╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:94:42
+ --> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:102:1
+ --> $DIR/ub-wide-ptr.rs:103:1
|
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:111:1
+ --> $DIR/ub-wide-ptr.rs:112:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:115:1
+ --> $DIR/ub-wide-ptr.rs:116:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:119:1
+ --> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ 04 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼....
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:122:57
+ --> $DIR/ub-wide-ptr.rs:123:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:125:57
+ --> $DIR/ub-wide-ptr.rs:126:57
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:128:56
+ --> $DIR/ub-wide-ptr.rs:129:56
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:131:1
+ --> $DIR/ub-wide-ptr.rs:132:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:136:1
+ --> $DIR/ub-wide-ptr.rs:137:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:141:1
+ --> $DIR/ub-wide-ptr.rs:142:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ 00 00 00 00 │ ╾──╼....
+ ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼....
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:143:1
+ --> $DIR/ub-wide-ptr.rs:144:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
- ╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼
}
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:149:5
+ --> $DIR/ub-wide-ptr.rs:150:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:153:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:36:1
+ --> $DIR/ub-wide-ptr.rs:37:1
|
LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN────────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:38:1
+ --> $DIR/ub-wide-ptr.rs:39:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:41:1
+ --> $DIR/ub-wide-ptr.rs:42:1
|
LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:44:1
+ --> $DIR/ub-wide-ptr.rs:45:1
|
LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:46:1
+ --> $DIR/ub-wide-ptr.rs:47:1
|
LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:50:1
+ --> $DIR/ub-wide-ptr.rs:51:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:53:1
+ --> $DIR/ub-wide-ptr.rs:54:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:60:1
+ --> $DIR/ub-wide-ptr.rs:61:1
|
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:67:1
+ --> $DIR/ub-wide-ptr.rs:68:1
|
LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:70:1
+ --> $DIR/ub-wide-ptr.rs:71:1
|
LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
+ ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:73:1
+ --> $DIR/ub-wide-ptr.rs:74:1
|
LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:76:1
+ --> $DIR/ub-wide-ptr.rs:77:1
|
LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────allocN───────╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:79:1
+ --> $DIR/ub-wide-ptr.rs:80:1
|
LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:83:1
+ --> $DIR/ub-wide-ptr.rs:84:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾───────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:83:40
+ --> $DIR/ub-wide-ptr.rs:84:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:90:1
+ --> $DIR/ub-wide-ptr.rs:91:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾──────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:90:42
+ --> $DIR/ub-wide-ptr.rs:91:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:94:1
+ --> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
- ╾──────allocN───────╼ │ ╾──────╼
+ ╾ALLOC_ID╼ │ ╾──────╼
}
note: erroneous constant used
- --> $DIR/ub-wide-ptr.rs:94:42
+ --> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:102:1
+ --> $DIR/ub-wide-ptr.rs:103:1
|
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:111:1
+ --> $DIR/ub-wide-ptr.rs:112:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:115:1
+ --> $DIR/ub-wide-ptr.rs:116:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:119:1
+ --> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:122:57
+ --> $DIR/ub-wide-ptr.rs:123:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:125:57
+ --> $DIR/ub-wide-ptr.rs:126:57
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed
- --> $DIR/ub-wide-ptr.rs:128:56
+ --> $DIR/ub-wide-ptr.rs:129:56
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:131:1
+ --> $DIR/ub-wide-ptr.rs:132:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:136:1
+ --> $DIR/ub-wide-ptr.rs:137:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:141:1
+ --> $DIR/ub-wide-ptr.rs:142:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+ ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
}
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:143:1
+ --> $DIR/ub-wide-ptr.rs:144:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
- ╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
+ ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
}
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:149:5
+ --> $DIR/ub-wide-ptr.rs:150:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer
- --> $DIR/ub-wide-ptr.rs:153:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
use std::mem;
+// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼"
// normalize-stderr-test "offset \d+" -> "offset N"
// normalize-stderr-test "alloc\d+" -> "allocN"
// normalize-stderr-test "size \d+" -> "size N"
// Since we are not copying anything, this should be allowed.
let src = ();
let mut dst = ();
- copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+ copy_nonoverlapping(&src as *const _ as *const u8, &mut dst as *mut _ as *mut u8, 0);
};
const COPY_OOB_1: () = unsafe {
//[with_flag]~| invalid value
};
-const UNALIGNED_READ: () = {
- INNER; //[with_flag]~ constant
- // There is an error here but its span is in the standard library so we cannot match it...
- // so we have this in a *nested* const, such that the *outer* const fails to use it.
- const INNER: () = unsafe {
- let x = &[0u8; 4];
- let ptr = x.as_ptr().cast::<u32>();
- ptr.read();
- };
-};
-
fn main() {}
LL | let _x: &u32 = transmute(&[0u8; 4]);
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
- = note: accessing memory with alignment 1, but alignment 4 is required
- |
-note: inside `std::ptr::read::<u32>`
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
- --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `INNER`
- --> $DIR/detect-extra-ub.rs:38:9
- |
-LL | ptr.read();
- | ^^^^^^^^^^
-
-note: erroneous constant used
- --> $DIR/detect-extra-ub.rs:32:5
- |
-LL | INNER;
- | ^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+#![feature(dyn_star)]
+#![allow(incomplete_features)]
+
+trait Tr {}
+
+fn f(x: dyn* Tr) -> usize {
+ x as usize
+ //~^ ERROR casting `(dyn* Tr + 'static)` as `usize` is invalid
+}
+
+fn main() {}
--- /dev/null
+error[E0606]: casting `(dyn* Tr + 'static)` as `usize` is invalid
+ --> $DIR/dyn-to-rigid.rs:7:5
+ |
+LL | x as usize
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
LL | let xe1 = XEmpty2();
| ~~~~~~~
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:25:19
|
LL | let xe3 = XE::Empty3;
| ^^^^^^
| |
- | variant or associated item not found in `empty_struct::XE`
+ | variant or associated item not found in `XE`
| help: there is a variant with a similar name: `XEmpty3`
-error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
+error[E0599]: no variant or associated item named `Empty3` found for enum `XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:26:19
|
LL | let xe3 = XE::Empty3();
| ^^^^^^
| |
- | variant or associated item not found in `empty_struct::XE`
+ | variant or associated item not found in `XE`
| help: there is a variant with a similar name: `XEmpty3`
error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE`
|
help: use the fully-qualified path to the only available implementation
|
-LL | inner::<MyStruct as MyTrait>::my_fn();
- | ++++++++++++ +
+LL | <MyStruct as inner::MyTrait>::my_fn();
+ | ++++++++++++ +
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:30:13
|
help: use the fully-qualified path to the only available implementation
|
-LL | let _ = inner::<MyStruct as MyTrait>::MY_ASSOC_CONST;
- | ++++++++++++ +
+LL | let _ = <MyStruct as inner::MyTrait>::MY_ASSOC_CONST;
+ | ++++++++++++ +
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:50:5
+#![allow(unused, bare_trait_objects)]
#[repr(align(256))]
-#[allow(dead_code)]
struct A {
v: u8,
}
}
}
-fn foo(x: dyn Foo) {
- //~^ ERROR [E0277]
+fn foo(x: dyn Foo) { //~ ERROR [E0277]
x.foo()
}
+fn bar(x: Foo) { //~ ERROR [E0277]
+ x.foo()
+}
+
+fn qux(_: [()]) {} //~ ERROR [E0277]
+
fn main() {
let x: Box<dyn Foo> = Box::new(A { v: 22 });
- foo(*x);
- //~^ ERROR [E0277]
+ foo(*x); //~ ERROR [E0277]
}
|
= help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | fn foo(x: impl Foo) {
+ | ~~~~
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | fn foo(x: &dyn Foo) {
| +
error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
- --> $DIR/feature-gate-unsized_fn_params.rs:24:9
+ --> $DIR/feature-gate-unsized_fn_params.rs:21:8
+ |
+LL | fn bar(x: Foo) {
+ | ^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
+ = help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | fn bar(x: impl Foo) {
+ | ++++
+help: function arguments must have a statically known size, borrowed types always have a known size
+ |
+LL | fn bar(x: &Foo) {
+ | +
+
+error[E0277]: the size for values of type `[()]` cannot be known at compilation time
+ --> $DIR/feature-gate-unsized_fn_params.rs:25:8
+ |
+LL | fn qux(_: [()]) {}
+ | ^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[()]`
+ = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+ |
+LL | fn qux(_: &[()]) {}
+ | +
+
+error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
+ --> $DIR/feature-gate-unsized_fn_params.rs:29:9
|
LL | foo(*x);
| ^^ doesn't have a size known at compile-time
= note: all function arguments must have a statically known size
= help: unsized fn params are gated as an unstable feature
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.
|
= help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | fn f(f: impl FnOnce()) {}
+ | ~~~~
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | fn f(f: &dyn FnOnce()) {}
LL | trait Bar {
| ^^^^^^^^^
-error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:22:36]>` in the current scope
--> $DIR/fn-help-with-err.rs:23:10
|
LL | arc2.bar();
- | ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
+ | ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:22:36]>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Bar` defines an item `bar`, perhaps you need to implement it
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@issue-30786.rs:117:27]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:118:22
|
LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@issue-30786.rs:117:27]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@issue-30786.rs:129:30]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:130:24
|
LL | pub struct Filter<S, F> {
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
-error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:39:9
|
LL | let v = Unit2.m(
LL | fn bak() -> dyn Trait { unimplemented!() }
| ^^^^^^^^^ doesn't have a size known at compile-time
|
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
- |
-LL | fn bak() -> T { unimplemented!() }
- | ~
help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature
|
LL | fn bak() -> impl Trait { unimplemented!() }
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method2` found for struct `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:50:37
|
LL | no_method_suggested_traits::Foo.method2();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+ | ^^^^^^^ method not found in `Foo`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Foo>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:52:71
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method2` found for enum `Bar` in the current scope
--> $DIR/no-method-suggested-traits.rs:54:40
|
LL | no_method_suggested_traits::Bar::X.method2();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+ | ^^^^^^^ method not found in `Bar`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | pub trait Bar {
| ^^^^^^^^^^^^^
-error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&Bar>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:56:74
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
| ^^^^^^^ method not found in `Rc<&mut Box<&usize>>`
-error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:71:37
|
LL | no_method_suggested_traits::Foo.method3();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
+ | ^^^^^^^ method not found in `Foo`
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:72:71
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>`
-error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `Bar` in the current scope
--> $DIR/no-method-suggested-traits.rs:74:40
|
LL | no_method_suggested_traits::Bar::X.method3();
- | ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
+ | ^^^^^^^ method not found in `Bar`
-error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:75:74
|
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
- | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>`
+ | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>`
error: aborting due to 24 previous errors
LL | dyn AbstractRenderer
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
-help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
- |
-LL | T
- |
help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature
|
LL | impl AbstractRenderer
-error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph<i32, i32>` in the current scope
+error[E0599]: no function or associated item named `new_undirected` found for struct `Graph<i32, i32>` in the current scope
--> $DIR/issue-30123.rs:7:33
|
LL | let ug = Graph::<i32, i32>::new_undirected();
- | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+ | ^^^^^^^^^^^^^^ function or associated item not found in `Graph<i32, i32>`
|
= note: the function or associated item was found for
- `issue_30123_aux::Graph<N, E, Undirected>`
-error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
+error[E0271]: expected `TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>` to be an iterator that yields `&_`, but it yields `u8`
--> $DIR/issue-31173.rs:11:10
|
LL | .cloned()
|
= note: expected reference `&_`
found type `u8`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-31173.rs:3:20
+ |
+LL | pub fn get_tok(it: &mut IntoIter<u8>) {
+ | ^^^^^^^^^^^^^^^^^ `Iterator::Item` is `u8` here
+...
+LL | .take_while(|&x| {
+ | __________-
+LL | | found_e = true;
+LL | | false
+LL | | })
+ | |__________- `Iterator::Item` remains `u8` here
note: required by a bound in `cloned`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:12:10
|
LL | .collect();
use std::collections::HashMap;
fn main() {
- for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
- //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
- //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
}
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:36
|
LL | for _ in HashMap::new().iter().cloned() {}
|
= note: expected reference `&_`
found tuple `(&_, &_)`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/issue-33941.rs:6:29
+ |
+LL | for _ in HashMap::new().iter().cloned() {}
+ | -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here
+ | |
+ | this expression has type `HashMap<_, _>`
note: required by a bound in `cloned`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`
-error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| ------------------------ method `iter` not found for this struct
...
LL | println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
- | ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>`
+ | ^^^^ method not found in `Iterate<{integer}, [closure@issue-41880.rs:26:24]>`
error: aborting due to previous error
|
= help: the trait `Sized` is not implemented for `(dyn ToString + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | pub fn f(_: impl ToString) {}
+ | ~~~~
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | pub fn f(_: &dyn ToString) {}
|
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | r: impl A + 'static
+ | ~~~~
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | r: &dyn A + 'static
+use std::collections::hash_set::Iter;
+use std::collections::HashSet;
+
+fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+ let i = i.map(|x| x.clone());
+ i.collect() //~ ERROR E0277
+}
+
fn main() {
let scores = vec![(0, 0)]
.iter()
});
let f = e.filter(|_| false);
let g: Vec<i32> = f.collect(); //~ ERROR E0277
+
+ let mut s = HashSet::new();
+ s.insert(1u8);
+ println!("{:?}", iter_to_vec(s.iter()));
}
+error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X`
+ --> $DIR/invalid-iterator-chain.rs:6:7
+ |
+LL | i.collect()
+ | ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>`
+ |
+ = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>`
+ = help: the trait `FromIterator<T>` is implemented for `Vec<T>`
+note: the method call chain might not have had the expected associated types
+ --> $DIR/invalid-iterator-chain.rs:4:26
+ |
+LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> {
+ | ^^^^^^^^^^^ `Iterator::Item` is `&X` here
+LL | let i = i.map(|x| x.clone());
+ | ------------------ `Iterator::Item` remains `&X` here
+note: required by a bound in `collect`
+ --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
- --> $DIR/invalid-iterator-chain.rs:7:27
+ --> $DIR/invalid-iterator-chain.rs:15:27
|
LL | println!("{}", scores.sum::<i32>());
| ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:4:10
+ --> $DIR/invalid-iterator-chain.rs:12:10
|
LL | let scores = vec![(0, 0)]
| ------------ this expression has type `Vec<({integer}, {integer})>`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
- --> $DIR/invalid-iterator-chain.rs:18:14
+ --> $DIR/invalid-iterator-chain.rs:26:14
|
LL | .sum::<i32>(),
| ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:12:14
+ --> $DIR/invalid-iterator-chain.rs:20:14
|
LL | vec![0, 1]
| ---------- this expression has type `Vec<{integer}>`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64`
- --> $DIR/invalid-iterator-chain.rs:28:14
+ --> $DIR/invalid-iterator-chain.rs:36:14
|
LL | .sum::<i32>(),
| ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=f64>`
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:24:14
+ --> $DIR/invalid-iterator-chain.rs:32:14
|
LL | vec![0, 1]
| ---------- this expression has type `Vec<{integer}>`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()`
- --> $DIR/invalid-iterator-chain.rs:30:54
+ --> $DIR/invalid-iterator-chain.rs:38:54
|
LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
| ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>`
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:30:38
+ --> $DIR/invalid-iterator-chain.rs:38:38
|
LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>());
| ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()`
- --> $DIR/invalid-iterator-chain.rs:31:40
+ --> $DIR/invalid-iterator-chain.rs:39:40
|
LL | println!("{}", vec![(), ()].iter().sum::<i32>());
| ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=&()>`
<i32 as Sum<&'a i32>>
<i32 as Sum>
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:31:33
+ --> $DIR/invalid-iterator-chain.rs:39:33
|
LL | println!("{}", vec![(), ()].iter().sum::<i32>());
| ------------ ^^^^^^ `Iterator::Item` is `&()` here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()`
- --> $DIR/invalid-iterator-chain.rs:40:25
+ --> $DIR/invalid-iterator-chain.rs:48:25
|
LL | let g: Vec<i32> = f.collect();
| ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>`
= help: the trait `FromIterator<()>` is not implemented for `Vec<i32>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: the method call chain might not have had the expected associated types
- --> $DIR/invalid-iterator-chain.rs:36:15
+ --> $DIR/invalid-iterator-chain.rs:44:15
|
LL | let a = vec![0];
| ------- this expression has type `Vec<{integer}>`
note: required by a bound in `collect`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(auto_traits)]
+
+auto trait Foo {
+ fn g(&self); //~ ERROR auto traits cannot have associated items
+}
+
+trait Bar {
+ fn f(&self) {
+ self.g(); //~ ERROR the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0380]: auto traits cannot have associated items
+ --> $DIR/issue-105732.rs:4:8
+ |
+LL | auto trait Foo {
+ | --- auto trait cannot have associated items
+LL | fn g(&self);
+ | ---^-------- help: remove these associated items
+
+error[E0599]: the method `g` exists for reference `&Self`, but its trait bounds were not satisfied
+ --> $DIR/issue-105732.rs:9:14
+ |
+LL | self.g();
+ | ^
+ |
+ = note: the following trait bounds were not satisfied:
+ `Self: Foo`
+ which is required by `&Self: Foo`
+ `&Self: Foo`
+ = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `g`, perhaps you need to add a supertrait for it:
+ |
+LL | trait Bar: Foo {
+ | +++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0380, E0599.
+For more information about an error, try `rustc --explain E0380`.
--> $DIR/method-not-found-generic-arg-elision.rs:87:29
|
LL | v.iter().map(|x| x * x).extend(std::iter::once(100));
- | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>`
+ | ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>`
error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
--> $DIR/method-not-found-generic-arg-elision.rs:90:13
--- /dev/null
+// build-pass
+struct Inv<'a>(&'a mut &'a ());
+enum Foo<T> {
+ Bar,
+ Var(T),
+}
+type Supertype = Foo<for<'a> fn(Inv<'a>, Inv<'a>)>;
+
+fn foo(x: Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>) {
+ match x {
+ Supertype::Bar => {}
+ Supertype::Var(x) => {}
+ }
+}
+
+fn foo_nested(x: Foo<Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>>) {
+ match x {
+ Foo::Bar => {}
+ Foo::Var(Supertype::Bar) => {}
+ Foo::Var(Supertype::Var(x)) => {}
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+enum Foo<T> {
+ Var(T),
+} // `T` is covariant.
+
+fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
+ let Foo::Var(x): Foo<fn(&'b ())> = x;
+}
+
+fn foo_nested<'b>(x: Foo<Foo<for<'a> fn(&'a ())>>) {
+ let Foo::Var(Foo::Var(x)): Foo<Foo<fn(&'b ())>> = x;
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+struct Foo<T>(T); // `T` is covariant.
+
+struct Bar<T> {
+ x: T,
+} // `T` is covariant.
+
+fn bar<'b>(x: Bar<for<'a> fn(&'a ())>) {
+ let Bar { x }: Bar<fn(&'b ())> = x;
+}
+
+fn bar_nested<'b>(x: Bar<Bar<for<'a> fn(&'a ())>>) {
+ let Bar { x: Bar { x } }: Bar<Bar<fn(&'b ())>> = x;
+}
+
+fn bar_foo_nested<'b>(x: Bar<Foo<for<'a> fn(&'a ())>>) {
+ let Bar { x: Foo ( x ) }: Bar<Foo<fn(&'b ())>> = x;
+}
+
+fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
+ let Foo(y): Foo<fn(&'b ())> = x;
+}
+
+fn foo_nested<'b>(x: Foo<Foo<for<'a> fn(&'a ())>>) {
+ let Foo(Foo(y)): Foo<Foo<fn(&'b ())>> = x;
+}
+
+fn tuple<'b>(x: (u32, for<'a> fn(&'a ()))) {
+ let (_, y): (u32, fn(&'b ())) = x;
+}
+
+fn tuple_nested<'b>(x: (u32, (u32, for<'a> fn(&'a ())))) {
+ let (_, (_, y)): (u32, (u32, fn(&'b ()))) = x;
+}
+
+fn main() {}
note: required by a bound in `filter`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
+error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
--> $DIR/issue-36053-2.rs:7:55
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
-error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
+error[E0271]: expected `[closure@fallback-closure-wrap.rs:18:40]` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {
|
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | fn foo(_x: impl K) {}
+ | ++++
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | fn foo(_x: &K) {}
--- /dev/null
+// check-pass
+#![allow(incomplete_features)]
+#![feature(
+ associated_type_bounds,
+ const_trait_impl,
+ const_cmp,
+ return_position_impl_trait_in_trait,
+)]
+
+use std::marker::Destruct;
+
+const fn cmp(a: &impl ~const PartialEq) -> bool {
+ a == a
+}
+
+const fn wrap(x: impl ~const PartialEq + ~const Destruct)
+ -> impl ~const PartialEq + ~const Destruct
+{
+ x
+}
+
+#[const_trait]
+trait Foo {
+ fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+}
+
+impl const Foo for () {
+ fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+ 123
+ }
+}
+
+const _: () = {
+ assert!(cmp(&0xDEADBEEFu32));
+ assert!(cmp(&()));
+ assert!(wrap(123) == wrap(123));
+ assert!(wrap(123) != wrap(456));
+ let x = <() as Foo>::huh();
+ assert!(x == x);
+};
+
+#[const_trait]
+trait T {}
+struct S;
+impl const T for S {}
+
+const fn rpit() -> impl ~const T { S }
+
+const fn apit(_: impl ~const T + ~const Destruct) {}
+
+const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
+
+const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
+
+fn main() {}
#![feature(const_trait_impl)]
#![feature(associated_type_bounds)]
-#[const_trait]
-trait T {}
-struct S;
-impl T for S {}
-
-fn rpit() -> impl ~const T { S }
-//~^ ERROR `~const` is not allowed
-
-fn apit(_: impl ~const T) {}
-//~^ ERROR `~const` is not allowed
-
-fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
-//~^ ERROR `~const` is not allowed
-
-fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
-//~^ ERROR `~const` is not allowed
-
struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
//~^ ERROR `~const` and `?` are mutually exclusive
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:9:19
- |
-LL | fn rpit() -> impl ~const T { S }
- | ^^^^^^^^
- |
- = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:12:17
- |
-LL | fn apit(_: impl ~const T) {}
- | ^^^^^^^^
- |
- = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:15:50
- |
-LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
- | ^^^^^^^^
- |
- = note: `impl Trait`s cannot have `~const` trait bounds
-
-error: `~const` is not allowed here
- --> $DIR/tilde-const-invalid-places.rs:18:48
- |
-LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
- | ^^^^^^^^
- |
- = note: `impl Trait`s cannot have `~const` trait bounds
-
error: `~const` and `?` are mutually exclusive
- --> $DIR/tilde-const-invalid-places.rs:21:25
+ --> $DIR/tilde-const-invalid-places.rs:4:25
|
LL | struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
| ^^^^^^^^^^^^^
-error: aborting due to 5 previous errors
+error: aborting due to previous error
--- /dev/null
+// run-rustfix
+fn wat<T: Clone>(t: &T) -> T {
+ t.clone() //~ ERROR E0308
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+ t.clone() //~ ERROR E0308
+}
+
+fn main() {
+ wat(&42);
+ wut(&Foo);
+}
--- /dev/null
+// run-rustfix
+fn wat<T>(t: &T) -> T {
+ t.clone() //~ ERROR E0308
+}
+
+struct Foo;
+
+fn wut(t: &Foo) -> Foo {
+ t.clone() //~ ERROR E0308
+}
+
+fn main() {
+ wat(&42);
+ wut(&Foo);
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+ |
+LL | fn wat<T>(t: &T) -> T {
+ | - - expected `T` because of return type
+ | |
+ | this type parameter
+LL | t.clone()
+ | ^^^^^^^^^ expected type parameter `T`, found `&T`
+ |
+ = note: expected type parameter `T`
+ found reference `&T`
+note: `T` does not implement `Clone`, so `&T` was cloned instead
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
+ |
+LL | t.clone()
+ | ^
+help: consider restricting type parameter `T`
+ |
+LL | fn wat<T: Clone>(t: &T) -> T {
+ | +++++++
+
+error[E0308]: mismatched types
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+ |
+LL | fn wut(t: &Foo) -> Foo {
+ | --- expected `Foo` because of return type
+LL | t.clone()
+ | ^^^^^^^^^ expected struct `Foo`, found `&Foo`
+ |
+note: `Foo` does not implement `Clone`, so `&Foo` was cloned instead
+ --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:9:5
+ |
+LL | t.clone()
+ | ^
+help: consider annotating `Foo` with `#[derive(Clone)]`
+ |
+LL | #[derive(Clone)]
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+trait Bar {}
+
+trait Foo {
+ fn f() {}
+}
+
+impl Foo for dyn Bar {}
+
+fn main() {
+ Foo::f();
+ //~^ ERROR cannot call associated function on trait without specifying the corresponding `impl` type
+}
--- /dev/null
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+ --> $DIR/issue-104327.rs:10:5
+ |
+LL | fn f() {}
+ | --------- `Foo::f` defined here
+...
+LL | Foo::f();
+ | ^^^^^^ cannot call associated function of trait
+ |
+help: use the fully-qualified path to the only available implementation
+ |
+LL | <(dyn Bar + 'static) as Foo>::f();
+ | +++++++++++++++++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0790`.
--- /dev/null
+#![feature(object_safe_for_dispatch)]
+
+trait Foo {
+ fn f() {}
+}
+
+impl Foo for dyn Sized {}
+
+fn main() {
+ Foo::f();
+ //~^ ERROR cannot call associated function on trait without specifying the corresponding `impl` type
+}
--- /dev/null
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+ --> $DIR/issue-104328.rs:10:5
+ |
+LL | fn f() {}
+ | --------- `Foo::f` defined here
+...
+LL | Foo::f();
+ | ^^^^^^ cannot call associated function of trait
+ |
+help: use the fully-qualified path to the only available implementation
+ |
+LL | <(dyn Sized + 'static) as Foo>::f();
+ | +++++++++++++++++++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0790`.
note: required by a bound in `BufWriter`
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
-error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
+error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied
--> $DIR/mut-borrow-needed-by-trait.rs:21:5
|
LL | writeln!(fp, "hello world").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds
--> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
|
= note: doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
impl Foo for IntoIter<i32> {
type Key = u32;
- //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+ //~^ ERROR expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
}
fn main() {}
-error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
+error[E0271]: expected `IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
--> $DIR/assoc-type-in-superbad.rs:12:16
|
LL | type Key = u32;
|
= help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
= help: unsized fn params are gated as an unstable feature
+help: you can use `impl Trait` as the argument type
+ |
+LL | fn foo(_x: impl Foo + Send) {
+ | ++++
help: function arguments must have a statically known size, borrowed types always have a known size
|
LL | fn foo(_x: &Foo + Send) {
|
help: use the fully-qualified path to the only available implementation
|
-LL | let _f: base::Foo = base::<Foo as HasNew>::new();
- | +++++++ +
+LL | let _f: base::Foo = <Foo as base::HasNew>::new();
+ | +++++++ +
error: aborting due to previous error
impl Foo for () {
type Bar = std::vec::IntoIter<u32>;
- //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+ //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
}
fn incoherent() {
-error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
+error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
--> $DIR/issue-57961.rs:10:16
|
LL | type X = impl Sized;
|
LL | nc.clone()
| ^^
+help: consider annotating `NotClone` with `#[derive(Clone)]`
+ |
+LL | #[derive(Clone)]
+ |
error: aborting due to previous error
-error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]` in the current scope
--> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
|
LL | mut_.call((0, ));
- | ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
+ | ^^^^ method not found in `[closure@unboxed-closures-static-call-wrong-trait.rs:6:26]`
error: aborting due to previous error
use rustc_middle::ty as rustc_ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
+use rustc_middle::ty::fast_reject::SimplifiedType::{
ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
};
};
use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Symbol;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Size, Align};
use rustc_target::spec::abi::Abi;
+use rustc_const_eval::const_eval::CheckAlignment;
use crate::{
concurrency::{data_race, weak_memory},
const PANIC_ON_ALLOC_FAIL: bool = false;
#[inline(always)]
- fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
- ecx.machine.check_alignment != AlignmentCheck::None
+ fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
+ if ecx.machine.check_alignment == AlignmentCheck::None {
+ CheckAlignment::No
+ } else {
+ CheckAlignment::Error
+ }
}
#[inline(always)]
ecx.machine.check_alignment == AlignmentCheck::Int
}
+ fn alignment_check_failed(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ has: Align,
+ required: Align,
+ _check: CheckAlignment,
+ ) -> InterpResult<'tcx, ()> {
+ throw_ub!(AlignmentCheckFailed { has, required })
+ }
+
#[inline(always)]
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.validate