Auto merge of #143667 - tgross35:rollup-yqitltm, r=tgross35
Rollup of 9 pull requests Successful merges: - rust-lang/rust#142357 (Simplify LLVM bitcode linker in bootstrap and add tests for it) - rust-lang/rust#143177 (Remove false label when `self` resolve failure does not relate to macro) - rust-lang/rust#143339 (Respect endianness correctly in CheckEnums test suite) - rust-lang/rust#143426 (clippy fix: indentation) - rust-lang/rust#143475 (tests: Use `cfg_target_has_reliable_f16_f128` in `conv-bits-runtime-const`) - rust-lang/rust#143499 (Don't call `predicates_of` on a dummy obligation cause's body id) - rust-lang/rust#143520 (Fix perf regression caused by tracing) - rust-lang/rust#143532 (More carefully consider span context when suggesting remove `&mut`) - rust-lang/rust#143606 (configure.py: Write last key in each section) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
558d25371f
48 changed files with 347 additions and 169 deletions
|
|
@ -96,7 +96,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
/// This inherent method takes priority over the trait method with the same name in LayoutOf,
|
||||
/// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span.
|
||||
/// See [LayoutOf::layout_of] for the original documentation.
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn layout_of(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use rustc_target::callconv::FnAbi;
|
|||
|
||||
use super::{
|
||||
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation,
|
||||
CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind,
|
||||
Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup,
|
||||
CtfeProvenance, EnteredTraceSpan, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy,
|
||||
MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup,
|
||||
};
|
||||
|
||||
/// Data returned by [`Machine::after_stack_pop`], and consumed by
|
||||
|
|
@ -147,12 +147,6 @@ pub trait Machine<'tcx>: Sized {
|
|||
/// already been checked before.
|
||||
const ALL_CONSTS_ARE_PRECHECKED: bool = true;
|
||||
|
||||
/// Determines whether rustc_const_eval functions that make use of the [Machine] should make
|
||||
/// tracing calls (to the `tracing` library). By default this is `false`, meaning the tracing
|
||||
/// calls will supposedly be optimized out. This flag is set to `true` inside Miri, to allow
|
||||
/// tracing the interpretation steps, among other things.
|
||||
const TRACING_ENABLED: bool = false;
|
||||
|
||||
/// Whether memory accesses should be alignment-checked.
|
||||
fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool;
|
||||
|
||||
|
|
@ -634,6 +628,17 @@ pub trait Machine<'tcx>: Sized {
|
|||
/// Compute the value passed to the constructors of the `AllocBytes` type for
|
||||
/// abstract machine allocations.
|
||||
fn get_default_alloc_params(&self) -> <Self::Bytes as AllocBytes>::AllocParams;
|
||||
|
||||
/// Allows enabling/disabling tracing calls from within `rustc_const_eval` at compile time, by
|
||||
/// delegating the entering of [tracing::Span]s to implementors of the [Machine] trait. The
|
||||
/// default implementation corresponds to tracing being disabled, meaning the tracing calls will
|
||||
/// supposedly be optimized out completely. To enable tracing, override this trait method and
|
||||
/// return `span.entered()`. Also see [crate::enter_trace_span].
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
fn enter_trace_span(_span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
|
|||
use self::place::{MemPlace, Place};
|
||||
pub use self::projection::{OffsetMode, Projectable};
|
||||
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation, StackPopInfo};
|
||||
pub use self::util::EnteredTraceSpan;
|
||||
pub(crate) use self::util::create_static_alloc;
|
||||
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
||||
pub use self::visitor::ValueVisitor;
|
||||
|
|
|
|||
|
|
@ -46,21 +46,20 @@ pub(crate) fn create_static_alloc<'tcx>(
|
|||
interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
|
||||
}
|
||||
|
||||
/// This struct is needed to enforce `#[must_use]` on [tracing::span::EnteredSpan]
|
||||
/// while wrapping them in an `Option`.
|
||||
#[must_use]
|
||||
pub enum MaybeEnteredSpan {
|
||||
Some(tracing::span::EnteredSpan),
|
||||
None,
|
||||
}
|
||||
/// A marker trait returned by [crate::interpret::Machine::enter_trace_span], identifying either a
|
||||
/// real [tracing::span::EnteredSpan] in case tracing is enabled, or the dummy type `()` when
|
||||
/// tracing is disabled.
|
||||
pub trait EnteredTraceSpan {}
|
||||
impl EnteredTraceSpan for () {}
|
||||
impl EnteredTraceSpan for tracing::span::EnteredSpan {}
|
||||
|
||||
/// Shortand for calling [crate::interpret::Machine::enter_trace_span] on a [tracing::info_span].
|
||||
/// This is supposed to be compiled out when [crate::interpret::Machine::enter_trace_span] has the
|
||||
/// default implementation (i.e. when it does not actually enter the span but instead returns `()`).
|
||||
/// Note: the result of this macro **must be used** because the span is exited when it's dropped.
|
||||
#[macro_export]
|
||||
macro_rules! enter_trace_span {
|
||||
($machine:ident, $($tt:tt)*) => {
|
||||
if $machine::TRACING_ENABLED {
|
||||
$crate::interpret::util::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
|
||||
} else {
|
||||
$crate::interpret::util::MaybeEnteredSpan::None
|
||||
}
|
||||
$machine::enter_trace_span(|| tracing::info_span!($($tt)*))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1183,15 +1183,23 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
_ => "`self` value is a keyword only available in methods with a `self` parameter",
|
||||
},
|
||||
);
|
||||
|
||||
// using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion.
|
||||
// So, we should return early if we're in a pattern, see issue #143134.
|
||||
if matches!(source, PathSource::Pat) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let is_assoc_fn = self.self_type_is_available();
|
||||
let self_from_macro = "a `self` parameter, but a macro invocation can only \
|
||||
access identifiers it receives from parameters";
|
||||
if let Some((fn_kind, span)) = &self.diag_metadata.current_function {
|
||||
if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function {
|
||||
// The current function has a `self` parameter, but we were unable to resolve
|
||||
// a reference to `self`. This can only happen if the `self` identifier we
|
||||
// are resolving came from a different hygiene context.
|
||||
// are resolving came from a different hygiene context or a variable binding.
|
||||
// But variable binding error is returned early above.
|
||||
if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
|
||||
err.span_label(*span, format!("this function has {self_from_macro}"));
|
||||
err.span_label(*fn_span, format!("this function has {self_from_macro}"));
|
||||
} else {
|
||||
let doesnt = if is_assoc_fn {
|
||||
let (span, sugg) = fn_kind
|
||||
|
|
@ -1204,7 +1212,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
// This avoids placing the suggestion into the visibility specifier.
|
||||
let span = fn_kind
|
||||
.ident()
|
||||
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
|
||||
.map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi()));
|
||||
(
|
||||
self.r
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_s
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
|
||||
use rustc_hir::intravisit::Visitor as _;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
|
||||
use rustc_infer::traits::util::elaborate;
|
||||
|
|
@ -128,19 +128,26 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
|
|||
},
|
||||
);
|
||||
|
||||
let predicates =
|
||||
tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
|
||||
for (pred, span) in elaborate(tcx, predicates.into_iter()) {
|
||||
let kind = pred.kind();
|
||||
if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
|
||||
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
|
||||
{
|
||||
if kind.rebind(trait_pred.trait_ref)
|
||||
== ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
|
||||
// If our `body_id` has been set (and isn't just from a dummy obligation cause),
|
||||
// then try to look for a param-env clause that would apply. The way we compute
|
||||
// this is somewhat manual, since we need the spans, so we elaborate this directly
|
||||
// from `predicates_of` rather than actually looking at the param-env which
|
||||
// otherwise would be more appropriate.
|
||||
let body_id = obligation.cause.body_id;
|
||||
if body_id != CRATE_DEF_ID {
|
||||
let predicates = tcx.predicates_of(body_id.to_def_id()).instantiate_identity(tcx);
|
||||
for (pred, span) in elaborate(tcx, predicates.into_iter()) {
|
||||
let kind = pred.kind();
|
||||
if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
|
||||
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
|
||||
{
|
||||
ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
|
||||
} else {
|
||||
ambiguities.push(CandidateSource::ParamEnv(span))
|
||||
if kind.rebind(trait_pred.trait_ref)
|
||||
== ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
|
||||
{
|
||||
ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
|
||||
} else {
|
||||
ambiguities.push(CandidateSource::ParamEnv(span))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1581,12 +1581,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
'outer: loop {
|
||||
while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
|
||||
count += 1;
|
||||
let span = if expr.span.eq_ctxt(borrowed.span) {
|
||||
expr.span.until(borrowed.span)
|
||||
} else {
|
||||
expr.span.with_hi(expr.span.lo() + BytePos(1))
|
||||
};
|
||||
let span =
|
||||
if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) {
|
||||
expr.span.until(borrowed_span)
|
||||
} else {
|
||||
break 'outer;
|
||||
};
|
||||
|
||||
// Double check that the span we extracted actually corresponds to a borrow,
|
||||
// rather than some macro garbage.
|
||||
match self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
Ok(snippet) if snippet.starts_with("&") => {}
|
||||
_ => break 'outer,
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ impl Layout {
|
|||
/// * `align` must be a power of two,
|
||||
///
|
||||
/// * `size`, when rounded up to the nearest multiple of `align`,
|
||||
/// must not overflow `isize` (i.e., the rounded value must be
|
||||
/// less than or equal to `isize::MAX`).
|
||||
/// must not overflow `isize` (i.e., the rounded value must be
|
||||
/// less than or equal to `isize::MAX`).
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1940,21 +1940,21 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
|||
/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
|
||||
///
|
||||
/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference), then
|
||||
/// you must not access the data in any way that contradicts that reference for the remainder of
|
||||
/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell<T>` and cast it
|
||||
/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found
|
||||
/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a `&mut
|
||||
/// T` reference that is released to safe code, then you must not access the data within the
|
||||
/// `UnsafeCell` until that reference expires.
|
||||
/// you must not access the data in any way that contradicts that reference for the remainder of
|
||||
/// `'a`. For example, this means that if you take the `*mut T` from an `UnsafeCell<T>` and cast it
|
||||
/// to an `&T`, then the data in `T` must remain immutable (modulo any `UnsafeCell` data found
|
||||
/// within `T`, of course) until that reference's lifetime expires. Similarly, if you create a
|
||||
/// `&mut T` reference that is released to safe code, then you must not access the data within the
|
||||
/// `UnsafeCell` until that reference expires.
|
||||
///
|
||||
/// - For both `&T` without `UnsafeCell<_>` and `&mut T`, you must also not deallocate the data
|
||||
/// until the reference expires. As a special exception, given an `&T`, any part of it that is
|
||||
/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the
|
||||
/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part
|
||||
/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if
|
||||
/// *every part of it* (including padding) is inside an `UnsafeCell`.
|
||||
/// until the reference expires. As a special exception, given an `&T`, any part of it that is
|
||||
/// inside an `UnsafeCell<_>` may be deallocated during the lifetime of the reference, after the
|
||||
/// last time the reference is used (dereferenced or reborrowed). Since you cannot deallocate a part
|
||||
/// of what a reference points to, this means the memory an `&T` points to can be deallocated only if
|
||||
/// *every part of it* (including padding) is inside an `UnsafeCell`.
|
||||
///
|
||||
/// However, whenever a `&UnsafeCell<T>` is constructed or dereferenced, it must still point to
|
||||
/// However, whenever a `&UnsafeCell<T>` is constructed or dereferenced, it must still point to
|
||||
/// live memory and the compiler is allowed to insert spurious reads if it can prove that this
|
||||
/// memory has not yet been deallocated.
|
||||
///
|
||||
|
|
@ -1962,10 +1962,10 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
|||
/// for single-threaded code:
|
||||
///
|
||||
/// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T`
|
||||
/// references, but not with a `&mut T`
|
||||
/// references, but not with a `&mut T`
|
||||
///
|
||||
/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T`
|
||||
/// co-exist with it. A `&mut T` must always be unique.
|
||||
/// co-exist with it. A `&mut T` must always be unique.
|
||||
///
|
||||
/// Note that whilst mutating the contents of an `&UnsafeCell<T>` (even while other
|
||||
/// `&UnsafeCell<T>` references alias the cell) is
|
||||
|
|
|
|||
|
|
@ -447,28 +447,28 @@ where
|
|||
/// separated by API boundaries:
|
||||
///
|
||||
/// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers
|
||||
/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`.
|
||||
/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`.
|
||||
///
|
||||
/// * Producer - the producer provides objects when requested via Request; eg. a library with an
|
||||
/// an `Error` implementation that automatically captures backtraces at the time instances are
|
||||
/// created.
|
||||
/// an `Error` implementation that automatically captures backtraces at the time instances are
|
||||
/// created.
|
||||
///
|
||||
/// The consumer only needs to know where to submit their request and are expected to handle the
|
||||
/// request not being fulfilled by the use of `Option<T>` in the responses offered by the producer.
|
||||
///
|
||||
/// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise
|
||||
/// prepared to generate a value requested). eg, `backtrace::Backtrace` or
|
||||
/// `std::backtrace::Backtrace`
|
||||
/// prepared to generate a value requested). eg, `backtrace::Backtrace` or
|
||||
/// `std::backtrace::Backtrace`
|
||||
/// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace`). In the
|
||||
/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and
|
||||
/// `request_value` to simplify obtaining an `Option<T>` for a given type.
|
||||
/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and
|
||||
/// `request_value` to simplify obtaining an `Option<T>` for a given type.
|
||||
/// * The Producer, when requested, populates the given Request object which is given as a mutable
|
||||
/// reference.
|
||||
/// reference.
|
||||
/// * The Consumer extracts a value or reference to the requested type from the `Request` object
|
||||
/// wrapped in an `Option<T>`; in the case of `dyn Error` the aforementioned `request_ref` and `
|
||||
/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at
|
||||
/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the
|
||||
/// Producer cannot currently offer an instance of the requested type, not it can't or never will.
|
||||
/// wrapped in an `Option<T>`; in the case of `dyn Error` the aforementioned `request_ref` and `
|
||||
/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at
|
||||
/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the
|
||||
/// Producer cannot currently offer an instance of the requested type, not it can't or never will.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -353,10 +353,10 @@ impl FormattingOptions {
|
|||
/// Sets or removes the sign (the `+` or the `-` flag).
|
||||
///
|
||||
/// - `+`: This is intended for numeric types and indicates that the sign
|
||||
/// should always be printed. By default only the negative sign of signed
|
||||
/// values is printed, and the sign of positive or unsigned values is
|
||||
/// omitted. This flag indicates that the correct sign (+ or -) should
|
||||
/// always be printed.
|
||||
/// should always be printed. By default only the negative sign of signed
|
||||
/// values is printed, and the sign of positive or unsigned values is
|
||||
/// omitted. This flag indicates that the correct sign (+ or -) should
|
||||
/// always be printed.
|
||||
/// - `-`: Currently not used
|
||||
#[unstable(feature = "formatting_options", issue = "118117")]
|
||||
pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self {
|
||||
|
|
@ -443,9 +443,9 @@ impl FormattingOptions {
|
|||
/// Sets or removes the precision.
|
||||
///
|
||||
/// - For non-numeric types, this can be considered a “maximum width”. If
|
||||
/// the resulting string is longer than this width, then it is truncated
|
||||
/// down to this many characters and that truncated value is emitted with
|
||||
/// proper fill, alignment and width if those parameters are set.
|
||||
/// the resulting string is longer than this width, then it is truncated
|
||||
/// down to this many characters and that truncated value is emitted with
|
||||
/// proper fill, alignment and width if those parameters are set.
|
||||
/// - For integral types, this is ignored.
|
||||
/// - For floating-point types, this indicates how many digits after the
|
||||
/// decimal point should be printed.
|
||||
|
|
|
|||
|
|
@ -211,8 +211,8 @@ pub trait PointeeSized {
|
|||
/// - The type is sized.
|
||||
/// - The type outlives `'a`.
|
||||
/// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize<Foo<..., U1, ..., Un, ...>>`
|
||||
/// where any number of (type and const) parameters may be changed if all of these conditions
|
||||
/// are met:
|
||||
/// where any number of (type and const) parameters may be changed if all of these conditions
|
||||
/// are met:
|
||||
/// - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`.
|
||||
/// - All other parameters of the struct are equal.
|
||||
/// - `Field<T1, ..., Tn>: Unsize<Field<U1, ..., Un>>`, where `Field<...>` stands for the actual
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
/// This destructor consists of two components:
|
||||
/// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type.
|
||||
/// - The automatically generated "drop glue" which recursively calls the destructors
|
||||
/// of all the fields of this value.
|
||||
/// of all the fields of this value.
|
||||
///
|
||||
/// As Rust automatically calls the destructors of all contained fields,
|
||||
/// you don't have to implement `Drop` in most cases. But there are some cases where
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@
|
|||
//! `Option::<T>::None`
|
||||
//! - `transmute::<_, [u8; size_of::<T>()]>(Option::<T>::None)` is sound and produces
|
||||
//! `[0u8; size_of::<T>()]`
|
||||
//!
|
||||
//! These cases are identified by the second column:
|
||||
//!
|
||||
//! | `T` | Transmuting between `[0u8; size_of::<T>()]` and `Option::<T>::None` sound? |
|
||||
|
|
|
|||
|
|
@ -137,10 +137,10 @@
|
|||
//! 2. An operation causes the value to depend on its own address not changing
|
||||
//! * e.g. calling [`poll`] for the first time on the produced [`Future`]
|
||||
//! 3. Further pieces of the safe interface of the type use internal [`unsafe`] operations which
|
||||
//! assume that the address of the value is stable
|
||||
//! assume that the address of the value is stable
|
||||
//! * e.g. subsequent calls to [`poll`]
|
||||
//! 4. Before the value is invalidated (e.g. deallocated), it is *dropped*, giving it a chance to
|
||||
//! notify anything with pointers to itself that those pointers will be invalidated
|
||||
//! notify anything with pointers to itself that those pointers will be invalidated
|
||||
//! * e.g. [`drop`]ping the [`Future`] [^pin-drop-future]
|
||||
//!
|
||||
//! There are two possible ways to ensure the invariants required for 2. and 3. above (which
|
||||
|
|
@ -148,8 +148,8 @@
|
|||
//!
|
||||
//! 1. Have the value detect when it is moved and update all the pointers that point to itself.
|
||||
//! 2. Guarantee that the address of the value does not change (and that memory is not re-used
|
||||
//! for anything else) during the time that the pointers to it are expected to be valid to
|
||||
//! dereference.
|
||||
//! for anything else) during the time that the pointers to it are expected to be valid to
|
||||
//! dereference.
|
||||
//!
|
||||
//! Since, as we discussed, Rust can move values without notifying them that they have moved, the
|
||||
//! first option is ruled out.
|
||||
|
|
@ -160,11 +160,11 @@
|
|||
//! be able to enforce this invariant in Rust:
|
||||
//!
|
||||
//! 1. Offer a wholly `unsafe` API to interact with the object, thus requiring every caller to
|
||||
//! uphold the invariant themselves
|
||||
//! uphold the invariant themselves
|
||||
//! 2. Store the value that must not be moved behind a carefully managed pointer internal to
|
||||
//! the object
|
||||
//! the object
|
||||
//! 3. Leverage the type system to encode and enforce this invariant by presenting a restricted
|
||||
//! API surface to interact with *any* object that requires these invariants
|
||||
//! API surface to interact with *any* object that requires these invariants
|
||||
//!
|
||||
//! The first option is quite obviously undesirable, as the [`unsafe`]ty of the interface will
|
||||
//! become viral throughout all code that interacts with the object.
|
||||
|
|
@ -530,7 +530,7 @@
|
|||
//! but it also implies that,
|
||||
//!
|
||||
//! 2. The memory location that stores the value must not get invalidated or otherwise repurposed
|
||||
//! during the lifespan of the pinned value until its [`drop`] returns or panics
|
||||
//! during the lifespan of the pinned value until its [`drop`] returns or panics
|
||||
//!
|
||||
//! This point is subtle but required for intrusive data structures to be implemented soundly.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -739,19 +739,29 @@ def configure_file(sections, top_level_keys, targets, config):
|
|||
|
||||
|
||||
def write_uncommented(target, f):
|
||||
"""Writes each block in 'target' that is not composed entirely of comments to 'f'.
|
||||
|
||||
A block is a sequence of non-empty lines separated by empty lines.
|
||||
"""
|
||||
block = []
|
||||
is_comment = True
|
||||
|
||||
def flush(last):
|
||||
# If the block is entirely made of comments, ignore it
|
||||
entire_block_comments = all(ln.startswith("#") or ln == "" for ln in block)
|
||||
if not entire_block_comments and len(block) > 0:
|
||||
for line in block:
|
||||
f.write(line + "\n")
|
||||
# Required to output a newline before the start of a new section
|
||||
if last:
|
||||
f.write("\n")
|
||||
block.clear()
|
||||
|
||||
for line in target:
|
||||
block.append(line)
|
||||
if len(line) == 0:
|
||||
if not is_comment:
|
||||
for ln in block:
|
||||
f.write(ln + "\n")
|
||||
block = []
|
||||
is_comment = True
|
||||
continue
|
||||
is_comment = is_comment and line.startswith("#")
|
||||
flush(last=False)
|
||||
|
||||
flush(last=True)
|
||||
return f
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2057,14 +2057,20 @@ impl Step for Assemble {
|
|||
trace!("llvm-bitcode-linker enabled, installing");
|
||||
let llvm_bitcode_linker =
|
||||
builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker {
|
||||
compiler,
|
||||
build_compiler: compiler,
|
||||
target: target_compiler.host,
|
||||
extra_features: vec![],
|
||||
});
|
||||
|
||||
// Copy the llvm-bitcode-linker to the self-contained binary directory
|
||||
let bindir_self_contained = builder
|
||||
.sysroot(compiler)
|
||||
.join(format!("lib/rustlib/{}/bin/self-contained", compiler.host));
|
||||
let tool_exe = exe("llvm-bitcode-linker", target_compiler.host);
|
||||
|
||||
t!(fs::create_dir_all(&bindir_self_contained));
|
||||
builder.copy_link(
|
||||
&llvm_bitcode_linker.tool_path,
|
||||
&libdir_bin.join(tool_exe),
|
||||
&bindir_self_contained.join(tool_exe),
|
||||
FileType::Executable,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2375,7 +2375,7 @@ impl Step for LlvmBitcodeLinker {
|
|||
builder.ensure(compile::Rustc::new(compiler, target));
|
||||
|
||||
let llbc_linker =
|
||||
builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] });
|
||||
builder.ensure(tool::LlvmBitcodeLinker { build_compiler: compiler, target });
|
||||
|
||||
let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
|
||||
|
||||
|
|
|
|||
|
|
@ -910,6 +910,13 @@ impl Step for LldWrapper {
|
|||
|
||||
tool_result
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Option<StepMetadata> {
|
||||
Some(
|
||||
StepMetadata::build("LldWrapper", self.target_compiler.host)
|
||||
.built_by(self.build_compiler),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
|
|
@ -1014,9 +1021,8 @@ impl Step for RustAnalyzerProcMacroSrv {
|
|||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct LlvmBitcodeLinker {
|
||||
pub compiler: Compiler,
|
||||
pub build_compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
pub extra_features: Vec<String>,
|
||||
}
|
||||
|
||||
impl Step for LlvmBitcodeLinker {
|
||||
|
|
@ -1032,8 +1038,9 @@ impl Step for LlvmBitcodeLinker {
|
|||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(LlvmBitcodeLinker {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
|
||||
extra_features: Vec::new(),
|
||||
build_compiler: run
|
||||
.builder
|
||||
.compiler(run.builder.top_stage, run.builder.config.host_target),
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
|
@ -1043,35 +1050,22 @@ impl Step for LlvmBitcodeLinker {
|
|||
instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all)
|
||||
)]
|
||||
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
|
||||
let tool_result = builder.ensure(ToolBuild {
|
||||
compiler: self.compiler,
|
||||
builder.ensure(ToolBuild {
|
||||
compiler: self.build_compiler,
|
||||
target: self.target,
|
||||
tool: "llvm-bitcode-linker",
|
||||
mode: Mode::ToolRustc,
|
||||
path: "src/tools/llvm-bitcode-linker",
|
||||
source_type: SourceType::InTree,
|
||||
extra_features: self.extra_features,
|
||||
extra_features: vec![],
|
||||
allow_features: "",
|
||||
cargo_args: Vec::new(),
|
||||
artifact_kind: ToolArtifactKind::Binary,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if tool_result.target_compiler.stage > 0 {
|
||||
let bindir_self_contained = builder
|
||||
.sysroot(tool_result.target_compiler)
|
||||
.join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple));
|
||||
t!(fs::create_dir_all(&bindir_self_contained));
|
||||
let bin_destination = bindir_self_contained
|
||||
.join(exe("llvm-bitcode-linker", tool_result.target_compiler.host));
|
||||
builder.copy_link(&tool_result.tool_path, &bin_destination, FileType::Executable);
|
||||
ToolBuildResult {
|
||||
tool_path: bin_destination,
|
||||
build_compiler: tool_result.build_compiler,
|
||||
target_compiler: tool_result.target_compiler,
|
||||
}
|
||||
} else {
|
||||
tool_result
|
||||
}
|
||||
fn metadata(&self) -> Option<StepMetadata> {
|
||||
Some(StepMetadata::build("LlvmBitcodeLinker", self.target).built_by(self.build_compiler))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -757,6 +757,58 @@ mod snapshot {
|
|||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_compiler_tools() {
|
||||
let ctx = TestCtx::new();
|
||||
insta::assert_snapshot!(
|
||||
ctx
|
||||
.config("build")
|
||||
.stage(2)
|
||||
.args(&["--set", "rust.lld=true", "--set", "rust.llvm-bitcode-linker=true"])
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustc 0 <host> -> LldWrapper 1 <host>
|
||||
[build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
|
||||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustc 1 <host> -> LldWrapper 2 <host>
|
||||
[build] rustc 2 <host> -> LlvmBitcodeLinker 3 <host>
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_compiler_tools_cross() {
|
||||
let ctx = TestCtx::new();
|
||||
insta::assert_snapshot!(
|
||||
ctx
|
||||
.config("build")
|
||||
.stage(2)
|
||||
.args(&["--set", "rust.lld=true", "--set", "rust.llvm-bitcode-linker=true"])
|
||||
.hosts(&[TEST_TRIPLE_1])
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustc 0 <host> -> LldWrapper 1 <host>
|
||||
[build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
|
||||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustc 1 <host> -> LldWrapper 2 <host>
|
||||
[build] rustc 2 <host> -> LlvmBitcodeLinker 3 <host>
|
||||
[build] rustc 1 <host> -> std 1 <target1>
|
||||
[build] rustc 2 <host> -> std 2 <target1>
|
||||
[build] llvm <target1>
|
||||
[build] rustc 1 <host> -> rustc 2 <target1>
|
||||
[build] rustc 1 <host> -> LldWrapper 2 <target1>
|
||||
[build] rustc 2 <target1> -> LlvmBitcodeLinker 3 <target1>
|
||||
[build] rustdoc 1 <target1>
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_library_no_explicit_stage() {
|
||||
let ctx = TestCtx::new();
|
||||
|
|
@ -1040,6 +1092,7 @@ mod snapshot {
|
|||
[build] rustc 0 <host> -> cargo-clippy 1 <host>
|
||||
[build] rustc 0 <host> -> miri 1 <host>
|
||||
[build] rustc 0 <host> -> cargo-miri 1 <host>
|
||||
[build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
|
||||
");
|
||||
}
|
||||
|
||||
|
|
@ -1230,6 +1283,7 @@ mod snapshot {
|
|||
[build] rustc 0 <host> -> cargo-clippy 1 <target1>
|
||||
[build] rustc 0 <host> -> miri 1 <target1>
|
||||
[build] rustc 0 <host> -> cargo-miri 1 <target1>
|
||||
[build] rustc 1 <host> -> LlvmBitcodeLinker 2 <target1>
|
||||
");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,8 +96,6 @@ impl ConfigBuilder {
|
|||
// in-tree LLVM from sources.
|
||||
self.args.push("--set".to_string());
|
||||
self.args.push("llvm.download-ci-llvm=false".to_string());
|
||||
self.args.push("--set".to_string());
|
||||
self.args.push(format!("target.'{}'.llvm-config=false", get_host_target()));
|
||||
|
||||
// Do not mess with the local rustc checkout build directory
|
||||
self.args.push("--build-dir".to_string());
|
||||
|
|
|
|||
|
|
@ -1014,8 +1014,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
|
||||
const PANIC_ON_ALLOC_FAIL: bool = false;
|
||||
|
||||
const TRACING_ENABLED: bool = cfg!(feature = "tracing");
|
||||
|
||||
#[inline(always)]
|
||||
fn enforce_alignment(ecx: &MiriInterpCx<'tcx>) -> bool {
|
||||
ecx.machine.check_alignment != AlignmentCheck::None
|
||||
|
|
@ -1827,6 +1825,16 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
#[cfg(not(target_os = "linux"))]
|
||||
MiriAllocParams::Global
|
||||
}
|
||||
|
||||
fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan {
|
||||
#[cfg(feature = "tracing")]
|
||||
{ span().entered() }
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
{
|
||||
let _ = span; // so we avoid the "unused variable" warning
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for callbacks handling asynchronous machine operations.
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ LL | fn qux(&self) {
|
|||
error[E0424]: expected unit struct, unit variant or constant, found module `self`
|
||||
--> $DIR/E0424.rs:20:9
|
||||
|
|
||||
LL | fn main () {
|
||||
| ---- this function can't have a `self` parameter
|
||||
LL | let self = "self";
|
||||
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
||||
|
||||
|
|
|
|||
|
|
@ -5,25 +5,24 @@
|
|||
|
||||
#![feature(f16)]
|
||||
#![feature(f128)]
|
||||
#![feature(cfg_target_has_reliable_f16_f128)]
|
||||
#![allow(unused_macro_rules)]
|
||||
// expect the unexpected (`target_has_reliable_*` are not "known" configs since they are unstable)
|
||||
#![expect(unexpected_cfgs)]
|
||||
|
||||
use std::hint::black_box;
|
||||
|
||||
macro_rules! both_assert {
|
||||
($a:expr) => {
|
||||
{
|
||||
const _: () = assert!($a);
|
||||
// `black_box` prevents promotion, and MIR opts are disabled above, so this is truly
|
||||
// going through LLVM.
|
||||
assert!(black_box($a));
|
||||
}
|
||||
};
|
||||
($a:expr, $b:expr) => {
|
||||
{
|
||||
const _: () = assert!($a == $b);
|
||||
assert_eq!(black_box($a), black_box($b));
|
||||
}
|
||||
};
|
||||
($a:expr) => {{
|
||||
const _: () = assert!($a);
|
||||
// `black_box` prevents promotion, and MIR opts are disabled above, so this is truly
|
||||
// going through LLVM.
|
||||
assert!(black_box($a));
|
||||
}};
|
||||
($a:expr, $b:expr) => {{
|
||||
const _: () = assert!($a == $b);
|
||||
assert_eq!(black_box($a), black_box($b));
|
||||
}};
|
||||
}
|
||||
|
||||
fn has_broken_floats() -> bool {
|
||||
|
|
@ -31,8 +30,8 @@ fn has_broken_floats() -> bool {
|
|||
cfg!(all(target_arch = "x86", not(target_feature = "sse2")))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn f16(){
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn f16() {
|
||||
both_assert!((1f16).to_bits(), 0x3c00);
|
||||
both_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00);
|
||||
both_assert!((12.5f16).to_bits(), 0x4a40);
|
||||
|
|
@ -122,7 +121,7 @@ fn f64() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(target_has_reliable_f128)]
|
||||
fn f128() {
|
||||
both_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000);
|
||||
both_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000);
|
||||
|
|
@ -154,12 +153,10 @@ fn f128() {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16();
|
||||
f32();
|
||||
f64();
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
f16();
|
||||
f128();
|
||||
}
|
||||
#[cfg(target_has_reliable_f128)]
|
||||
f128();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -C debug-assertions
|
||||
//@ error-pattern: trying to construct an enum from an invalid value 0x10000
|
||||
//@ error-pattern: trying to construct an enum from an invalid value
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u32)]
|
||||
|
|
@ -11,10 +11,9 @@ enum Foo {
|
|||
|
||||
#[allow(dead_code)]
|
||||
struct Bar {
|
||||
a: u16,
|
||||
b: u16,
|
||||
a: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 0, b: 1 }) };
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 3 }) };
|
||||
}
|
||||
|
|
@ -10,11 +10,10 @@ enum Foo {
|
|||
|
||||
#[allow(dead_code)]
|
||||
struct Bar {
|
||||
a: u16,
|
||||
b: u16,
|
||||
a: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 0, b: 0 }) };
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 1, b: 0 }) };
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 0 }) };
|
||||
let _val: Foo = unsafe { std::mem::transmute::<_, Foo>(Bar { a: 1 }) };
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -C debug-assertions
|
||||
//@ error-pattern: trying to construct an enum from an invalid value 0x3
|
||||
//@ error-pattern: trying to construct an enum from an invalid value
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u32)]
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
|
|
@ -10,11 +11,11 @@ enum Foo {
|
|||
|
||||
#[allow(dead_code)]
|
||||
struct Bar {
|
||||
a: usize,
|
||||
b: usize,
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _val: Option<(usize, Foo)> =
|
||||
unsafe { std::mem::transmute::<_, Option<(usize, Foo)>>(Bar { a: 3, b: 3 }) };
|
||||
let _val: Option<(u32, Foo)> =
|
||||
unsafe { std::mem::transmute::<_, Option<(u32, Foo)>>(Bar { a: 3, b: 3 }) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -C debug-assertions
|
||||
//@ error-pattern: trying to construct an enum from an invalid value 0x4
|
||||
//@ error-pattern: trying to construct an enum from an invalid value
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u16)]
|
||||
|
|
@ -17,5 +17,5 @@ enum Nested {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(4) };
|
||||
let _val: Nested = unsafe { std::mem::transmute::<u32, Nested>(u32::MAX) };
|
||||
}
|
||||
|
|
|
|||
10
tests/ui/resolve/false-self-in-macro-issue-143134.rs
Normal file
10
tests/ui/resolve/false-self-in-macro-issue-143134.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
trait T {
|
||||
fn f(self);
|
||||
}
|
||||
impl T for () {
|
||||
fn f(self) {
|
||||
let self = (); //~ ERROR expected unit struct, unit variant or constant, found local variable `self`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
9
tests/ui/resolve/false-self-in-macro-issue-143134.stderr
Normal file
9
tests/ui/resolve/false-self-in-macro-issue-143134.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0424]: expected unit struct, unit variant or constant, found local variable `self`
|
||||
--> $DIR/false-self-in-macro-issue-143134.rs:6:13
|
||||
|
|
||||
LL | let self = ();
|
||||
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0424`.
|
||||
12
tests/ui/suggestions/suggest-remove-refs-6.rs
Normal file
12
tests/ui/suggestions/suggest-remove-refs-6.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Regression test for #143523.
|
||||
|
||||
trait Trait {}
|
||||
|
||||
impl Trait for Vec<i32> {}
|
||||
|
||||
fn foo(_: impl Trait) {}
|
||||
|
||||
fn main() {
|
||||
foo(&mut vec![1]);
|
||||
//~^ ERROR the trait bound `&mut Vec<{integer}>: Trait` is not satisfied
|
||||
}
|
||||
22
tests/ui/suggestions/suggest-remove-refs-6.stderr
Normal file
22
tests/ui/suggestions/suggest-remove-refs-6.stderr
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
error[E0277]: the trait bound `&mut Vec<{integer}>: Trait` is not satisfied
|
||||
--> $DIR/suggest-remove-refs-6.rs:10:9
|
||||
|
|
||||
LL | foo(&mut vec![1]);
|
||||
| --- ^^^^^^^^^^^^ the trait `Trait` is not implemented for `&mut Vec<{integer}>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/suggest-remove-refs-6.rs:7:16
|
||||
|
|
||||
LL | fn foo(_: impl Trait) {}
|
||||
| ^^^^^ required by this bound in `foo`
|
||||
help: consider removing the leading `&`-reference
|
||||
|
|
||||
LL - foo(&mut vec![1]);
|
||||
LL + foo(vec![1]);
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Regression test for #143481, where we were calling `predicates_of` on
|
||||
// a Crate HIR node because we were using a dummy obligation cause's body id
|
||||
// without checking that it was meaningful first.
|
||||
|
||||
trait Role {
|
||||
type Inner;
|
||||
}
|
||||
struct HandshakeCallback<C>(C);
|
||||
impl<C: Clone> Role for HandshakeCallback {
|
||||
//~^ ERROR missing generics
|
||||
type Inner = usize;
|
||||
}
|
||||
struct Handshake<R: Role>(R::Inner);
|
||||
fn accept() -> Handshake<HandshakeCallback<()>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
error[E0107]: missing generics for struct `HandshakeCallback`
|
||||
--> $DIR/ambiguity-in-dropck-err-reporting.rs:9:25
|
||||
|
|
||||
LL | impl<C: Clone> Role for HandshakeCallback {
|
||||
| ^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: struct defined here, with 1 generic parameter: `C`
|
||||
--> $DIR/ambiguity-in-dropck-err-reporting.rs:8:8
|
||||
|
|
||||
LL | struct HandshakeCallback<C>(C);
|
||||
| ^^^^^^^^^^^^^^^^^ -
|
||||
help: add missing generic argument
|
||||
|
|
||||
LL | impl<C: Clone> Role for HandshakeCallback<C> {
|
||||
| +++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0107`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue