diff --git a/Cargo.lock b/Cargo.lock index bf0e6ec7f4575..98567f858e9f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4344,7 +4344,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", - "rustc_lint", + "rustc_lint_defs", "rustc_macros", "rustc_middle", "rustc_pattern_analysis", diff --git a/compiler/rustc_middle/src/query/job.rs b/compiler/rustc_middle/src/query/job.rs index b2e5649106ce9..574a671fd640f 100644 --- a/compiler/rustc_middle/src/query/job.rs +++ b/compiler/rustc_middle/src/query/job.rs @@ -7,17 +7,8 @@ use parking_lot::{Condvar, Mutex}; use rustc_span::Span; use crate::query::plumbing::CycleError; -use crate::query::stack::QueryStackFrame; use crate::ty::TyCtxt; -/// Represents a span and a query key. -#[derive(Clone, Debug)] -pub struct QueryInfo<'tcx> { - /// The span corresponding to the reason for which this query was required. - pub span: Span, - pub frame: QueryStackFrame<'tcx>, -} - /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct QueryJobId(pub NonZero); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e6b8a931071f5..517999baba1ec 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1,7 +1,7 @@ use rustc_hir::def_id::LocalDefId; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; -pub use self::job::{QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryWaiter}; +pub use self::job::{QueryJob, QueryJobId, QueryLatch, QueryWaiter}; pub use self::keys::{AsLocalQueryKey, LocalCrate, QueryKey}; pub use self::plumbing::{ ActiveKeyStatus, CycleError, EnsureMode, IntoQueryParam, QueryMode, QueryState, TyCtxtAt, diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 90491bc402fb9..6f18c01577da2 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -8,7 +8,7 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal}; use rustc_errors::Diag; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; -use rustc_span::Span; +use rustc_span::{Span, Spanned}; pub use sealed::IntoQueryParam; use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; @@ -16,7 +16,7 @@ use crate::ich::StableHashingContext; use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey}; use crate::query::on_disk_cache::OnDiskCache; use crate::query::stack::QueryStackFrame; -use crate::query::{QueryCache, QueryInfo, QueryJob}; +use crate::query::{QueryCache, QueryJob}; use crate::ty::TyCtxt; /// For a particular query, keeps track of "active" keys, i.e. keys whose @@ -50,11 +50,13 @@ pub enum ActiveKeyStatus<'tcx> { Poisoned, } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct CycleError<'tcx> { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame<'tcx>)>, - pub cycle: Vec>, + pub usage: Option>>, + + /// The span here corresponds to the reason for which this query was required. + pub cycle: Vec>>, } #[derive(Debug)] diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f05183d7c0681..fa22e07612cfe 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -15,7 +15,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } -rustc_lint = { path = "../rustc_lint" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 6a79401af24ea..baabc1afe3fac 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -8,7 +8,7 @@ use rustc_hir::def::*; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_lint::Level; +use rustc_lint_defs::Level; use rustc_middle::bug; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 96021704d3292..75e23c3a2ff16 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; -use rustc_lint as lint; +use rustc_lint_defs::builtin::RUST_2024_INCOMPATIBLE_PAT; use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; use rustc_span::{Ident, Span}; @@ -56,7 +56,7 @@ impl<'a> PatMigration<'a> { err.emit(); } else { tcx.emit_node_span_lint( - lint::builtin::RUST_2024_INCOMPATIBLE_PAT, + RUST_2024_INCOMPATIBLE_PAT, pat_id, spans, rustc_errors::DiagDecorator(|diag| { diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index 2e2f23d6b866f..fa508419b52f2 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -76,11 +76,11 @@ fn fn_sig<'tcx>( fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> ! { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); - for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::check_representability - && let Some(field_id) = info.frame.def_id + for frame in &cycle_error.cycle { + if frame.node.dep_kind == DepKind::check_representability + && let Some(field_id) = frame.node.def_id && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.frame.tagged_key.def_kind(tcx) + && let Some(DefKind::Field) = frame.node.tagged_key.def_kind(tcx) { let parent_id = tcx.parent(field_id.to_def_id()); let item_id = match tcx.def_kind(parent_id) { @@ -90,8 +90,8 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx> item_and_field_ids.push((item_id.expect_local(), field_id)); } } - for info in &cycle_error.cycle { - if let TaggedQueryKey::check_representability_adt_ty(key) = info.frame.tagged_key + for frame in &cycle_error.cycle { + if let TaggedQueryKey::check_representability_adt_ty(key) = frame.node.tagged_key && let Some(adt) = key.ty_adt_def() && let Some(def_id) = adt.did().as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) @@ -109,9 +109,9 @@ fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx search_for_cycle_permutation( &cycle_error.cycle, |cycle| { - if let Some(info) = cycle.get(0) - && info.frame.dep_kind == DepKind::variances_of - && let Some(def_id) = info.frame.def_id + if let Some(frame) = cycle.get(0) + && frame.node.dep_kind == DepKind::variances_of + && let Some(def_id) = frame.node.def_id { let n = tcx.generics_of(def_id).own_params.len(); ControlFlow::Break(tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))) @@ -121,7 +121,7 @@ fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx }, || { span_bug!( - cycle_error.usage.as_ref().unwrap().0, + cycle_error.usage.as_ref().unwrap().span, "only `variances_of` returns `&[ty::Variance]`" ) }, @@ -154,7 +154,7 @@ fn layout_of<'tcx>( let diag = search_for_cycle_permutation( &cycle_error.cycle, |cycle| { - if let TaggedQueryKey::layout_of(key) = cycle[0].frame.tagged_key + if let TaggedQueryKey::layout_of(key) = cycle[0].node.tagged_key && let ty::Coroutine(def_id, _) = key.value.kind() && let Some(def_id) = def_id.as_local() && let def_kind = tcx.def_kind(def_id) @@ -178,8 +178,8 @@ fn layout_of<'tcx>( tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), tcx.def_kind_descr(def_kind, def_id.to_def_id()), ); - for (i, info) in cycle.iter().enumerate() { - let TaggedQueryKey::layout_of(frame_key) = info.frame.tagged_key else { + for (i, frame) in cycle.iter().enumerate() { + let TaggedQueryKey::layout_of(frame_key) = frame.node.tagged_key else { continue; }; let &ty::Coroutine(frame_def_id, _) = frame_key.value.kind() else { @@ -189,7 +189,7 @@ fn layout_of<'tcx>( continue; }; let frame_span = - info.frame.tagged_key.default_span(tcx, cycle[(i + 1) % cycle.len()].span); + frame.node.tagged_key.default_span(tcx, cycle[(i + 1) % cycle.len()].span); if frame_span.is_dummy() { continue; } diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 90fb1c26910ad..6bd4c4af5daf7 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -7,10 +7,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; use rustc_middle::query::{ - CycleError, QueryInfo, QueryJob, QueryJobId, QueryLatch, QueryStackFrame, QueryWaiter, + CycleError, QueryJob, QueryJobId, QueryLatch, QueryStackFrame, QueryWaiter, }; use rustc_middle::ty::TyCtxt; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, respan}; use crate::{CollectActiveJobsKind, collect_active_jobs_from_all_queries}; @@ -64,7 +64,7 @@ pub(crate) fn find_cycle_in_stack<'tcx>( while let Some(job) = current_job { let info = &job_map.map[&job]; - cycle.push(QueryInfo { span: info.job.span, frame: info.frame.clone() }); + cycle.push(respan(info.job.span, info.frame.clone())); if job == id { cycle.reverse(); @@ -77,7 +77,7 @@ pub(crate) fn find_cycle_in_stack<'tcx>( // Find out why the cycle itself was used let usage = try { let parent = info.job.parent?; - (info.job.span, job_map.frame_of(parent).clone()) + respan(info.job.span, job_map.frame_of(parent).clone()) }; return CycleError { usage, cycle }; } @@ -313,14 +313,14 @@ fn remove_cycle<'tcx>( let usage = entry_point .query_waiting_on_cycle - .map(|(span, job)| (span, job_map.frame_of(job).clone())); + .map(|(span, job)| respan(span, job_map.frame_of(job).clone())); // Create the cycle error let error = CycleError { usage, cycle: stack .iter() - .map(|&(span, job)| QueryInfo { span, frame: job_map.frame_of(job).clone() }) + .map(|&(span, job)| respan(span, job_map.frame_of(job).clone())) .collect(), }; @@ -454,12 +454,12 @@ pub(crate) fn report_cycle<'tcx>( ) -> Diag<'tcx> { assert!(!stack.is_empty()); - let span = stack[0].frame.tagged_key.default_span(tcx, stack[1 % stack.len()].span); + let span = stack[0].node.tagged_key.default_span(tcx, stack[1 % stack.len()].span); let mut cycle_stack = Vec::new(); use crate::error::StackCount; - let stack_bottom = stack[0].frame.tagged_key.description(tcx); + let stack_bottom = stack[0].node.tagged_key.description(tcx); let stack_count = if stack.len() == 1 { StackCount::Single { stack_bottom: stack_bottom.clone() } } else { @@ -467,28 +467,27 @@ pub(crate) fn report_cycle<'tcx>( }; for i in 1..stack.len() { - let frame = &stack[i].frame; - let span = frame.tagged_key.default_span(tcx, stack[(i + 1) % stack.len()].span); - cycle_stack - .push(crate::error::CycleStack { span, desc: frame.tagged_key.description(tcx) }); + let node = &stack[i].node; + let span = node.tagged_key.default_span(tcx, stack[(i + 1) % stack.len()].span); + cycle_stack.push(crate::error::CycleStack { span, desc: node.tagged_key.description(tcx) }); } let mut cycle_usage = None; - if let Some((span, ref query)) = *usage { + if let Some(usage) = usage { cycle_usage = Some(crate::error::CycleUsage { - span: query.tagged_key.default_span(tcx, span), - usage: query.tagged_key.description(tcx), + span: usage.node.tagged_key.default_span(tcx, usage.span), + usage: usage.node.tagged_key.description(tcx), }); } let alias = if stack .iter() - .all(|entry| matches!(entry.frame.tagged_key.def_kind(tcx), Some(DefKind::TyAlias))) + .all(|entry| matches!(entry.node.tagged_key.def_kind(tcx), Some(DefKind::TyAlias))) { Some(crate::error::Alias::Ty) } else if stack .iter() - .all(|entry| entry.frame.tagged_key.def_kind(tcx) == Some(DefKind::TraitAlias)) + .all(|entry| entry.node.tagged_key.def_kind(tcx) == Some(DefKind::TraitAlias)) { Some(crate::error::Alias::Trait) } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 629bd30d88e8e..16b0e96cde0fa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -555,6 +555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id: _, generic_args, have_turbofish, + hir_id, } => { let generics = self.tcx.generics_of(generics_def_id); let is_type = term.as_type().is_some(); @@ -577,7 +578,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(generics_def_id) { - "Vec<_>".to_string() + if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(hir_id) + && let hir::ExprKind::Call(expr, _args) = expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind + && let Res::Def(DefKind::AssocFn, def_id) = path.res + && let Some(try_trait) = self.tcx.lang_items().try_trait() + && try_trait == self.tcx.parent(def_id) + && let DefKind::Fn | DefKind::AssocFn = + self.tcx.def_kind(body_def_id.to_def_id()) + && let ret = self + .tcx + .fn_sig(body_def_id.to_def_id()) + .instantiate_identity() + .skip_binder() + .output() + && let ty::Adt(adt, _args) = ret.kind() + && let Some(sym::Option | sym::Result) = + self.tcx.get_diagnostic_name(adt.did()) + { + if let Some(sym::Option) = self.tcx.get_diagnostic_name(adt.did()) { + "Option<_>".to_string() + } else { + "Result<_, _>".to_string() + } + } else { + "Vec<_>".to_string() + } } else { let mut p = fmt_printer(self, Namespace::TypeNS); p.comma_sep(generic_args.iter().copied().map(|arg| { @@ -710,6 +736,7 @@ enum InferSourceKind<'tcx> { def_id: DefId, generic_args: &'tcx [GenericArg<'tcx>], have_turbofish: bool, + hir_id: HirId, }, FullyQualifiedMethodCall { receiver: &'tcx Expr<'tcx>, @@ -1188,19 +1215,45 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { if let Some(ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { - match local.source { - LocalSource::Normal if local.ty.is_none() => { - self.update_infer_source(InferSource { - span: local.pat.span, - kind: InferSourceKind::LetBinding { - insert_span: local.pat.span.shrink_to_hi(), - pattern_name: local.pat.simple_ident(), - ty, - def_id: None, - }, - }) + fn get_did( + typeck_results: &TypeckResults<'_>, + expr: &hir::Expr<'_>, + ) -> Option { + match expr.kind { + hir::ExprKind::Match(expr, _, hir::MatchSource::TryDesugar(_)) + if let hir::ExprKind::Call(_, [expr]) = expr.kind => + { + get_did(typeck_results, expr) + } + hir::ExprKind::Call(base, _args) + if let hir::ExprKind::Path(path) = base.kind + && let hir::QPath::Resolved(_, path) = path + && let Res::Def(_, did) = path.res => + { + Some(did) + } + hir::ExprKind::MethodCall(..) + if let Some(did) = + typeck_results.type_dependent_def_id(expr.hir_id) => + { + Some(did) + } + _ => None, } - _ => {} + } + + if let LocalSource::Normal = local.source + && local.ty.is_none() + { + self.update_infer_source(InferSource { + span: local.pat.span, + kind: InferSourceKind::LetBinding { + insert_span: local.pat.span.shrink_to_hi(), + pattern_name: local.pat.simple_ident(), + ty, + def_id: local.init.and_then(|expr| get_did(self.typeck_results, expr)), + }, + }); } } } @@ -1285,6 +1338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { def_id, generic_args, have_turbofish, + hir_id: expr.hir_id, }, }); } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ad6479f84c732..7e2c6b9b3bcb2 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -8,11 +8,11 @@ use crate::{fmt, intrinsics, ptr, slice}; /// /// # Initialization invariant /// -/// The compiler, in general, assumes that a variable is properly initialized +/// The compiler, in general, assumes that a variable is [properly initialized or "valid"][validity] /// according to the requirements of the variable's type. For example, a variable of /// reference type must be aligned and non-null. This is an invariant that must /// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a -/// variable of reference type causes instantaneous [undefined behavior][ub], +/// variable of reference type causes instantaneous undefined behavior, /// no matter whether that reference ever gets used to access memory: /// /// ```rust,no_run @@ -53,6 +53,11 @@ use crate::{fmt, intrinsics, ptr, slice}; /// // The equivalent code with `MaybeUninit`: /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` +/// +/// Conversely, sometimes it is okay to not initialize *all* bytes of a `MaybeUninit` +/// before calling `assume_init`. For instance, padding bytes do not have to be initialized. +/// See the field-by-field struct initialization example below for a case of that. +/// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] /// is considered initialized (under the current implementation; this does not constitute @@ -197,7 +202,12 @@ use crate::{fmt, intrinsics, ptr, slice}; /// ); /// ``` /// [`&raw mut`]: https://doc.rust-lang.org/reference/types/pointer.html#r-type.pointer.raw.constructor -/// [ub]: ../../reference/behavior-considered-undefined.html +/// [validity]: ../../reference/behavior-considered-undefined.html#r-undefined.validity +/// +/// Note that we have not initialized the padding, but that's fine -- it does not have to be +/// initialized. In fact, even if we had initialized the padding in `uninit`, those bytes would be +/// lost when copying the result: no matter the contents of the padding bytes in `uninit`, they will +/// always be uninitialized in `foo`. /// /// # Layout /// @@ -657,11 +667,18 @@ impl MaybeUninit { /// # Safety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes immediate undefined - /// behavior. The [type-level documentation][inv] contains more information about - /// this initialization invariant. + /// state, i.e., a state that is considered ["valid" for type `T`][validity]. Calling this when + /// the content is not yet fully initialized causes immediate undefined behavior. The + /// [type-level documentation][inv] contains more information about this initialization + /// invariant. + /// + /// It is a common mistake to assume that this function is safe to call on integers because they + /// can hold all bit patterns. It is also a common mistake to think that calling this function + /// is UB if any byte is uninitialized. Both of these assumptions are wrong. If that is + /// surprising to you, please read the [type-level documentation][inv]. /// /// [inv]: #initialization-invariant + /// [validity]: ../../reference/behavior-considered-undefined.html#r-undefined.validity /// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] @@ -689,12 +706,13 @@ impl MaybeUninit { /// *Incorrect* usage of this method: /// /// ```rust,no_run + /// # #![allow(invalid_value)] /// use std::mem::MaybeUninit; /// - /// let x = MaybeUninit::>::uninit(); - /// let x_init = unsafe { x.assume_init() }; - /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ + /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` + /// + /// See the [type-level documentation][#examples] for more examples. #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_assume_init_by_value", since = "1.59.0")] #[inline(always)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index d8521e79006e3..b321908fd9e77 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1,7 +1,32 @@ -//! Basic functions for dealing with memory. +//! Basic functions for dealing with memory, values, and types. //! -//! This module contains functions for querying the size and alignment of -//! types, initializing and manipulating memory. +//! The contents of this module can be seen as belonging to a few families: +//! +//! * [`drop`], [`replace`], [`swap`], and [`take`] +//! are safe functions for moving values in particular ways. +//! They are useful in everyday Rust code. +//! +//! * [`size_of`], [`size_of_val`], [`align_of`], [`align_of_val`], and [`offset_of`] +//! give information about the representation of values in memory. +//! +//! * [`discriminant`] +//! allows comparing the variants of [`enum`] values while ignoring their fields. +//! +//! * [`forget`] and [`ManuallyDrop`] +//! prevent destructors from running, which is used in certain kinds of ownership transfer. +//! [`needs_drop`] +//! tells you whether a type’s destructor even does anything. +//! +//! * [`transmute`], [`transmute_copy`], and [`MaybeUninit`] +//! convert and construct values in [`unsafe`] ways. +//! +//! See also the [`alloc`] and [`ptr`] modules for more primitive operations on memory. +//! +// core::alloc exists but doesn’t contain all the items we want to discuss +//! [`alloc`]: ../../std/alloc/index.html +//! [`enum`]: ../../std/keyword.enum.html +//! [`ptr`]: crate::ptr +//! [`unsafe`]: ../../std/keyword.unsafe.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index f4a09f9faae8f..0216ae7a30ddb 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use std::{ffi, panic}; use build_helper::drop_bomb::DropBomb; -use crate::util::handle_failed_output; +use crate::util::{handle_failed_output, verbose_print_command}; use crate::{ assert_contains, assert_contains_regex, assert_equals, assert_not_contains, assert_not_contains_regex, @@ -156,7 +156,7 @@ impl Command { /// Inspect what the underlying [`std::process::Command`] is up to the /// current construction. - pub fn inspect(&mut self, inspector: I) -> &mut Self + pub fn inspect(&self, inspector: I) -> &Self where I: FnOnce(&StdCommand), { @@ -233,6 +233,8 @@ impl Command { let output = self.command_output(); if !output.status().success() { handle_failed_output(&self, output, panic::Location::caller().line()); + } else { + verbose_print_command(self, &output); } output } @@ -245,6 +247,8 @@ impl Command { let output = self.command_output(); if output.status().success() { handle_failed_output(&self, output, panic::Location::caller().line()); + } else { + verbose_print_command(self, &output); } output } diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index b95f3a5cfe5a8..43f0473ddf4a1 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -1,9 +1,8 @@ +use std::env; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; -use std::{env, panic}; use crate::command::{Command, CompletedProcess}; -use crate::util::handle_failed_output; use crate::{cwd, env_var}; #[track_caller] @@ -59,43 +58,26 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { }); cmd.env("LC_ALL", "C"); // force english locale + cmd.inspect(|std_cmd| eprintln!("running: {std_cmd:?}")); cmd } /// Run a built binary and make sure it succeeds. #[track_caller] pub fn run(name: &str) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, None); - let output = cmd.run(); - if !output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, None).run() } /// Run a built binary with one or more argument(s) and make sure it succeeds. #[track_caller] pub fn run_with_args(name: &str, args: &[&str]) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, Some(args)); - let output = cmd.run(); - if !output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, Some(args)).run() } /// Run a built binary and make sure it fails. #[track_caller] pub fn run_fail(name: &str) -> CompletedProcess { - let caller = panic::Location::caller(); - let mut cmd = run_common(name, None); - let output = cmd.run_fail(); - if output.status().success() { - handle_failed_output(&cmd, output, caller.line()); - } - output + run_common(name, None).run_fail() } /// Create a new custom [`Command`]. This should be preferred to creating [`std::process::Command`] diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 6288f5f7c59da..bbc36889b1a4b 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -2,7 +2,6 @@ use std::panic; use crate::command::Command; use crate::env_var; -use crate::util::handle_failed_output; /// `TARGET` #[must_use] @@ -81,11 +80,5 @@ pub fn llvm_components_contain(component: &str) -> bool { #[track_caller] #[must_use] pub fn uname() -> String { - let caller = panic::Location::caller(); - let mut uname = Command::new("uname"); - let output = uname.run(); - if !output.status().success() { - handle_failed_output(&uname, output, caller.line()); - } - output.stdout_utf8() + Command::new("uname").run().stdout_utf8() } diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs index 7908dc1f7b3d9..f44b3861d11d3 100644 --- a/src/tools/run-make-support/src/util.rs +++ b/src/tools/run-make-support/src/util.rs @@ -4,6 +4,18 @@ use crate::command::{Command, CompletedProcess}; use crate::env::env_var; use crate::path_helpers::cwd; +pub(crate) fn verbose_print_command(cmd: &Command, output: &CompletedProcess) { + cmd.inspect(|std_cmd| { + eprintln!("{std_cmd:?}"); + }); + eprintln!("output status: `{}`", output.status()); + eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); + eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); + if !cmd.get_context().is_empty() { + eprintln!("Context:\n{}", cmd.get_context()); + } +} + /// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the /// executed command, failure location, output status and stdout/stderr, and abort the process with /// exit code `1`. @@ -17,13 +29,7 @@ pub(crate) fn handle_failed_output( } else { eprintln!("command failed at line {caller_line_number}"); } - eprintln!("{cmd:?}"); - eprintln!("output status: `{}`", output.status()); - eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); - eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); - if !cmd.get_context().is_empty() { - eprintln!("Context:\n{}", cmd.get_context()); - } + verbose_print_command(cmd, &output); std::process::exit(1) } diff --git a/tests/ui/binding/match-naked-record.rs b/tests/ui/binding/match-naked-record.rs deleted file mode 100644 index ce9489a00f2c6..0000000000000 --- a/tests/ui/binding/match-naked-record.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -struct X { x: isize } - -pub fn main() { - let _x = match 0 { - _ => X { - x: 0 - } - }; -} diff --git a/tests/ui/inference/question-mark-type-infer.rs b/tests/ui/inference/question-mark-type-infer.rs index 10560f85ed480..b04868c5324ff 100644 --- a/tests/ui/inference/question-mark-type-infer.rs +++ b/tests/ui/inference/question-mark-type-infer.rs @@ -10,6 +10,20 @@ fn g() -> Result, ()> { l.iter().map(f).collect()? //~^ ERROR type annotations needed } +fn h() -> Result<(), ()> { + let l = [1, 2, 3, 4]; + // The resulting binding doesn't have a type, so we need to guess the `Ok` type too. + let x = l.iter().map(f).collect()?; + //~^ ERROR type annotations needed + Ok(()) +} +fn i() -> Result<(), ()> { + let l = [1, 2, 3, 4]; + // The resulting binding already has a type, so we don't need to specify the `Ok` type. + let x: Vec = l.iter().map(f).collect()?; + //~^ ERROR type annotations needed + Ok(()) +} fn main() { g(); diff --git a/tests/ui/inference/question-mark-type-infer.stderr b/tests/ui/inference/question-mark-type-infer.stderr index 45303a2c87ff0..9e1232cb4a6fa 100644 --- a/tests/ui/inference/question-mark-type-infer.stderr +++ b/tests/ui/inference/question-mark-type-infer.stderr @@ -9,9 +9,37 @@ note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider specifying the generic argument | -LL | l.iter().map(f).collect::>()? - | ++++++++++ +LL | l.iter().map(f).collect::>()? + | ++++++++++++++++ -error: aborting due to 1 previous error +error[E0283]: type annotations needed + --> $DIR/question-mark-type-infer.rs:16:29 + | +LL | let x = l.iter().map(f).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: cannot satisfy `_: FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let x = l.iter().map(f).collect::>()?; + | ++++++++++++++++ + +error[E0283]: type annotations needed + --> $DIR/question-mark-type-infer.rs:23:39 + | +LL | let x: Vec = l.iter().map(f).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: cannot satisfy `_: FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let x: Vec = l.iter().map(f).collect::>()?; + | ++++++++++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.rs b/tests/ui/inference/question-mark-type-inference-in-chain.rs new file mode 100644 index 0000000000000..47c41e52b9acc --- /dev/null +++ b/tests/ui/inference/question-mark-type-inference-in-chain.rs @@ -0,0 +1,84 @@ +// #129269 +use std::fmt::Display; + +#[derive(Debug)] +struct AnotherError; +type Result = core::result::Result; + +#[derive(Debug)] +pub struct Error; + +impl From for Error { + fn from(_: AnotherError) -> Self { Error } +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +#[derive(Ord, PartialEq, PartialOrd, Eq)] +pub struct Version {} + +fn parse(_s: &str) -> std::result::Result { + todo!() +} + +pub fn error1(lines: &[&str]) -> Result> { + let mut tags = lines.iter().map(|e| parse(e)).collect()?; + //~^ ERROR: type annotations needed + //~| HELP: consider giving `tags` an explicit type + + tags.sort(); //~ NOTE: type must be known at this point + + Ok(tags) +} + +pub fn error2(lines: &[&str]) -> Result> { + let mut tags: Vec = lines.iter().map(|e| parse(e)).collect()?; + //~^ ERROR: type annotations needed + //~| NOTE: cannot infer type of the type parameter `B` + //~| NOTE: cannot satisfy `_: FromIterator>` + //~| NOTE: required by a bound in `collect` + //~| HELP: consider specifying the generic argument + tags.sort(); + + Ok(tags) +} + +pub fn error3(lines: &[&str]) -> Result> { + let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; + //~^ ERROR: the `?` operator can only be applied to values that implement `Try` + //~| NOTE: the `?` operator cannot be applied to type `Vec>` + //~| HELP: the nightly-only, unstable trait `Try` is not implemented + //~| NOTE: in this expansion of desugaring of operator `?` + //~| NOTE: in this expansion of desugaring of operator `?` + tags.sort(); + + Ok(tags) +} + +pub fn error4(lines: &[&str]) -> Result> { + let mut tags = lines + //~^ NOTE: this expression has type `&[&str]` + .iter() + //~^ NOTE: `Iterator::Item` is `&&str` here + .map(|e| parse(e)) + //~^ NOTE: the method call chain might not have had the expected associated types + //~| NOTE: `Iterator::Item` changed to `Result` here + .collect::>>()?; + //~^ ERROR: a value of type `std::result::Result, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result` + //~| NOTE: value of type `std::result::Result, AnotherError>` cannot be built from `std::iter::Iterator>` + //~| NOTE: required by a bound introduced by this call + //~| HELP: the trait + //~| HELP: for that trait implementation, expected `AnotherError`, found `Error` + //~| NOTE: required by a bound in `collect` + tags.sort(); + + Ok(tags) +} + +fn main() {} diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.stderr b/tests/ui/inference/question-mark-type-inference-in-chain.stderr new file mode 100644 index 0000000000000..0c11cdccd174f --- /dev/null +++ b/tests/ui/inference/question-mark-type-inference-in-chain.stderr @@ -0,0 +1,66 @@ +error[E0282]: type annotations needed + --> $DIR/question-mark-type-inference-in-chain.rs:31:9 + | +LL | let mut tags = lines.iter().map(|e| parse(e)).collect()?; + | ^^^^^^^^ +... +LL | tags.sort(); + | ---- type must be known at this point + | +help: consider giving `tags` an explicit type + | +LL | let mut tags: Vec<_> = lines.iter().map(|e| parse(e)).collect()?; + | ++++++++ + +error[E0283]: type annotations needed + --> $DIR/question-mark-type-inference-in-chain.rs:41:65 + | +LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect()?; + | ^^^^^^^ cannot infer type of the type parameter `B` declared on the method `collect` + | + = note: cannot satisfy `_: FromIterator>` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider specifying the generic argument + | +LL | let mut tags: Vec = lines.iter().map(|e| parse(e)).collect::>()?; + | ++++++++++++++++ + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/question-mark-type-inference-in-chain.rs:53:20 + | +LL | let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `Vec>` + | + = help: the nightly-only, unstable trait `Try` is not implemented for `Vec>` + +error[E0277]: a value of type `std::result::Result, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result` + --> $DIR/question-mark-type-inference-in-chain.rs:72:20 + | +LL | .collect::>>()?; + | ------- ^^^^^^^^^^^^^^^^^^^^ value of type `std::result::Result, AnotherError>` cannot be built from `std::iter::Iterator>` + | | + | required by a bound introduced by this call + | +help: the trait `FromIterator>` is not implemented for `std::result::Result, AnotherError>` + but trait `FromIterator>` is implemented for it + --> $SRC_DIR/core/src/result.rs:LL:COL + = help: for that trait implementation, expected `AnotherError`, found `Error` +note: the method call chain might not have had the expected associated types + --> $DIR/question-mark-type-inference-in-chain.rs:69:10 + | +LL | let mut tags = lines + | ----- this expression has type `&[&str]` +LL | +LL | .iter() + | ------ `Iterator::Item` is `&&str` here +LL | +LL | .map(|e| parse(e)) + | ^^^^^^^^^^^^^^^^^ `Iterator::Item` changed to `Result` here +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0282, E0283. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-4830.rs b/tests/ui/issues/issue-4830.rs deleted file mode 100644 index d48c13fd10b1d..0000000000000 --- a/tests/ui/issues/issue-4830.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - - -pub struct Scheduler { - /// The event loop used to drive the scheduler and perform I/O - event_loop: Box -} - -pub fn main() { } diff --git a/tests/ui/issues/issue-5192.rs b/tests/ui/issues/issue-5192.rs deleted file mode 100644 index be5d70f09b3c0..0000000000000 --- a/tests/ui/issues/issue-5192.rs +++ /dev/null @@ -1,38 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -pub trait EventLoop { - fn dummy(&self) { } -} - -pub struct UvEventLoop { - uvio: isize -} - -impl UvEventLoop { - pub fn new() -> UvEventLoop { - UvEventLoop { - uvio: 0 - } - } -} - -impl EventLoop for UvEventLoop { -} - -pub struct Scheduler { - event_loop: Box, -} - -impl Scheduler { - - pub fn new(event_loop: Box) -> Scheduler { - Scheduler { - event_loop: event_loop, - } - } -} - -pub fn main() { - let _sched = Scheduler::new(Box::new(UvEventLoop::new()) as Box); -} diff --git a/tests/ui/macros/unreachable.rs b/tests/ui/macros/unreachable.rs deleted file mode 100644 index c5cea5551cfcf..0000000000000 --- a/tests/ui/macros/unreachable.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:internal error: entered unreachable code -//@ needs-subprocess - -fn main() { - unreachable!() -} diff --git a/tests/ui/moves/array-copy-move.rs b/tests/ui/moves/array-copy-move.rs deleted file mode 100644 index ea95bc06a3693..0000000000000 --- a/tests/ui/moves/array-copy-move.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! regression test for issue https://github.com/rust-lang/rust/issues/16783 -//@ run-pass -#![allow(unused_variables)] - -pub fn main() { - let x = [1, 2, 3]; - let y = x; -}